Android 自定义View 横向翻页

原理见翻页效果原理实现之翻页的尝试



package com.stone.turnpage.view;

import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

/**
 * author : stone
 * email  : aa86799@163.com
 * time   : 16/7/8 10 35
 */
public class HorizonTurnPageView extends View {

    private List<Bitmap> mBitmaps;
    private float mClipX; //裁剪右端点坐标
    private float mCurPointX;// 指尖触碰屏幕时点X的坐标值
    private float mAutoAreaLeft, mAutoAreaRight; //控件左侧和右侧自动吸附的区域
    private boolean mIsLastPage; //是否最后一页
    private boolean mIsNextPage; //是否下一页
    private int mPageIndex;

    private Runnable mMsgCallback;
    private Handler mHandler = new Handler();

    public HorizonTurnPageView(Context context) {
        super(context);

//        ViewConfiguration.get(context).getScaledTouchSlop()
    }

    public void setBitmaps(List<Bitmap> bitmaps) {
        if (null == bitmaps || bitmaps.size() == 0) return;
        this.mBitmaps = bitmaps;
        System.out.println("setBitmaps");
        invalidate();
    }

    /**
     * 图片倒序:集合中最先加入的图(最后绘制)就能绘制在最上层
     */
    private void initBitmaps() {
        if (mBitmaps == null) {
            return;
        }
        List<Bitmap> temp = new ArrayList<Bitmap>();
        for (int i = mBitmaps.size() - 1; i >= 0; i--) {
            Bitmap bitmap = Bitmap.createScaledBitmap(mBitmaps.get(i), getWidth(), getHeight(), true);
            temp.add(bitmap);
        }
        mBitmaps = temp;
    }

    private void drawBitmaps(Canvas canvas) {
/*        for (int i = 0; i < mBitmaps.size(); i++) {
//            canvas.save();

            if (i == mBitmaps.size() - 1) {//只有最后一位的图片(即原集合中的首图)时才裁剪一次
                canvas.clipRect(0, 0, mClipX, getHeight());
            }
            canvas.drawBitmap(mBitmaps.get(i), 0, 0, null);

//            canvas.restore();
        }*/

        /*
        如果图片太多,那么 其实只要绘制上下两张图即可,  而不用 所有都绘制
        代码重构如下
         */
        mIsLastPage = false;
        mPageIndex = mPageIndex < 0 ? 0 : mPageIndex;
        mPageIndex = mPageIndex > mBitmaps.size() ? mBitmaps.size() : mPageIndex;
        // 计算数据起始位置
        int start = mBitmaps.size() - 2 - mPageIndex;//mBitmaps.size() - 2 表示倒数第二个
        int end = mBitmaps.size() - mPageIndex;   // end - start = 2
        /*
         * 如果数据起点位置小于0则表示当前已经到了最后一张图片
         */
        if (start < 0) {
            mIsLastPage = true; // 此时mPageIndex = size - 1

            showToast("已经最后一页了");
            // 强制重置起始位置
            start = 0;
            end = 1;
        }
        for (int i = start; i < end; i++) {//end - start = 2   这里最多循环两次
            if (!mIsLastPage && i == end - 1) {
                canvas.clipRect(0, 0, mClipX, getHeight()); //之后的绘制会相对当前裁剪区
            }
            canvas.drawBitmap(mBitmaps.get(i), 0, 0, null);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mIsNextPage = true;
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                mCurPointX = event.getX();
                if (mCurPointX < mAutoAreaLeft) {
                    mIsNextPage = false; //上一页
                    mPageIndex--;
                    mClipX = mCurPointX;
                    invalidate();
                }
                break;

            case MotionEvent.ACTION_MOVE:
                mClipX = event.getX();
                invalidate();
                break;

            case MotionEvent.ACTION_UP:
                judgeSlideAuto();
                /*
                 * 如果当前页不是最后一页
                 * 如果是需要翻下一页
                 * 并且上一页已被clip掉,即judgeSlideAuto中执行了向左
                 */
                if (!mIsLastPage && mIsNextPage && mClipX <= 0) {
                    mPageIndex++;
                    mClipX = getWidth();
                    invalidate();
                }
                break;
        }
        return true;
    }

    /**
     * 判断是否要自动滑动: 向左或向右 滑动到底
     */
    private void judgeSlideAuto() {
        if (mClipX < mAutoAreaLeft) {// 小于 1/5 w   向左
            while (mClipX > 0) {
                mClipX--;
                invalidate();
            }

        } else if (mClipX > mAutoAreaRight) {// 大于 4/5 w  向右
            while (mClipX < getWidth()) {
                mClipX++;
                invalidate();
            }
        }
    }

    /*
    onMeasure后 调用, 如果是ViewGroup型, 在onLayout时又改变了大小才会 再次调用
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        System.out.println("onSizeChanged");
        initBitmaps();

        mClipX = getWidth();
        mAutoAreaLeft = getWidth() / 5f;
        mAutoAreaRight = getWidth() / 5f * 4;

    }

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

        if (null == mBitmaps || mBitmaps.size() == 0) {
            return;
        }
        drawBitmaps(canvas);

    }

    private void showToast(final Object msg) {
        mHandler.removeCallbacksAndMessages(null);
        mMsgCallback = new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getContext(), msg.toString(), Toast.LENGTH_SHORT).show();
            }
        };
        mHandler.postDelayed(mMsgCallback, 200);

    }

}

我的自定义View项目地址: https://github.com/aa86799/MyCustomView (欢迎start&fork)

本文地址:https://github.com/aa86799/MyCustomView/tree/master/turnpage

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值