自定义View学习之12/6(Viewpager高级定制)

今天我们准备做一款根据viewpager做改动的自定义圆点,并且更改viewpager原有动画。

思路如下:
1、做到自动化,圆点根据viewpager的大小来订制。有多少个viewpager就有多少个圆点;
2、滑动的时候让圆点也要跟着滑动;
3、去掉viewpager原有动画,加上自己需要的移动动画;
4、设置点击事件,为了不让事件冲突,我这里是用OnTouch来模拟点击做的;

先贴效果:

界面代码如下(代码里面有详细注释):

package com.wyw.viewpageranimationdemo;

import java.util.ArrayList;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends Activity {

    // 切换页控件
    private ViewPager viewPager;
    // 切换也白点控件
    private CircleViewpager circlePager;
    // view集合
    private ArrayList<View> views;
    // 切换页适配器
    private ViewPagerAdapter adapter;
    //当前轮播下标
    public int currentItem = 0;
    //按下的X轴
    private float downx;
    //按下的Y轴
    private float downy;

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

        viewPager = (ViewPager) findViewById(R.id.viewPager);
        circlePager = (CircleViewpager) findViewById(R.id.indicator);

        initData();

        //捕捉页面切换Touch事件
        viewPager.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                switch (motionEvent.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        //按下时关闭轮播
                        downx = motionEvent.getRawX();
                        downy = motionEvent.getRawY();
                        break;
                    case MotionEvent.ACTION_UP:
                        //按下的xy轴 - 抬起时的xy轴 < 10 就等于是点击事件
                        if (Math.abs(downx - motionEvent.getRawX()) < 10 && Math.abs(downy - motionEvent.getRawY()) < 10) {
                            Toast.makeText(MainActivity.this, currentItem+"", Toast.LENGTH_LONG).show();
                        }
                        break;
                }
                return false;
            }
        });
    }

    private void initData() {
        views = new ArrayList<View>();
        for (int i = 0; i < 4; i++) {
            ImageView img = new ImageView(MainActivity.this);
            img.setScaleType(ImageView.ScaleType.CENTER_CROP);
            img.setTag(i);
            switch (i) {
            case 0:
                img.setBackgroundResource(R.color.ffffaf1a);
                break;
            case 1:
                img.setBackgroundResource(R.color.ffef5088);
                break;
            case 2:
                img.setBackgroundResource(R.color.ff56ae2e);
                break;
            case 3:
                img.setBackgroundResource(R.color.ff3598da);
                break;
            default:
                break;
            }
            views.add(img);
        }
        adapter = new ViewPagerAdapter();
        viewPager.setAdapter(adapter);

        //设置圆点的纵向位置 距上面185dp
        circlePager.setDy(DisplayUtil.dip2px(MainActivity.this, 185));
        //设置圆点传入viewPager自动算出多少个圆点
        circlePager.setViewPager(viewPager, MainActivity.this);
        //设置切换动画
        viewPager.setPageTransformer(true, new CubeOutTransformer());
    }

    private class ViewPagerAdapter extends PagerAdapter {

        // 获取要滑动的控件的数量,在这里我们以滑动的广告栏为例,那么这里就应该是展示的广告图片的ImageView数量
        @Override
        public int getCount() {
            return views.size();
        }

        // 来判断显示的是否是同一张图片,这里我们将两个参数相比较返回即可
        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }

        // 当要显示的图片可以进行缓存的时候,会调用这个方法进行显示图片的初始化,我们将要显示的ImageView加入到ViewGroup中,然后作为返回值返回即可
        @Override
        public Object instantiateItem(ViewGroup view, final int position) {
            view.addView(views.get(position));
            return views.get(position);
        }

        // PagerAdapter只缓存三张要显示的图片,如果滑动的图片超出了缓存的范围,就会调用这个方法,将图片销毁
        @Override
        public void destroyItem(ViewGroup view, int position, Object object) {
            view.removeView(views.get(position));
        }
    }
}

自定义圆点代码:

package com.wyw.viewpageranimationdemo;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.View;

/** * 自动创建圆点viewpager */
public class CircleViewpager extends View implements ViewPager.OnPageChangeListener {
    // 上下文
    private Context context;
    // 切换页面控件
    private ViewPager mViewPager;
    // 当前滑动状态
    private int mScrollState;
    // 第几页
    private int mCurrentPage;
    // 当前页面偏移的百分比
    private float mPageOffset;
    // 页面总数
    private int count;
    // 第一个圆点显示的位置
    float longOffset;

    // 圆点的半径
    private float mRadius;
    // 第一个圆点的左边x坐标和第二个圆点的左边x坐标相距5个半径(实际第一个和第二个真是相距是3个半径)
    public float dX;
    // y坐标
    private float dy;

    // 移动的圆点画笔
    private Paint mPaintFill;
    // 固定的圆点画笔
    private Paint mPaintStroke;

    // 车生活fragment
    private MainActivity MainActivity;

    private int width;

    // 设置y坐标
    public void setDy(float dy) {
        this.dy = dy;
    }

    public CircleViewpager(Context context) {
        super(context);
        this.context = context;
        init();
    }

    public CircleViewpager(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        init();
    }

    public CircleViewpager(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        init();
    }

    private void init() {
        // 默认-1
        dy = -1;
        //屏幕宽度
        width = DisplayUtil.getScreenWidthPx(context);
        //圆点的半径 是4dp
        mRadius = DisplayUtil.dip2px(context, 4);
        //第一个圆点的左边x坐标和第二个圆点的左边x坐标相距4个半径(实际第一个和第二个真是相距是2个半径)
        dX = mRadius * 4;

        mPaintFill = new Paint();
        mPaintFill.setStyle(Paint.Style.FILL);
        mPaintFill.setColor(getResources().getColor(R.color.white));

        mPaintStroke = new Paint();
        mPaintStroke.setStyle(Paint.Style.FILL);
        mPaintStroke.setColor(getResources().getColor(R.color.white_30));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mViewPager == null) {
            return;
        }
        // 获取总页数
        count = mViewPager.getAdapter().getCount();
        if (count == 0) {
            return;
        }
        // 第一个圆点的位置
        longOffset = (width / 2.0f) - ((count - 1) * dX / 2.0f);
        if (dy != -1) {
            for (int i = 0; i < count; i++) {
                // 在指定x和y坐标画出默认圆点
                canvas.drawCircle(longOffset + (dX * i), dy, mRadius,
                        mPaintStroke);
            }
        }

        // 在指定x和y坐标画出移动圆点
        canvas.drawCircle(
                (mCurrentPage * dX) + (dX * mPageOffset) + longOffset, dy,
                mRadius, mPaintFill);
    }

    // 设置viewpager
    public void setViewPager(ViewPager view, MainActivity MainActivity) {
        if (mViewPager == view) {
            if (mViewPager.getAdapter().getCount() == view.getAdapter()
                    .getCount()) {
                return;
            }
        }
        if (view.getAdapter() == null) {
            return;
        }
        if (mViewPager != null) {
            mViewPager.setOnPageChangeListener(null);
        }
        this.MainActivity = MainActivity;
        mViewPager = view;
        // 设置页面切换监听
        mViewPager.setOnPageChangeListener(this);
        invalidate();
    }

    @Override
    public void onPageScrolled(int position, float positionOffset,
            int positionOffsetPixels) {
        // 获取当前页下标
        mCurrentPage = position;
        // 获取当前页面偏移的百分比
        mPageOffset = positionOffset;
        invalidate();
    }

    @Override
    public void onPageSelected(int position) {
        // mScrollState ==SCROLL_STATE_DRAGGING
        // 表示正在滑动,mScrollState==SCROLL_STATE_SETTLING 表示滑动完毕了,
        // mScrollState==SCROLL_STATE_IDLE表示什么都没做
        if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
            // 获取当前页下标
            mCurrentPage = position;
            invalidate();
        }
        MainActivity.currentItem = position;
    }

    @Override
    public void onPageScrollStateChanged(int state) {
        // mScrollState ==1表示正在滑动,mScrollState==2表示滑动完毕了,mScrollState==0表示什么都没做
        mScrollState = state;
    }
}

去除viewpager原有滑动动画改为自定义代码(找的网上开源代码这里就不注释了,调用只需要这一段代码即可viewPager.setPageTransformer(true, new CubeOutTransformer());)。如果需要自己改动画重写CubeOutTransformer这个类里面这个onTransform()这个方法即可;

package com.wyw.viewpageranimationdemo; import android.annotation.SuppressLint; import android.support.v4.view.ViewPager.PageTransformer; import android.view.View; @SuppressLint("NewApi") public abstract class ABaseTransformer implements PageTransformer { /** * Called each {@link #transformPage(View, float)}. * * @param page * Apply the transformation to this page * @param position * Position of page relative to the current front-and-center position of the pager. 0 is front and * center. 1 is one full page position to the right, and -1 is one page position to the left. */ protected abstract void onTransform(View page, float position); /** * Apply a property transformation to the given page. For most use cases, this method should not be overridden. * Instead use {@link #transformPage(View, float)} to perform typical transformations. * * @param page * Apply the transformation to this page * @param position * Position of page relative to the current front-and-center position of the pager. 0 is front and * center. 1 is one full page position to the right, and -1 is one page position to the left. */ @Override public void transformPage(View page, float position) { onPreTransform(page, position); onTransform(page, position); onPostTransform(page, position); } /** * If the position offset of a fragment is less than negative one or greater than one, returning true will set the * fragment alpha to 0f. Otherwise fragment alpha is always defaulted to 1f. * * @return */ protected boolean hideOffscreenPages() { return true; } /** * Indicates if the default animations of the view pager should be used. * * @return */ protected boolean isPagingEnabled() { return false; } /** * Called each {@link #transformPage(View, float)} before {{@link #onTransform(View, float)}. * <p> * The default implementation attempts to reset all view properties. This is useful when toggling transforms that do * not modify the same page properties. For instance changing from a transformation that applies rotation to a * transformation that fades can inadvertently leave a fragment stuck with a rotation or with some degree of applied * alpha. * * @param page * Apply the transformation to this page * @param position * Position of page relative to the current front-and-center position of the pager. 0 is front and * center. 1 is one full page position to the right, and -1 is one page position to the left. */ protected void onPreTransform(View page, float position) { final float width = page.getWidth(); page.setRotationX(0); page.setRotationY(0); page.setRotation(0); page.setScaleX(1); page.setScaleY(1); page.setPivotX(0); page.setPivotY(0); page.setTranslationY(0); page.setTranslationX(isPagingEnabled() ? 0f : -width * position); if (hideOffscreenPages()) { page.setAlpha(position <= -1f || position >= 1f ? 0f : 1f); page.setEnabled(false); } else { page.setEnabled(true); page.setAlpha(1f); } } /** * Called each {@link #transformPage(View, float)} after {@link #onTransform(View, float)}. * * @param page * Apply the transformation to this page * @param position * Position of page relative to the current front-and-center position of the pager. 0 is front and * center. 1 is one full page position to the right, and -1 is one page position to the left. */ protected void onPostTransform(View page, float position) { } /** * Same as {@link Math#min(double, double)} without double casting, zero closest to infinity handling, or NaN support. * * @param val * @param min * @return */ protected static final float min(float val, float min) { return val < min ? min : val; } } package com.wyw.viewpageranimationdemo; import android.annotation.SuppressLint; import android.view.View; @SuppressLint("NewApi") public class CubeOutTransformer extends ABaseTransformer { @Override protected void onTransform(View view, float position) { view.setPivotX(position < 0f ? view.getWidth() : 0f); view.setPivotY(view.getHeight() * 0.5f); view.setRotationY(90f * position); } @Override public boolean isPagingEnabled() { return true; } }

本篇博客就到这里,如果对viewpager滑动动画有兴趣的朋友可以去尝试重写那个类,改变他的滑动轨迹。

希望大家多多关注我的博客,多多支持我。
如有好意见或更好的方式欢迎留言谈论。

尊重原创转载请注明:(http://blog.csdn.net/u013895206) !

下面是地址传送门:
http://download.csdn.net/detail/u013895206/9344739

你可能感兴趣的:(动画,viewpager,自定义,自动化,滑动)