Android-自定義ViewPager

效果圖:android

 

佈局去指定自定義ViewPager:canvas

view.custom.shangguigucustomview.MyCustomViewPager
<!-- 仿viewpager -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".ShangGuiguTestActivity">

    <RadioGroup
        android:id="@+id/radio_group"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:orientation="horizontal"></RadioGroup>

    <view.custom.shangguigucustomview.MyCustomViewPager
        android:id="@+id/mycustom_viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </view.custom.shangguigucustomview.MyCustomViewPager>

</LinearLayout>

 

自定義ViewPager:ide

public class MyCustomViewPager extends ViewGroup {

    private static final String TAG =  MyCustomViewPager.class.getSimpleName();

    /**
     * 定義手勢識別器(注意:手勢識別器沒有事件攔截的特色)
     */
    private GestureDetector gestureDetector;

    private Scroller mScroller;

    public MyCustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);

        initView(context, attrs);
    }

    void initView(final Context context, AttributeSet attributeSet) {

        mScroller = new Scroller(context);

        gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener(){
            @Override
            public void onLongPress(MotionEvent e) {
                super.onLongPress(e);
                Toast.makeText(context, "你長按了", Toast.LENGTH_SHORT).show();
            }

            @Override
            public boolean onDoubleTap(MotionEvent e) {
                Toast.makeText(context,"你雙擊了", Toast.LENGTH_SHORT).show();
                return super.onDoubleTap(e);
            }

            /**
             *
             * @param e1 開始按下的玩意
             * @param e2 up後的玩意
             * @param distanceX 滑動的X軸
             * @param distanceY 滑動的Y軸
             * @return
             */
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                // 本身不變,讓本身內部的內容發生移動
                // scrollBy((int)distanceX, (int)distanceY); // 根據當前的位置進行移動

                scrollBy((int)distanceX, 0);  // getScaleY(); // 建立的時候默認的一個起始值
                // scrollTo((int)distanceX, 0 ); // 相對的是座標,By相對的是距離

                return true; // 手勢滑動 本身來處理,本身來消耗,因此retrun true;
            }
        });
    }

    /**
     * 1.爲何在一級畫面可以顯示,而在一級畫面裏面到子畫面沒法顯示?
     *   就是由於一級畫面在onLayout一級畫面指定好位置了,系統就能夠繪製好,而在畫面中沒有測量好,因此須要遍歷子畫面進行測量
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     *
     * 在ViewGroup中沒有測量本身,只有測量孩子
     * ViewGroup (調用去測量孩子) --> View(測量本身)
     */
    /**
     *
     * @param widthMeasureSpec  1073742904 這個參數是父層視圖給當前視圖的寬度 和 模式
     * @param heightMeasureSpec 1073743468 這個參數是父層視圖給當前視圖的高度 和 模式
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        Log.i(TAG, "widthMeasureSpec:" + widthMeasureSpec + " heightMeasureSpec:" + heightMeasureSpec);

        // 獲得寬高的Size
        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
        int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);

        // 獲得高寬的模式
        int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
        int modeHeight = MeasureSpec.getMode(heightMeasureSpec);

        Log.i(TAG, ">>>>>>>> 🐶 sizeWidth:" + sizeWidth + " sizeHeight:" + sizeHeight);
        Log.i(TAG, ">>>>>>>> 🐶 modeWidth:" + modeWidth + " modeHeight:" + modeHeight);


        MeasureSpec.getMode(widthMeasureSpec);

        // 三種模式
        int unspecified = MeasureSpec.UNSPECIFIED; // 父容器不作任何限制,想多大就多大,屬於:包裹
        int exactly = MeasureSpec.EXACTLY; // 父容器已檢測出View所需大小
        int  atMost = MeasureSpec.AT_MOST; // 父容器已經規定了大小,不能超過規定的大小


        /**
         * 視圖中又有視圖,給本身的孩子東東
         */
        int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(sizeHeight, modeHeight);
        int newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(sizeWidth, modeWidth);

        ///////// 與如下代碼是分開的


        // 獲得因此到孩子,給孩子測量,才能讓系統到onDraw繪製出來
        int childCount = getChildCount();
        for (int i=0;i<childCount;i++) {
            View childAtView = getChildAt(i);
            childAtView.measure(widthMeasureSpec, heightMeasureSpec);
        }
    }

    /**
     * 繼承ViewGroup必須重寫的方法
     * (無論是系統繪製仍是本身來繪製,都是依賴於測量,或者是 onLayout來指定好來位置,才能繪製到顯示)
     * @param booleanB 但佈局變化但時候
     * @param l 左上角 距離 左邊的寬度
     * @param t 左上角 距離 頂部的高度
     * @param r 右下角 距離 左邊但寬度
     * @param b 右下角 距離 頂部但高度
     */
    @Override
    protected void onLayout(boolean booleanB, int l, int t, int r, int b) {

        // 我先獲得一個孩子,設置位置,在展現看看
        /*View childView = getChildAt(0);
        childView.layout(0,0, (0 + 1) * getWidth(), getHeight());*/

        // 遍歷全部的孩子
        for (int i=0; i<getChildCount(); i++){
            View childAtView = getChildAt(i);
            l = i*getWidth(); // 左上角距離左邊的距離,第一個頁面:0*任何都得0, 第二個頁面:1*寬度的一個寬度,..
            t = 0; // 左上角 我要貼到頂部,因此不須要距離頂部
            r = getWidth() * (i+1); // 右下角 距離左邊到寬度很重要,第一個頁面須要設置屏幕寬度,第二個頁面須要 2*屏幕寬度,...
            b = getHeight(); // 右下角 距離頂部到高度,一直是屏幕高度就好來
            /**
             * 指定每一個孩子到位置
             */
            childAtView.layout(l, t, r, b); // 都已經人爲都指定好了,因此測量都方法就不須要了
        }
    }

    /*@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }*/

    private float startX;
    private float endX;
    private int tempIndex;

    private IMyCustomViewPagerBack back;

    public void setIBack(IMyCustomViewPagerBack back) {
        this.back = back;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        gestureDetector.onTouchEvent(event); // 要把事件傳遞給(手勢識別器)
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startX = event.getX();
                break;
            case MotionEvent.ACTION_UP:
                if (getWidth()/2 < startX - endX) {
                    tempIndex ++;
                } else if (getWidth() / 2 < endX - startX ) {
                    tempIndex --;
                }

                // 防止越界
                if (tempIndex < 0) {
                    tempIndex = 0;
                } else if (tempIndex > getChildCount()-1) {
                    tempIndex = getChildCount() - 1;
                }

                toScroller(tempIndex);

                break;
            case MotionEvent.ACTION_MOVE:
                endX = event.getX();
                break;
            default:
                break;
        }
        return true;
    }

    public void toScroller(int tempIndex) {

        if (null != back) {
            back.backMethod(tempIndex);
        }

        // 總距離
        test = (tempIndex * getWidth()) - getScrollX();
        v = 0;

        // scrollTo(test, 0);

        // handler.sendEmptyMessage(0);

        invalidate();



        mScroller.startScroll(getScrollX(),getScrollY(), test, Math.abs(test));

    }

    private int test;
    private int v = 10;

    private android.os.Handler handler = new android.os.Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            switch (msg.what) {
                case 0:
                    scrollTo(v, getScrollY());
                    handler.sendEmptyMessageDelayed(1, 500);
                    break;
                case 1:
                    if (v < test) {
                       v = v + v;
                        scrollTo(v, getScrollY());
                        handler.sendEmptyMessageDelayed(1, 500);
                    }
                    break;
            }
        }
    };

    @Override
    public void computeScroll() {
        super.computeScroll();

        if (mScroller.computeScrollOffset()) {
            int curX =  mScroller.getCurrX();
            scrollTo(curX, 0);
            invalidate();
        }
    }

    float mystartX;
    float mystartY;

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        super.onInterceptTouchEvent(ev);
        // return true; // 攔截事件 將會觸發onTouchEvent
        // return false; // 不攔截事件,將事件交給自控件

        // 把事件給收拾識別器
        gestureDetector.onTouchEvent(ev);

        boolean result = false; // 默認是不攔截的
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 記錄觸摸下的值
                mystartX = ev.getX();
                mystartY = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                // 記錄摸移動的值
                float endX = ev.getX();
                float endY = ev.getY();

                // 計算絕對值
                float jueduiX = Math.abs(endX - mystartX);
                float jueduiY = Math.abs(endY - mystartY);

                // 計算是不是橫行滑動
                if (jueduiX > jueduiY && Math.abs(jueduiX) > 6) {
                    result = true;
                } else {
                    result = false;
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
            default:
                break;
        }
        return result;
    }
}

 

在Activity如何去使用自定義ViewPager:佈局

     /**
         * 仿viewpager
         */
        myCustomViewPager = (MyCustomViewPager) findViewById(R.id.mycustom_viewpager);

        radioGroup = (RadioGroup) findViewById(R.id.radio_group);

        // 先給View增長一個ImageView
        // ImageView imageView = new ImageView(this);
        // imageView.setBackgroundResource(R.mipmap.a1);
        // myCustomViewPager.addView(imageView);

        int[] imgs  = {R.mipmap.fang_view_pager1,R.mipmap.fang_view_pager2,R.mipmap.fang_view_pager3,
         R.mipmap.fang_view_pager4, R.mipmap.fang_view_pager5, R.mipmap.fang_view_pager6};
for (int i = 0; i < imgs.length; i++) { ImageView imageView = new ImageView(this); imageView.setBackgroundResource(imgs[i]); myCustomViewPager.addView(imageView); } // 把佈局文件添加到自定義ViewPager中 View testLayout = View.inflate(this, R.layout.my_custom_viewpager_layout, null); myCustomViewPager.addView(testLayout, 2); for (int j=0; j<myCustomViewPager.getChildCount(); j++) { RadioButton radioButton = new RadioButton(this); radioButton.setId(j); if (j == 0) { radioButton.setChecked(true); } radioGroup.addView(radioButton); } myCustomViewPager.setIBack(new IMyCustomViewPagerBack() { @Override public void backMethod(int index) { // Toast.makeText(MainActivity.this, "index:" + index, Toast.LENGTH_SHORT).show(); radioGroup.getCheckedRadioButtonId(); radioGroup.check(index); } }); radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup radioGroup, int i) { myCustomViewPager.toScroller(i); } });
相關文章
相關標籤/搜索