自定义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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值