ViewPager简单实现

package com.edu.fzu.news.view;

import android.content.Context;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Scroller;
/**
 * 使用:
 *       MyScrollView myScrollView = (MyScrollView) findViewById(R.id.myscrollview);
 *       // 添加子View到MyScrollView中
         for (int i = 0; i < ids.length; i++) {
            ImageView image = new ImageView(this);
            image.setBackgroundResource(ids[i]);
            myScrollView.addView(image);
         }
 * 
 * 
 */

/**
 * 仿ViewPager:实现ViewPager随着手指的滑动而滑动
 * 实现:
 * 1.界面:测量,布局(充血onMeasure和onLayout)
 * 2.事件:滑动跟随运动(onTouch事件),松手缓慢滑动到指定位置(Scroller类+computeScroll回调)
 * 补充:
 *  1.控件滑动有三种方式:Scroller,动画,Layoutparams
 *  2.如果要实现类似ViewPager的回调,可采用设计回调接口,然后对外暴露
 */
public class MyScrollView extends ViewGroup {
    private Scroller mScroller;

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

    public MyScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    private void initView() {
        mScroller = new Scroller(getContext());
    }

    /*
        display:
        1.measure
        2.layout
        3.draw--this is view, so don't draw
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // measure self
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        // measure child
        for (int i=0; i<getChildCount(); i++) {
            measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);
        }
     }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        // layout child
        for (int i=0; i<getChildCount(); i++) {
            View view = getChildAt(i);
            view.layout(i*getWidth(), 0, (i+1)*getWidth(), getHeight());
        }
    }


    /*
    刷新思路:
        1.监听滑动松开(ACTION_UP),调用启动缓慢滑动事件myScroller.startScroll
           并刷新当前view,invalidate();
        2.调用invalidate();导致computeScroll被回调
        3.计算滑动是否完成myScroller.computeScrollOffset,并获取中间位置
           myScroller.getCurrX(),跳转到中间位置
        4.重新刷新界面(递归上面2-4步骤)
    */

    /*
        event:
        deal the scroll event
        scroll distance
     */
    private PointF downPoint = new PointF();
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // mGestureDetector.onTouchEvent(event);
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downPoint.set(event.getX(), event.getY());
                break;
            case MotionEvent.ACTION_MOVE:
                float curX = event.getX();
                float disX = -(curX - downPoint.x);
                scrollBy((int) disX, 0);
                downPoint.x = curX;
                break;
            case MotionEvent.ACTION_UP:
                int nextId = (getScrollX()+getWidth()/2) / getWidth();
                moveToDest(nextId);
                break;
        }

        return true;
    }

    /**
     * 移动到指定的屏幕上
     * @param nextId   屏幕 的下标
     */
    private void moveToDest(int nextId) {
        // check nextId between[0, getChildCount())
        if (nextId < 0) {
            nextId = 0;
        }
        if (nextId > getChildCount()-1) {
            nextId = getChildCount() - 1;
        }

        //瞬间移动
        // scroll direct to distination
        // scrollTo(nextId*getWidth(), 0);

        //缓慢移动到指定最终位置
        int dx = nextId*getWidth() - getScrollX();
        mScroller.startScroll(getScrollX(), 0, dx, 0);
        /*
       * 刷新当前view   onDraw()方法 的执行
       */
        invalidate();
    }

    @Override
    /**
     * invalidate();  会导致  computeScroll()这个方法的执行
     */
    public void computeScroll() {
        if(mScroller.computeScrollOffset()){   // 有点类似回调:两个函数循环互相调用
            int newX = (int) mScroller.getCurrX();
            scrollTo(newX, 0);

            invalidate();
        };
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值