Android仿京東首頁畫軸效果

記得之前京東首頁有一個效果,有一個畫軸,然後可以滾動畫軸,去打開畫(不知道怎麼去形容這個效果,就叫做畫軸效果吧- -!),然後去做相關操作,剛開始看到這個效果,想法是動態的去改變一個ImageView的高度,基本效果也就出來了,不過滾動部分的內容,當時接觸的也不是很多,只是看過一些大牛的博客,略微瞭解了一點,當時也忙着寫項目,也就沒去多想,前些天忽然想到這個效果,就想着實現一下,不過京東新版本好像去掉這個東西了,只能憑着自己的記憶來大概搞一下,也是對滑動這部分內容的一個小練習吧.

先看一下效果圖:

效果圖


一、需求分析

看到效果之後,先來分析一下:
首先是需要一個可以滑動的畫軸,並且這個畫軸需要一定的滑動空間,有滑動的效果,這個用Scroller幫助完成就可以了.
然後看一下畫軸點擊移動時候的背景圖,是跟隨畫軸移動,動態改變高度的.這個用一個ImageView來搞定,設置ImageView的scaleType就可以了,不過這個地方有一些小問題,下面會說.

二、具體實現

簡單分析完,來實現一下,先來做一下畫軸.創建一個ScrollPaintView繼承自RelativeLayout,因爲需要一定的滑動空間,所以需要是一個ViewGroup.

ScrollPaintView的一些基本屬性:


public class ScrollPaintView extends RelativeLayout {
    /**
     * TAG
     */
    private static final String TAG = "ScrollPaintView";
    /**
     * 默認滾軸高度
     */
    private final int DEFAULT_PAINT_SCROLL_HEIGHT = 25;
    /**
     * 默認滾動的速度
     */
    private final int DEFAULT_SCROLL_SPEED = 1000;
    /**
     * 默認分割點高度
     */
    private final int DEFAULT_PARTITION_NODE = 150;
    /**
     * 默認畫軸文字大小
     */
    private final int DEFAULT_PAINT_SCROLL_TXT_SIZE = 16;
    /**
     * Scroller
     */
    private Scroller mScroller;
    /**
     * 滾軸Iv
     */
    private ImageView mPaintScrollImageView;
    /**
     * 滾軸Tv
     */
    private TextView mPaintScrollTextView;
    /**
     * 圖畫Iv
     */
    private ImageView mPaintView;
    /**
     * 畫軸圖
     */
    private Bitmap mPaintScrollBp;
    /**
     * 畫軸高度
     */
    private int mPaintIvHeight;
    /**
     * 畫軸文字
     */
    private String mPaintScrollTxt;
    /**
     * 畫軸文字大小
     */
    private float mPaintScrollTxtSize;
    /**
     * 畫軸文字顏色
     */
    private int mPaintScrollTxtColor;
    /**
     * 圖畫開始時的高度
     */
    private int mPaintStartHeight;
    /**
     * 上一次獲取的Y
     */
    private int mLastY;
    /**
     * 滾動速度
     */
    private int mScrollSpeed;
    /**
     * 分隔節點
     */
    private int partitionNode;
    /**
     * 是否是向上滾動
     */
    private boolean isScrllerTop = false;
    /**
     * 是否正在點擊
     */
    private boolean isClick = false;
    /**
     * 佈局參數
     */
    private LayoutParams lpp;
    /**
     * 屏幕高度
     */
    private int screenHeight;
    /**
     * 屏幕寬度
     */
    private int screenWidth;
    /**
     * 回調監聽
     */
    private ScrollPaintCompleteListener listener;
    /**
     * 上一次滾動的Y值
     */
    private int lastScrollY;

    /**
     * 構造方法
     */
    public ScrollPaintView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // 獲取屬性
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ScrollPaintView);
        mPaintIvHeight = (int) ta.getDimension(R.styleable.ScrollPaintView_paintScrollHeight, TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, DEFAULT_PAINT_SCROLL_HEIGHT, getResources().getDisplayMetrics()));
        mScrollSpeed = ta.getInteger(R.styleable.ScrollPaintView_scrollSpeed, DEFAULT_SCROLL_SPEED);
        partitionNode = ta.getInteger(R.styleable.ScrollPaintView_scrollPartitionNode, DEFAULT_PARTITION_NODE);
        mPaintScrollBp = drawableToBitamp(ta.getDrawable(R.styleable.ScrollPaintView_paintScrollSrc));
        mPaintScrollTxt = ta.getString(R.styleable.ScrollPaintView_paintScrollTxt);
        mPaintScrollTxtColor = ta.getColor(R.styleable.ScrollPaintView_paintScrollTxtColor, Color.BLACK);
        mPaintScrollTxtSize = px2sp(ta.getDimensionPixelSize(R.styleable.ScrollPaintView_paintScrollTxtSize, DEFAULT_PAINT_SCROLL_TXT_SIZE));
        ta.recycle();
    }
}

看一下創建畫軸:

    /**
     * 創建滾軸
     */
    private void makePaintScroll() {
        // 如果已經存在,則不再創建
        if (null != mPaintScrollImageView || null != mPaintScrollTextView) {
            return;
        }
        // 創建滾軸
        mPaintScrollImageView = new ImageView(getContext());
        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        lp.height = mPaintIvHeight;
        mPaintScrollImageView.setLayoutParams(lp);
        mPaintScrollImageView.setScaleType(ImageView.ScaleType.FIT_XY);
        mPaintScrollImageView.setImageBitmap(null == mPaintScrollBp ? makeDefaultScroll() : mPaintScrollBp);
        addView(mPaintScrollImageView);
        // 創建文字
        mPaintScrollTextView = new TextView(getContext());
        LayoutParams lpt = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        lpt.height = mPaintIvHeight;
        mPaintScrollTextView.setLayoutParams(lpt);
        mPaintScrollTextView.setText(null == mPaintScrollTxt ? "" : mPaintScrollTxt);
        mPaintScrollTextView.setTextSize(mPaintScrollTxtSize);
        mPaintScrollTextView.setTextColor(mPaintScrollTxtColor);
        mPaintScrollTextView.setGravity(Gravity.CENTER);
        addView(mPaintScrollTextView);
    }

    /**
     * 設置默認的滾軸
     *
     * @return
     */
    private Bitmap makeDefaultScroll() {
        Bitmap defaultBp = Bitmap.createBitmap(screenWidth, mPaintIvHeight,
                Bitmap.Config.ARGB_8888);
        //填充顏色
        defaultBp.eraseColor(Color.parseColor("#FF0000"));
        return defaultBp;

    }

創建了一個畫軸ImageView和一個文字TextView作爲初始的畫軸,如果沒有傳入畫軸的圖片,則默認去創建一個畫軸.不難理解,接着去配合Scroller,讓畫軸滾動起來.

簡單滾動:

    /**
     * 處理View
     */
    private void handleView() {
        // 初始化Scroller
        mScroller = new Scroller(getContext());
        // 畫軸點擊效果
        mPaintScrollImageView.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent event) {
                int x = (int) event.getRawX();
                int y = (int) event.getRawY();
                int action = event.getAction();
                switch (action) {
                     case MotionEvent.ACTION_DOWN: 
                        isClick = true;
                        mLastY = y;
                        if (!mScroller.isFinished()) { // 如果上次的調用沒有執行完就取消。
                            mScroller.abortAnimation();
                        }
                     return true;
                     case MotionEvent.ACTION_MOVE: 
                        // 移動的距離
                        int dy = y - mLastY;
                        mLastY = y;
                        // 滑動
                        scrollBy(0, -dy);
                        return true;
                    case MotionEvent.ACTION_UP:
                      mScroller.startScroll(getScrollX(), getScrollY(), -getScrollX(), -getScrollY(), 1000);
                        invalidate();
                        return true;
                }
                return false;
            }
        });
    }

    /**
     * 滑動處理
     */
    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {  // 計算新位置,並判斷上一個滾動是否完成。 
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            invalidate();
            }
    }

這樣滑動處理就做完了,在佈局中引用一下,看一下效果

activity_main:

    <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#eeeeee"
        tools:context="com.example.junweiliu.scrollpaintdemo.MainActivity">
            <!--畫軸控件-->
  <com.example.junweiliu.scrollpaintdemo.widget.ScrollPaintView
            android:id="@+id/spv_paint"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:paintScrollHeight="25dp"
            app:paintScrollSrc="@mipmap/paint_scroll_img"
            app:paintScrollTxt="拉我看看"
            app:paintScrollTxtColor="#FF000000"
            app:paintScrollTxtSize="16sp"
    >
    </com.example.junweiliu.scrollpaintdemo.widget.ScrollPaintView>
</RelativeLayout>

效果圖:

效果圖

滾動條基本能用了,接着來設置一個ImageView來配合使用下,先獲取到一個ImageView,然後拖動畫軸時,來動態改變ImageView的高度,在做這部分內容前,先來考慮下,因爲需求需要的是圖畫整體不會變形,是一點一點拉開的感覺,就像是打開一幅畫一樣,那麼用哪種scaleType能滿足呢.試了好多種,來分別看一下:

相關代碼:
提供一個設置ImageView的方法
在MotionEvent.ACTION_MOVE:中動態改變ImageView的高度
滑動時動態改變ImageView的高度

    /**
     * 設置paintView
     *
     * @param paintView
     */
    public void setPaintView(ImageView paintView) {
        if (null == paintView) {
            Log.e(TAG, "設置的View爲空");
            return;
        }
        mPaintView = paintView;
    }

MotionEvent.ACTION_MOVE:

   // 滑動處理   
   case MotionEvent.ACTION_MOVE: 
   ...
     // 動態改變高度
     if (Math.abs(getScrollY()) > 0) {
                            lpp.height = mPaintStartHeight + Math.abs(getScrollY());
                            mPaintView.setLayoutParams(lpp);
                        }

滑動處理:

    /**
     * 滑動處理
     */
    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {  // 計算新位置,並判斷上一個滾動是否完成。
            // 請求處理點擊事件,防止父控件滑動
            requestDisallowInterceptTouchEvent(true);
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            // 重新設置顯示的控件高度
            if (0 < Math.abs(mScroller.getCurrY())) {
                if (!isScrllerTop) {
                    lpp.height = mPaintStartHeight + Math.abs(mScroller.getCurrY()) + mPaintIvHeight / 2;
                } else {
                    lpp.height = mPaintStartHeight + Math.abs(mScroller.getCurrY()) - mPaintIvHeight / 2;
                }
            } else {
                lpp.height = mPaintStartHeight;
            }
            mPaintView.setLayoutParams(lpp);
            invalidate();
        }
}

設置不同scaleType效果,簡單試幾個效果:

fitXY:

這裏寫圖片描述

centerCrop:

這裏寫圖片描述

matrix:

這裏寫圖片描述

觀察一下,好像那個效果都不是很好,不過matrix拉開的效果和預期需要的是一樣的,不過用matrix之後,就沒有辦法設置其他scaleType了,沒辦法把圖片進行縮放了,這腫麼辦呢,其實很簡單,只需要把顯示的圖片提前進行一下縮放就可以了.

處理圖片相關:

    /**
     * 設置paintView
     *
     * @param paintView
     */
    public void setPaintView(ImageView paintView) {
        if (null == paintView) {
            Log.e(TAG, "設置的View爲空");
            return;
        }
        // 處理圖片,對圖片按照屏幕寬高比進行縮放
        Bitmap bp = drawableToBitamp(paintView.getDrawable());
        paintView.setImageBitmap(scaleBitmal(bp));
        // 設置縮放形式
        paintView.setScaleType(ImageView.ScaleType.MATRIX);
        mPaintView = paintView;
    }
    /**
     * drawable轉bitmap
     *
     * @param drawable
     * @return
     */
    private Bitmap drawableToBitamp(Drawable drawable) {
        if (null == drawable) {
            return null;
        }
        if (drawable instanceof BitmapDrawable) {
            BitmapDrawable bd = (BitmapDrawable) drawable;
            return bd.getBitmap();
        }
        int w = drawable.getIntrinsicWidth();
        int h = drawable.getIntrinsicHeight();
        Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, w, h);
        drawable.draw(canvas);
        return bitmap;
    }


    /**
     * 按照屏幕寬高縮放圖片
     *
     * @param bp
     * @return
     */
    private Bitmap scaleBitmal(Bitmap bp) {
        // 寬度比例
        float scaleW = (float) screenWidth / (float) bp.getWidth();
        // 高度比例
        float scaleH = (float) screenHeight / (float) bp.getHeight();
        // 矩陣,用於縮放圖片
        Matrix matrix = new Matrix();
        matrix.postScale(scaleW, scaleH);
        // 縮放後的圖片
        Bitmap scaleBp = Bitmap.createBitmap(bp, 0, 0, bp.getWidth(), bp.getHeight(), matrix, true);
        return scaleBp;
    }

看一下效果:

這裏寫圖片描述

效果還不錯,接下來就是做一下細節上的處理,設置一個臨界點,讓畫軸向上或者向下滾動,設置邊界點,讓畫軸不越界等等.還有一般都是在ScrollView中使用到這個效果,所以要去處理一下事件衝突,當然還有去重寫一下onMeasure方法,不然會出現不顯示的情況.(相信大家也遇到過ScrollView裏邊嵌套ListView導致ListView顯示不全)這裏就不再詳細介紹了.直接貼下代碼.


三、完整代碼

MainActivity:

package com.example.junweiliu.scrollpaintdemo;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.example.junweiliu.scrollpaintdemo.widget.ScrollPaintView;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    /**
     * 需要顯示的IV
     */
    private ImageView mPaintIv;
    /**
     * 畫軸
     */
    private ScrollPaintView mScrollPaintView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();

    }

    /**
     * 初始化控件
     */
    private void initView() {
        mPaintIv = (ImageView) findViewById(R.id.iv_paint);
        mScrollPaintView = (ScrollPaintView) findViewById(R.id.spv_paint);
        mScrollPaintView.setPaintView(mPaintIv);
        mPaintIv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "功夫!", Toast.LENGTH_SHORT).show();
            }
        });
        mScrollPaintView.setScrollPaintCompleteListener(new ScrollPaintView.ScrollPaintCompleteListener() {
            @Override
            public void onScrollTouch(TextView tv) {
                mPaintIv.setVisibility(View.VISIBLE);
            }

            @Override
            public void onScrollTop(TextView tv) {
//                Log.e(TAG, "收縮了");
                tv.setText("拉我看看");
                if (View.VISIBLE == mPaintIv.getVisibility()) {
                    mPaintIv.setVisibility(View.GONE);
                }
            }

            @Override
            public void onScrollBottom(TextView tv) {
//                Log.e(TAG, "展開了");
                tv.setText("到底了");
                Intent intent = new Intent(MainActivity.this, DetailActivity.class);
                startActivity(intent);
                // 延遲800毫秒重置位置
                new Handler(new Handler.Callback() {
                    @Override
                    public boolean handleMessage(Message message) {
                        mScrollPaintView.replaceScroll();
                        return false;
                    }
                }).sendEmptyMessageDelayed(0, 600);
            }

            @Override
            public void onScrollMove(TextView tv) {
//                Log.e(TAG, "移動了");
                tv.setText("請上下拖動");
            }
        });
    }
}

ScrollPaintView:

package com.example.junweiliu.scrollpaintdemo.widget;

import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Scroller;
import android.widget.TextView;

import com.example.junweiliu.scrollpaintdemo.R;

/**
 * Created by junweiliu on 16/12/10.
 */
public class ScrollPaintView extends RelativeLayout {
    /**
     * TAG
     */
    private static final String TAG = "ScrollPaintView";
    /**
     * 默認滾軸高度
     */
    private final int DEFAULT_PAINT_SCROLL_HEIGHT = 25;
    /**
     * 默認滾動的速度
     */
    private final int DEFAULT_SCROLL_SPEED = 1000;
    /**
     * 默認分割點高度
     */
    private final int DEFAULT_PARTITION_NODE = 150;
    /**
     * 默認畫軸文字大小
     */
    private final int DEFAULT_PAINT_SCROLL_TXT_SIZE = 16;
    /**
     * Scroller
     */
    private Scroller mScroller;
    /**
     * 滾軸Iv
     */
    private ImageView mPaintScrollImageView;
    /**
     * 滾軸Tv
     */
    private TextView mPaintScrollTextView;
    /**
     * 圖畫Iv
     */
    private ImageView mPaintView;
    /**
     * 畫軸圖
     */
    private Bitmap mPaintScrollBp;
    /**
     * 畫軸高度
     */
    private int mPaintIvHeight;
    /**
     * 畫軸文字
     */
    private String mPaintScrollTxt;
    /**
     * 畫軸文字大小
     */
    private float mPaintScrollTxtSize;
    /**
     * 畫軸文字顏色
     */
    private int mPaintScrollTxtColor;
    /**
     * 圖畫開始時的高度
     */
    private int mPaintStartHeight;
    /**
     * 上一次獲取的Y
     */
    private int mLastY;
    /**
     * 滾動速度
     */
    private int mScrollSpeed;
    /**
     * 分隔節點
     */
    private int partitionNode;
    /**
     * 是否是向上滾動
     */
    private boolean isScrllerTop = false;
    /**
     * 是否正在點擊
     */
    private boolean isClick = false;
    /**
     * 佈局參數
     */
    private LayoutParams lpp;
    /**
     * 屏幕高度
     */
    private int screenHeight;
    /**
     * 屏幕寬度
     */
    private int screenWidth;
    /**
     * 回調監聽
     */
    private ScrollPaintCompleteListener listener;
    /**
     * 上一次滾動的Y值
     */
    private int lastScrollY;

    /**
     * 回調接口
     */
    public interface ScrollPaintCompleteListener {
        /**
         * 點擊時的回調
         */
        public void onScrollTouch(TextView tv);

        /**
         * 收縮時的回調
         */
        public void onScrollTop(TextView tv);

        /**
         * 展開時的回調
         */
        public void onScrollBottom(TextView tv);

        /**
         * 滾動中的回調
         */
        public void onScrollMove(TextView tv);

    }


    public ScrollPaintView(Context context) {
        this(context, null);
    }

    public ScrollPaintView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ScrollPaintView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // 獲取屬性
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ScrollPaintView);
        mPaintIvHeight = (int) ta.getDimension(R.styleable.ScrollPaintView_paintScrollHeight, TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, DEFAULT_PAINT_SCROLL_HEIGHT, getResources().getDisplayMetrics()));
        mScrollSpeed = ta.getInteger(R.styleable.ScrollPaintView_scrollSpeed, DEFAULT_SCROLL_SPEED);
        partitionNode = ta.getInteger(R.styleable.ScrollPaintView_scrollPartitionNode, DEFAULT_PARTITION_NODE);
        mPaintScrollBp = drawableToBitamp(ta.getDrawable(R.styleable.ScrollPaintView_paintScrollSrc));
        mPaintScrollTxt = ta.getString(R.styleable.ScrollPaintView_paintScrollTxt);
        mPaintScrollTxtColor = ta.getColor(R.styleable.ScrollPaintView_paintScrollTxtColor, Color.BLACK);
        mPaintScrollTxtSize = px2sp(ta.getDimensionPixelSize(R.styleable.ScrollPaintView_paintScrollTxtSize, DEFAULT_PAINT_SCROLL_TXT_SIZE));
        ta.recycle();
        init();
        makePaintScroll();
        handleView();
    }

    /**
     * 設置paintView
     *
     * @param paintView
     */
    public void setPaintView(ImageView paintView) {
        if (null == paintView) {
            Log.e(TAG, "設置的View爲空");
            return;
        }
        // 處理圖片,對圖片按照屏幕寬高比進行縮放
        Bitmap bp = drawableToBitamp(paintView.getDrawable());
        paintView.setImageBitmap(scaleBitmal(bp));
        // 設置縮放形式
        paintView.setScaleType(ImageView.ScaleType.MATRIX);
        mPaintView = paintView;
    }

    /**
     * 設置回調
     */
    public void setScrollPaintCompleteListener(ScrollPaintCompleteListener listener) {
        if (null != listener) {
            this.listener = listener;
        }
    }

    /**
     * 初始化
     */
    private void init() {
        mScroller = new Scroller(getContext());
        lpp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        // 獲取屏幕信息
        DisplayMetrics displayMetrics = new DisplayMetrics();
        ((Activity) getContext()).getWindowManager().getDefaultDisplay()
                .getMetrics(displayMetrics);
        // 屏幕高度
        screenHeight = displayMetrics.heightPixels;
        // 屏幕寬度
        screenWidth = displayMetrics.widthPixels;
    }


    /**
     * 創建滾軸
     */
    private void makePaintScroll() {
        // 如果已經存在,則不再創建
        if (null != mPaintScrollImageView || null != mPaintScrollTextView) {
            return;
        }
        // 創建滾軸
        mPaintScrollImageView = new ImageView(getContext());
        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        lp.height = mPaintIvHeight;
        mPaintScrollImageView.setLayoutParams(lp);
        mPaintScrollImageView.setScaleType(ImageView.ScaleType.FIT_XY);
        mPaintScrollImageView.setImageBitmap(null == mPaintScrollBp ? makeDefaultScroll() : mPaintScrollBp);
        addView(mPaintScrollImageView);
        // 創建文字
        mPaintScrollTextView = new TextView(getContext());
        LayoutParams lpt = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        lpt.height = mPaintIvHeight;
        mPaintScrollTextView.setLayoutParams(lpt);
        mPaintScrollTextView.setText(null == mPaintScrollTxt ? "" : mPaintScrollTxt);
        mPaintScrollTextView.setTextSize(mPaintScrollTxtSize);
        mPaintScrollTextView.setTextColor(mPaintScrollTxtColor);
        mPaintScrollTextView.setGravity(Gravity.CENTER);
        addView(mPaintScrollTextView);
    }


    /**
     * 測量方法
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (null != mPaintView && getTop() + mPaintIvHeight != mPaintView.getHeight()) {
            // 重新設置圖畫高度
            mPaintStartHeight = getTop() + mPaintIvHeight / 2;
            lpp.height = mPaintStartHeight;
            mPaintView.setLayoutParams(lpp);
        }
        // 測量狀態欄高度
        Rect frame = new Rect();
        ((Activity) getContext()).getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
        int statusBarHeight = frame.top;
        // 高度爲屏幕高度減去狀態欄高度和top的高度
        setMeasuredDimension(screenWidth, screenHeight - getTop() - statusBarHeight);
    }

    /**
     * 處理View
     */
    private void handleView() {
        mPaintScrollImageView.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent event) {
                if (null == mPaintView) {
                    Log.e(TAG, "設置的View爲空");
                    return true;
                }
                // 獲取點擊的XY座標
                int x = (int) event.getRawX();
                int y = (int) event.getRawY();
                int action = event.getAction();
                switch (action) {
                    case MotionEvent.ACTION_DOWN: {
                        // 請求處理點擊事件
                        requestDisallowInterceptTouchEvent(true);
                        isClick = true;
                        mLastY = y;
                        if (!mScroller.isFinished()) { // 如果上次的調用沒有執行完就取消。
                            mScroller.abortAnimation();
                        }
                        if (null != listener) {
                            listener.onScrollTouch(mPaintScrollTextView);
                        }
                        return true;
                    }
                    case MotionEvent.ACTION_MOVE: {
                        // 移動的距離
                        int dy = y - mLastY;
                        mLastY = y;
                        // 滑動
                        scrollBy(0, -dy);
                        //  如果是向上滑動並且是在初始位置,則不去做處理
                        if (getScrollY() >= 0 && dy <= 0) {
                            lpp.height = mPaintStartHeight;
                            mPaintView.setLayoutParams(lpp);
                            scrollTo(0, 0);
                            return true;
                        }
                        // 如果是向下滑動並且超過屏幕高度,則不去處理
                        if (Math.abs(getScrollY()) >= getHeight() - mPaintIvHeight && dy >= 0) {
                            lpp.height = mPaintStartHeight + getHeight() - mPaintIvHeight;
                            mPaintView.setLayoutParams(lpp);
                            scrollTo(0, -(getHeight() - mPaintIvHeight));
                            return true;
                        }
                        // 滾動回調
                        if (null != listener) {
                            listener.onScrollMove(mPaintScrollTextView);
                        }
                        // 重新設置顯示的控件高度
                        if (Math.abs(getScrollY()) > 0) {
                            lpp.height = mPaintStartHeight + Math.abs(getScrollY());
                            mPaintView.setLayoutParams(lpp);
                        }
                        return true;
                    }
                    case MotionEvent.ACTION_UP:
                        // 恢復事件處理
                        requestDisallowInterceptTouchEvent(false);
                        isClick = false;
                        // 沒有發生移動
                        if (getScrollY() >= 0) {
                            if (null != listener) {
                                listener.onScrollTop(mPaintScrollTextView);
                            }
                            return true;
                        }
                        if (-getScrollY() < partitionNode) {   // 如果小於臨界值,則返回起始座標
                            // XY都從滑動的距離回去,最後一個參數是多少毫秒內執行完這個動作。
                            isScrllerTop = true;
                            mScroller.startScroll(getScrollX(), getScrollY(), -getScrollX(), -getScrollY(), mScrollSpeed);
                        } else {    // 如果大於臨界值,則展開
                            isScrllerTop = false;
                            mScroller.startScroll(getScrollX(), getScrollY(), -getScrollX(), -(getHeight() - (-getScrollY()) - mPaintIvHeight), mScrollSpeed);
                        }
                        invalidate();
                        return true;
                }
                return false;
            }
        });
    }


    /**
     * 滑動處理
     */
    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {  // 計算新位置,並判斷上一個滾動是否完成。
            // 請求處理點擊事件,防止父控件滑動
            requestDisallowInterceptTouchEvent(true);
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            // 重新設置顯示的控件高度
            if (0 < Math.abs(mScroller.getCurrY())) {
                if (!isScrllerTop) {
                    lpp.height = mPaintStartHeight + Math.abs(mScroller.getCurrY()) + mPaintIvHeight / 2;
                } else {
                    lpp.height = mPaintStartHeight + Math.abs(mScroller.getCurrY()) - mPaintIvHeight / 2;
                }
            } else {
                lpp.height = mPaintStartHeight;
            }
            mPaintView.setLayoutParams(lpp);
            invalidate();
        } else {
            // 重新設置畫圖高度,防止高度異常
            if (mPaintView.getHeight() > mPaintStartHeight + Math.abs(mScroller.getCurrY()) && !isScrllerTop && mScroller.getStartY() > 0) {
                lpp.height = mPaintStartHeight + Math.abs(mScroller.getCurrY());
                mPaintView.setLayoutParams(lpp);
            }
        }
        // 防止多次調用
        if (lastScrollY != mScroller.getCurrY()) {
            // 收縮完成
            if (mScroller.getCurrY() >= 0 && !isClick) {
                if (null != listener) {
                    listener.onScrollTop(mPaintScrollTextView);
                }
            }
            // 展開完成
            if (-mScroller.getCurrY() >= getHeight() - mPaintIvHeight && !isClick) {
                if (null != listener) {
                    listener.onScrollBottom(mPaintScrollTextView);
                }
            }
            lastScrollY = mScroller.getCurrY();
        }
    }

    /**
     * 重置滾動
     */
    public void replaceScroll() {
        // 重置信息
        scrollTo(0, 0);
        mScroller.setFinalY(0);
        lastScrollY = 0;
        lpp.height = mPaintStartHeight;
        mPaintView.setLayoutParams(lpp);
        if (null != listener) {
            listener.onScrollTop(mPaintScrollTextView);
        }
    }

    /**
     * drawable轉bitmap
     *
     * @param drawable
     * @return
     */
    private Bitmap drawableToBitamp(Drawable drawable) {
        if (null == drawable) {
            return null;
        }
        if (drawable instanceof BitmapDrawable) {
            BitmapDrawable bd = (BitmapDrawable) drawable;
            return bd.getBitmap();
        }
        int w = drawable.getIntrinsicWidth();
        int h = drawable.getIntrinsicHeight();
        Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, w, h);
        drawable.draw(canvas);
        return bitmap;
    }


    /**
     * 按照屏幕寬高縮放圖片
     *
     * @param bp
     * @return
     */
    private Bitmap scaleBitmal(Bitmap bp) {
        // 寬度比例
        float scaleW = (float) screenWidth / (float) bp.getWidth();
        // 高度比例
        float scaleH = (float) screenHeight / (float) bp.getHeight();
        // 矩陣,用於縮放圖片
        Matrix matrix = new Matrix();
        matrix.postScale(scaleW, scaleH);
        // 縮放後的圖片
        Bitmap scaleBp = Bitmap.createBitmap(bp, 0, 0, bp.getWidth(), bp.getHeight(), matrix, true);
        return scaleBp;
    }

    /**
     * 設置默認的滾軸
     *
     * @return
     */
    private Bitmap makeDefaultScroll() {
        Bitmap defaultBp = Bitmap.createBitmap(screenWidth, mPaintIvHeight,
                Bitmap.Config.ARGB_8888);
        //填充顏色
        defaultBp.eraseColor(Color.parseColor("#FF0000"));
        return defaultBp;

    }


    /**
     * 將px值轉換爲sp值,保證文字大小不變
     */
    public int px2sp(float pxValue) {
        final float fontScale = getContext().getResources().getDisplayMetrics().scaledDensity;
        return (int) (pxValue / fontScale + 0.5f);
    }

}

activity_main:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#eeeeee"
        tools:context="com.example.junweiliu.scrollpaintdemo.MainActivity">
    <ScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        <RelativeLayout android:layout_width="match_parent"
                        android:layout_height="match_parent">
            <!--頭部圖片部分-->
            <ImageView
                    android:id="@+id/iv_banner"
                    android:layout_width="match_parent"
                    android:layout_height="200dp"
                    android:scaleType="fitXY"
                    android:src="@mipmap/show_banner"/>
            <!--中間內容部分-->
            <LinearLayout
                    android:id="@+id/ll_first"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/iv_banner"
                    android:layout_marginTop="20dp"
                    android:orientation="horizontal"
                    android:padding="16dp">
                <LinearLayout
                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_marginRight="16dp"
                        android:layout_weight="1"
                        android:gravity="center_horizontal"
                        android:orientation="vertical">
                    <ImageView
                            android:layout_width="80dp"
                            android:layout_height="120dp"
                            android:scaleType="fitXY"
                            android:src="@mipmap/movie_playbill_a"/>
                    <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="10dp"
                            android:gravity="center"
                            android:text="藝術片"
                            android:textColor="#666666"/>
                </LinearLayout>
                <LinearLayout
                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_marginRight="16dp"
                        android:layout_weight="1"
                        android:gravity="center_horizontal"
                        android:orientation="vertical">
                    <ImageView
                            android:layout_width="80dp"
                            android:layout_height="120dp"
                            android:scaleType="fitXY"
                            android:src="@mipmap/movie_playbill_b"/>
                    <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="10dp"
                            android:gravity="center"
                            android:text="懷舊片"
                            android:textColor="#666666"/>
                </LinearLayout>
                <LinearLayout
                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_marginRight="16dp"
                        android:layout_weight="1"
                        android:gravity="center_horizontal"
                        android:orientation="vertical">
                    <ImageView
                            android:layout_width="80dp"
                            android:layout_height="120dp"
                            android:scaleType="fitXY"
                            android:src="@mipmap/movie_playbill_c"/>
                    <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="10dp"
                            android:gravity="center"
                            android:text="科幻片"
                            android:textColor="#666666"/>
                </LinearLayout>
                <LinearLayout
                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_weight="1"
                        android:gravity="center_horizontal"
                        android:orientation="vertical">
                    <ImageView
                            android:layout_width="80dp"
                            android:layout_height="120dp"
                            android:scaleType="fitXY"
                            android:src="@mipmap/movie_playbill_d"/>
                    <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="10dp"
                            android:gravity="center"
                            android:text="動畫片"
                            android:textColor="#666666"/>
                </LinearLayout>
            </LinearLayout>
            <LinearLayout
                    android:id="@+id/ll_sencond"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/ll_first"
                    android:layout_marginTop="20dp"
                    android:orientation="horizontal"
                    android:padding="16dp">
                <LinearLayout

                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_marginRight="16dp"
                        android:layout_weight="1"
                        android:gravity="center_horizontal"
                        android:orientation="vertical">
                    <ImageView
                            android:layout_width="80dp"
                            android:layout_height="120dp"
                            android:scaleType="fitXY"
                            android:src="@mipmap/movie_playbill_a"/>
                    <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="10dp"
                            android:gravity="center"
                            android:text="藝術片"
                            android:textColor="#666666"/>
                </LinearLayout>
                <LinearLayout
                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_marginRight="16dp"
                        android:layout_weight="1"
                        android:gravity="center_horizontal"
                        android:orientation="vertical">
                    <ImageView
                            android:layout_width="80dp"
                            android:layout_height="120dp"
                            android:scaleType="fitXY"
                            android:src="@mipmap/movie_playbill_b"/>
                    <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="10dp"
                            android:gravity="center"
                            android:text="懷舊片"
                            android:textColor="#666666"/>
                </LinearLayout>
                <LinearLayout
                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_marginRight="16dp"
                        android:layout_weight="1"
                        android:gravity="center_horizontal"
                        android:orientation="vertical">
                    <ImageView
                            android:layout_width="80dp"
                            android:layout_height="120dp"
                            android:scaleType="fitXY"
                            android:src="@mipmap/movie_playbill_c"/>
                    <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="10dp"
                            android:gravity="center"
                            android:text="科幻片"
                            android:textColor="#666666"/>
                </LinearLayout>
                <LinearLayout
                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_weight="1"
                        android:gravity="center_horizontal"
                        android:orientation="vertical">
                    <ImageView
                            android:layout_width="80dp"
                            android:layout_height="120dp"
                            android:scaleType="fitXY"
                            android:src="@mipmap/movie_playbill_d"/>
                    <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="10dp"
                            android:gravity="center"
                            android:text="動畫片"
                            android:textColor="#666666"/>
                </LinearLayout>
            </LinearLayout>
            <LinearLayout
                    android:id="@+id/ll_threeth"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/ll_sencond"
                    android:layout_marginTop="20dp"
                    android:orientation="horizontal"
                    android:padding="16dp">
                <LinearLayout
                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_marginRight="16dp"
                        android:layout_weight="1"
                        android:gravity="center_horizontal"
                        android:orientation="vertical">
                    <ImageView
                            android:layout_width="80dp"
                            android:layout_height="120dp"
                            android:scaleType="fitXY"
                            android:src="@mipmap/movie_playbill_a"/>
                    <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="10dp"
                            android:gravity="center"
                            android:text="藝術片"
                            android:textColor="#666666"/>
                </LinearLayout>
                <LinearLayout
                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_marginRight="16dp"
                        android:layout_weight="1"
                        android:gravity="center_horizontal"
                        android:orientation="vertical">
                    <ImageView
                            android:layout_width="80dp"
                            android:layout_height="120dp"
                            android:scaleType="fitXY"
                            android:src="@mipmap/movie_playbill_b"/>
                    <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="10dp"
                            android:gravity="center"
                            android:text="懷舊片"
                            android:textColor="#666666"/>
                </LinearLayout>
                <LinearLayout
                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_marginRight="16dp"
                        android:layout_weight="1"
                        android:gravity="center_horizontal"
                        android:orientation="vertical">
                    <ImageView
                            android:layout_width="80dp"
                            android:layout_height="120dp"
                            android:scaleType="fitXY"
                            android:src="@mipmap/movie_playbill_c"/>
                    <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="10dp"
                            android:gravity="center"
                            android:text="科幻片"
                            android:textColor="#666666"/>
                </LinearLayout>
                <LinearLayout
                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_weight="1"
                        android:gravity="center_horizontal"
                        android:orientation="vertical">
                    <ImageView
                            android:layout_width="80dp"
                            android:layout_height="120dp"
                            android:scaleType="fitXY"
                            android:src="@mipmap/movie_playbill_d"/>
                    <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="10dp"
                            android:gravity="center"
                            android:text="動畫片"
                            android:textColor="#666666"/>
                </LinearLayout>
            </LinearLayout>
            <LinearLayout
                    android:id="@+id/ll_fourth"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/ll_threeth"
                    android:layout_marginTop="20dp"
                    android:orientation="horizontal"
                    android:padding="16dp">
                <LinearLayout
                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_marginRight="16dp"
                        android:layout_weight="1"
                        android:gravity="center_horizontal"
                        android:orientation="vertical">
                    <ImageView
                            android:layout_width="80dp"
                            android:layout_height="120dp"
                            android:scaleType="fitXY"
                            android:src="@mipmap/movie_playbill_a"/>
                    <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="10dp"
                            android:gravity="center"
                            android:text="藝術片"
                            android:textColor="#666666"/>
                </LinearLayout>
                <LinearLayout
                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_marginRight="16dp"
                        android:layout_weight="1"
                        android:gravity="center_horizontal"
                        android:orientation="vertical">
                    <ImageView
                            android:layout_width="80dp"
                            android:layout_height="120dp"
                            android:scaleType="fitXY"
                            android:src="@mipmap/movie_playbill_b"/>
                    <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="10dp"
                            android:gravity="center"
                            android:text="懷舊片"
                            android:textColor="#666666"/>
                </LinearLayout>
                <LinearLayout
                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_marginRight="16dp"
                        android:layout_weight="1"
                        android:gravity="center_horizontal"
                        android:orientation="vertical">
                    <ImageView
                            android:layout_width="80dp"
                            android:layout_height="120dp"
                            android:scaleType="fitXY"
                            android:src="@mipmap/movie_playbill_c"/>
                    <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="10dp"
                            android:gravity="center"
                            android:text="科幻片"
                            android:textColor="#666666"/>
                </LinearLayout>
                <LinearLayout
                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_weight="1"
                        android:gravity="center_horizontal"
                        android:orientation="vertical">
                    <ImageView
                            android:layout_width="80dp"
                            android:layout_height="120dp"
                            android:scaleType="fitXY"
                            android:src="@mipmap/movie_playbill_d"/>
                    <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="10dp"
                            android:gravity="center"
                            android:text="動畫片"
                            android:textColor="#666666"/>
                </LinearLayout>
            </LinearLayout>

            <!--需要顯示的圖-->
            <ImageView
                    android:id="@+id/iv_paint"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:scaleType="matrix"
                    android:src="@mipmap/show_img"
                    android:visibility="gone"/>
            <!--畫軸控件-->
            <com.example.junweiliu.scrollpaintdemo.widget.ScrollPaintView
                    android:id="@+id/spv_paint"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_below="@+id/iv_banner"
                    app:paintScrollHeight="25dp"
                    app:paintScrollSrc="@mipmap/paint_scroll_img"
                    app:paintScrollTxt="拉我看看"
                    app:paintScrollTxtColor="#FF000000"
                    app:paintScrollTxtSize="16sp"
            >
            </com.example.junweiliu.scrollpaintdemo.widget.ScrollPaintView>
        </RelativeLayout>
    </ScrollView>
</RelativeLayout>

attr:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--畫軸的高度-->
    <attr name="paintScrollHeight" format="dimension"/>
    <!--畫軸的圖片-->
    <attr name="paintScrollSrc" format="reference"/>
    <!--畫軸文字-->
    <attr name="paintScrollTxt" format="string"/>
    <!--畫軸文字顏色-->
    <attr name="paintScrollTxtColor" format="color"/>
    <!--畫軸文字大小-->
    <attr name="paintScrollTxtSize" format="dimension"/>
    <!--滾動速度-->
    <attr name="scrollSpeed" format="integer"/>
    <!--分割節點-->
    <attr name="scrollPartitionNode" format="integer"/>
    <declare-styleable name="ScrollPaintView">
        <attr name="paintScrollHeight"/>
        <attr name="paintScrollSrc"/>
        <attr name="paintScrollTxt"/>
        <attr name="paintScrollTxtColor"/>
        <attr name="paintScrollTxtSize"/>
        <attr name="scrollSpeed"/>
        <attr name="scrollPartitionNode"/>
    </declare-styleable>
</resources>

四、問題

滾動的時間不宜設置太短,因爲動態設置ImageView高度時可能出現繪製速度趕不上滾動的速度,會出現錯位,當然時間設置太短,也看不到這種滑動的效果了.暫時想到的做法就是這樣,應該還會有更好的方法.

源碼地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章