仿ViewPager实现页面切换的动画效果

时间:2021-07-06 17:58:39

(1)自定义类继承ViewGroup,并实现一个构造方法和onLayout方法

public class MyScrollPager extends ViewGroup{
    
    private Context ctx;

    public MyScrollPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
    //定义页面的布局
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
    }

(2)在xml(activity_mian.xml)布局中添加自定义view

  <com.bxf.myviewpager.MyScrollPager
         android:id="@+id/mypager"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"/>

(3)在MainActivity中找到此view比添加几个子view

public class MainActivity extends Activity{
    
    private int[] ids = {R.drawable.a1,R.drawable.a2,R.drawable.a3,R.drawable.a4,R.drawable.a5,R.drawable.a6};
    private MyScrollPager scrollPager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        scrollPager = (MyScrollPager) findViewById(R.id.mypager);
        
        for (int i = 0; i < ids.length; i++) {
            ImageView image = new ImageView(this);
            image.setBackgroundResource(ids[i]);
            scrollPager.addView(image);//将imageview 添加到view中
        }
    }
}
(4)在MyScrollPager中找到新添加的子view,并指定其位置

//定义页面的布局
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        //定义每一个view的布局
        int count = getChildCount();
        for (int i = 0; i < count; i++) {
            View view = getChildAt(i);
            view.layout(i*getWidth(), 0, getWidth() + i*getWidth(), getHeight());
        }
    }

(5)添加滑动监听事件,并实现滑动切换

GestureDetector gestureDetector = new GestureDetector(ctx, new OnGestureListener() {
            
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                return false;
            }
            
            @Override
            public void onShowPress(MotionEvent e) {
                
            }
            
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
                    float distanceY) {
                scrollBy((int) distanceX, 0);//在屏幕上滑动
                return false;
            }
            
            @Override
            public void onLongPress(MotionEvent e) {
                
            }
            
            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                    float velocityY) {
                return false;
            }
            
            @Override
            public boolean onDown(MotionEvent e) {
                return false;
            }
        });//手势识别器
    private float firstX = 0;//初始位置
    private float offsetX = 0;//初始位置
    private int currId = 0;//当前屏幕显示的图片ID
    //设置滑动监听
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        gestureDetector.onTouchEvent(event);
        
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            firstX = event.getX();
            break;
        case MotionEvent.ACTION_MOVE:
            
            break;
        case MotionEvent.ACTION_UP:
            offsetX = event.getX() - firstX;
            updateCurrId(offsetX);
            //瞬间移动
            scrollTo(currId * getWidth(), 0);
            break;

        }
        return true;
    }

//更新当前显示的图片ID
    private void updateCurrId(float endX2) {
        if(offsetX > getWidth()/2){
            currId --;//上一张图片
        }else if(offsetX < -getWidth()/2){
            currId ++;//下一张图片
        }
        currId = (currId>0)?currId:0;
        currId = (currId>=getChildCount()-1)?getChildCount()-1:currId;
    }

(6)实现缓慢滚动效果

创建滚动类,Scroller管理滚动的位置

public class Scroller {
    
    private int duration = 500;//需要滚动的时间
    private float currX;//滚动到的当前位置
    
    

    private float startX;
    private float startY;
    private float disX;
    private float disY;
    private long startTime;
    private boolean isFinish;//是否结束了滚动--true->是
    public void startScroll(float startX, float startY, float disX, float disY) {
        this.startX = startX;
        this.startY = startY;
        this.disX = disX;
        this.disY = disY;
        this.startTime = SystemClock.uptimeMillis();
        this.isFinish = false;
    }
    
    public boolean computeScrollOffset(){
        if(isFinish){//滚动已经结束
            return false;
        }
        long currTime = SystemClock.uptimeMillis();
        long scrollTime = currTime - startTime;
        //计算滚动到的当前位置
        if(scrollTime < duration){
            //正在滚动
            currX = startX + disX*scrollTime/duration;
        }else{
            //滚动完成
            currX = startX + disX;
            isFinish = true;
        }
        return true;
    }
    
    
    public int getDuration() {
        return duration;
    }

    public void setDuration(int duration) {
        this.duration = duration;
    }

    public float getCurrX() {
        return currX;
    }

    public void setCurrX(float currX) {
        this.currX = currX;
    }
    
}

 

(7)最后MianActivity中的代码如下

import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

public class MyScrollPager extends ViewGroup{
    
    private Context ctx;
    private Scroller scroller;

    public MyScrollPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.ctx = context;
        init();
    }
    
    //定义页面的布局
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        //定义每一个view的布局
        int count = getChildCount();
        for (int i = 0; i < count; i++) {
            View view = getChildAt(i);
            view.layout(i*getWidth(), 0, getWidth() + i*getWidth(), getHeight());
        }
    }
    
    GestureDetector gestureDetector;//手势识别器
    private float firstX = 0;//初始位置
    private float offsetX = 0;//初始位置
    private int currId = 0;//当前屏幕显示的图片ID
    //设置滑动监听
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        gestureDetector.onTouchEvent(event);
        
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            firstX = event.getX();
            break;
        case MotionEvent.ACTION_MOVE:
            
            break;
        case MotionEvent.ACTION_UP:
            offsetX = event.getX() - firstX;
            updateCurrId(offsetX);
            //瞬间移动
            scrollTo(currId * getWidth(), 0);
            //缓慢移动
            getScrollX();//代表左边缘总共滑动的距离距起始点的距离
            scroller.startScroll(getScrollX(), 0,currId * getWidth() - getScrollX(),0);
            break;

        }
        invalidate();//刷新界面,这个方法会导致computeScroll方法的执行
        return true;
    }
    @Override
    public void computeScroll() {
        if(scroller.computeScrollOffset()){
            float currX = scroller.getCurrX();
            scrollTo((int) currX, 0);
            invalidate();//刷新界面
        }
    }
    //更新当前显示的图片ID
    private void updateCurrId(float endX2) {
        if(offsetX > getWidth()/2){
            currId --;//上一张图片
        }else if(offsetX < -getWidth()/2){
            currId ++;//下一张图片
        }
        currId = (currId>0)?currId:0;
        currId = (currId>=getChildCount()-1)?getChildCount()-1:currId;
    }

    private void init() {
        scroller = new Scroller();
        gestureDetector = new GestureDetector(ctx, new OnGestureListener() {
            
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                return false;
            }
            
            @Override
            public void onShowPress(MotionEvent e) {
                
            }
            
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
                    float distanceY) {
                scrollBy((int) distanceX, 0);//在屏幕上滑动
                return false;
            }
            
            @Override
            public void onLongPress(MotionEvent e) {
                
            }
            
            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                    float velocityY) {
                return false;
            }
            
            @Override
            public boolean onDown(MotionEvent e) {
                return false;
            }
        });
    }
}