Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

示例代码_CheckView #10

Open
GcsSloop opened this issue Feb 5, 2016 · 31 comments
Open

示例代码_CheckView #10

GcsSloop opened this issue Feb 5, 2016 · 31 comments

Comments

@GcsSloop
Copy link
Owner

GcsSloop commented Feb 5, 2016

package com.sloop.canvas;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

/**
 * <ul type="disc">
 * <li>Author: Sloop</li>
 * <li>Version: v1.0.0</li>
 * <li>Copyright: Copyright (c) 2015</li>
 * <li>Date: 2016/2/5</li>
 * <li><a href="http://www.sloop.icoc.cc"    target="_blank">作者网站</a>      </li>
 * <li><a href="http://weibo.com/5459430586" target="_blank">作者微博</a>      </li>
 * <li><a href="https://github.com/GcsSloop" target="_blank">作者GitHub</a>   </li>
 * </ul>
 */
public class CheckView extends View {

    private static final int ANIM_NULL = 0;         //动画状态-没有
    private static final int ANIM_CHECK = 1;        //动画状态-开启
    private static final int ANIM_UNCHECK = 2;      //动画状态-结束

    private Context mContext;           // 上下文
    private int mWidth, mHeight;        // 宽高
    private Handler mHandler;           // handler

    private Paint mPaint;
    private Bitmap okBitmap;

    private int animCurrentPage = -1;       // 当前页码
    private int animMaxPage = 13;           // 总页数
    private int animDuration = 500;         // 动画时长
    private int animState = ANIM_NULL;      // 动画状态

    private boolean isCheck = false;        // 是否只选中状态

    public CheckView(Context context) {
        super(context, null);

    }

    public CheckView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    /**
     * 初始化
     * @param context
     */
    private void init(Context context) {
        mContext = context;

        mPaint = new Paint();
        mPaint.setColor(0xffFF5317);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setAntiAlias(true);

        okBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.checkres);

        mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if (animCurrentPage < animMaxPage && animCurrentPage >= 0) {
                    invalidate();
                    if (animState == ANIM_NULL)
                        return;
                    if (animState == ANIM_CHECK) {

                        animCurrentPage++;
                    } else if (animState == ANIM_UNCHECK) {
                        animCurrentPage--;
                    }

                    this.sendEmptyMessageDelayed(0, animDuration / animMaxPage);
                    Log.e("AAA", "Count=" + animCurrentPage);
                } else {
                    if (isCheck) {
                        animCurrentPage = animMaxPage - 1;
                    } else {
                        animCurrentPage = -1;
                    }
                    invalidate();
                    animState = ANIM_NULL;
                }
            }
        };
    }


    /**
     * View大小确定
     * @param w
     * @param h
     * @param oldw
     * @param oldh
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;
    }

    /**
     * 绘制内容
     * @param canvas
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // 移动坐标系到画布中央
        canvas.translate(mWidth / 2, mHeight / 2);

        // 绘制背景圆形
        canvas.drawCircle(0, 0, 240, mPaint);

        // 得出图像边长
        int sideLength = okBitmap.getHeight();

        // 得到图像选区 和 实际绘制位置
        Rect src = new Rect(sideLength * animCurrentPage, 0, sideLength * (animCurrentPage + 1), sideLength);
        Rect dst = new Rect(-200, -200, 200, 200);

        // 绘制
        canvas.drawBitmap(okBitmap, src, dst, null);
    }


    /**
     * 选择
     */
    public void check() {
        if (animState != ANIM_NULL || isCheck)
            return;
        animState = ANIM_CHECK;
        animCurrentPage = 0;
        mHandler.sendEmptyMessageDelayed(0, animDuration / animMaxPage);
        isCheck = true;
    }

    /**
     * 取消选择
     */
    public void unCheck() {
        if (animState != ANIM_NULL || (!isCheck))
            return;
        animState = ANIM_UNCHECK;
        animCurrentPage = animMaxPage - 1;
        mHandler.sendEmptyMessageDelayed(0, animDuration / animMaxPage);
        isCheck = false;
    }

    /**
     * 设置动画时长
     * @param animDuration
     */
    public void setAnimDuration(int animDuration) {
        if (animDuration <= 0)
            return;
        this.animDuration = animDuration;
    }

    /**
     * 设置背景圆形颜色
     * @param color
     */
    public void setBackgroundColor(int color){
        mPaint.setColor(color);
    }
}
@hunao0221
Copy link

 public void handleMessage(Message msg)

中,应该在

  this.sendEmptyMessageDelayed(0, animDuration / animMaxPage);

前面或者后面invalidate();,不然是看不到动画的,每更新一张picture都刷新一下。

@bqq1986
Copy link

bqq1986 commented Jun 21, 2016

挺好

@wonbin2011
Copy link

赞一个

@flyzend
Copy link

flyzend commented Sep 7, 2016

感谢分享!

@liqiang861220
Copy link

good

@liulixin1
Copy link

public class CheckView extends View {

private static final int ANIM_NULL = 0;         //动画状态-没有
private static final int ANIM_CHECK = 1;        //动画状态-开启
private static final int ANIM_UNCHECK = 2;      //动画状态-结束

private Context mContext;

private Paint mPaint;
private int mWidth, mHeight;//宽高
private Handler handler;
private Bitmap okBitmap;

private int currentPage = -1;//当前页数
private int animCurrentPage = -1;       // 当前页码
private int animMaxPage = 13;           // 总页数
private int animDuration = 500;         // 动画时长

private int animState = ANIM_NULL;      // 动画状态

private boolean isCheck = false;        // 是否只选中状态

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

public CheckView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
}

/**
 * 初始化
 *
 * @param context
 */
private void init(Context context) {
    mContext = context;

    mPaint = new Paint();
    mPaint.setColor(0xffFF5317);
    mPaint.setStyle(Paint.Style.FILL);
    mPaint.setAntiAlias(true);

    okBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.checkmark);

    handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (animCurrentPage < animMaxPage && animCurrentPage >= 0) {
                invalidate();
                if (animState == ANIM_NULL)
                    return;
                if (animState == ANIM_CHECK) {

                    animCurrentPage++;
                } else if (animState == ANIM_UNCHECK) {
                    animCurrentPage--;
                }
                invalidate();
                this.sendEmptyMessageDelayed(0, animDuration / animMaxPage);
                Log.e("AAA", "Count=" + animCurrentPage);
            } else {
                if (isCheck) {
                    animCurrentPage = animMaxPage - 1;
                } else {
                    animCurrentPage = -1;
                }
                invalidate();
                animState = ANIM_NULL;
            }
        }
    };
}


/**
 * View大小确定
 *
 * @param w
 * @param h
 * @param oldw
 * @param oldh
 */
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    mWidth = w;
    mHeight = h;
}

/**
 * 绘制内容
 *
 * @param canvas
 */
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    Log.e("llx", "onDraw()--");
    // 移动坐标系到画布中央
    canvas.translate(mWidth / 2, mHeight / 2);

    // 绘制背景圆形
    canvas.drawCircle(0, 0, 240, mPaint);

    // 得出图像边长
    int sideLength = okBitmap.getHeight();

    // 得到图像选区 和 实际绘制位置
    Rect src = new Rect(sideLength * animCurrentPage, 0, sideLength * (animCurrentPage + 1), sideLength);
    Rect dst = new Rect(200, 200, 200, 200);

    // 绘制
    canvas.drawBitmap(okBitmap, src, dst, null);
}


/**
 * 选择
 */
public void check() {
    if (animState != ANIM_NULL || isCheck)
        return;
    animState = ANIM_CHECK;
    animCurrentPage = 0;
    handler.sendEmptyMessageDelayed(0, animDuration / animMaxPage);
    isCheck = true;
}

/**
 * 取消选择
 */
public void unCheck() {
    if (animState != ANIM_NULL || (!isCheck))
        return;
    animState = ANIM_UNCHECK;
    animCurrentPage = animMaxPage - 1;
    handler.sendEmptyMessageDelayed(0, animDuration / animMaxPage);
    isCheck = false;
}

/**
 * 设置动画时长
 *
 * @param animDuration
 */
public void setAnimDuration(int animDuration) {
    if (animDuration <= 0)
        return;
    this.animDuration = animDuration;
}

/**
 * 设置背景圆形颜色
 *
 * @param color
 */
public void setBackgroundColor(int color) {
    mPaint.setColor(color);
}

}

这是我的代码 为什么图片没有执行显示呢

@GcsSloop
Copy link
Owner Author

注意这里:

Rect dst = new Rect(200, 200, 200, 200);

@liulixin1
Copy link

@GcsSloop 是这里的原因 Thanks

@liqiang861220
Copy link

刚看到你的信息,解决了就好。

在 2016-10-21 19:28:46,"Liulixin" notifications@github.com 写道:

@GcsSloop 是这里的原因 Thanks


You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.

@ghost
Copy link

ghost commented Nov 19, 2016

第一个构造方法中使用super在按钮点击事件会报空指针异常,需要改为this(context,null)就不报异常了,但仍无法显示动画啊。从始至终,一直没有动画效果。本人是一个小白,没有办法了。
public CheckView(Context context) {
super(context, null); //报异常
}

@GcsSloop
Copy link
Owner Author

如果你不是直接继承的 View,那么上层View 可能没有两个参数的构造函数,使用 super(context, null); 就可能报错。
另外,想要显示动画效果需要调用 check 活着 unCheck 方法,直接加载 View 是没有效果的。

@ghost
Copy link

ghost commented Nov 19, 2016

@GcsSloop 我在按钮上已经加入了点击事件了,并且在logCat有打印当前的页码数,只是没有动画效果。所以,我现在也不知道哪里出现了问题。

@GcsSloop
Copy link
Owner Author

检查你的图片和绘制区域的大小是否正确。

1.先在本应该绘制图片等区域绘制一种和背景不同颜色看是否正确。
2.检查图片是否读取成功。
3.检查图片截取大小是否正确。
4.检查是否是硬件加速的问题。 #7

@newcaoguo
Copy link

学习了

@MLLWF
Copy link

MLLWF commented Jan 16, 2017

图片在那能找到?

@GcsSloop
Copy link
Owner Author

这篇文章 图片文字 里面

@MLLWF
Copy link

MLLWF commented Jan 16, 2017

你好,有一点不是很明白,当你选定图片的区域绘制到实际的位置的时候图片会自动按照绘制区域的大小进行缩放啊,怎么会达成你说的那种效果呢? @GcsSloop

@GcsSloop
Copy link
Owner Author

例如截取的部分是 100 x 100 的大小,但绘制区域是 100 x 200 大小,那么图片高度会放大到原来的两倍,以填充所有的区域。

@ZhouKanZ
Copy link

我有个问题,如果一个文字 比如 ‘好’ 女 是绿色 子是红色怎么实现

@GcsSloop
Copy link
Owner Author

如果是左右分的,没有交叉部分的文字,就用遮罩,绘制两次,第一次用绿色,区域只包括左边,第二次用红色,区域只包括右边。

@zhouminxia
Copy link

我按照上面的代码,运行怎么都没有动画效果,在activity中给button设置一个点击时间,调用checkview.check(),但是还是没有动画。

@GcsSloop
Copy link
Owner Author

GcsSloop commented Apr 7, 2017

@zhouminxia
1.资源文件对吗?
2. 剪裁区域和绘制区域是否修改过?
3. handler 正确执行了吗。

@BINBINXIAO
Copy link

为什么我运行的时候报错呢, 说图片资源文件长度太长

@linsir6
Copy link

linsir6 commented Jun 14, 2017

换个手机测试一下吧,我也用了 博主的这个 是 完全好用的。你可以看一下。
https://github.com/linsir6/Android-Notes/blob/master/Android%E8%87%AA%E5%AE%9A%E4%B9%89View/%E8%87%AA%E5%AE%9A%E4%B9%89View%E2%80%94%E2%80%94CheckView.md

@zhanzengyu
Copy link

zhanzengyu commented Oct 18, 2017

@GcsSloop
用了楼主的代码,发现点击check后最后会闪一下。
调试之后发现是由于调用invalidate()时并不会堵塞主线程,是异步问题导致的。
通过在onDraw方法中打印发现绘制了最大页13之后又绘制了12,所以会闪一下。
这边简单修改了下。只改了handle里面的处理:

if (animCurrentPage < animMaxPage && animCurrentPage >= 0) {
    if (animState == ANIM_NULL)
        return;
    if (animState == ANIM_CHECK) {
        animCurrentPage++;
    } else if (animState == ANIM_UNCHECK) {
        animCurrentPage--;
    }
    //animCurrentPage为animMaxPage不需要更新,否则下面的else会导致绘制前一张图闪一下
    if (animCurrentPage != animMaxPage) {
        invalidate();
    }
    this.sendEmptyMessageDelayed(0, animDuration / animMaxPage);
} else {
    if (isCheck) {
        animCurrentPage = animMaxPage - 1;
    } else {
        animCurrentPage = -1;
    }
    invalidate();
    animState = ANIM_NULL;
}

@xqgdmg
Copy link

xqgdmg commented Mar 29, 2018

@huo2016
Copy link

huo2016 commented Jul 4, 2018

为啥我的显示效果和你的效果不太一样

@longjianghong
Copy link

My Code is as follows,for your reference.(please ignore my shandong chinese english 😔)

public class CheckView extends View {
private Paint mPaint;
private static final int ANIM_NULL=0;
private static final int ANIM_CHECK=1;
private static final int ANIM_UNCHECK=2;
private int mWidth,mHeight;
private Handler mHandler;
private Bitmap okBitmap;
private int animCurrentPage=-1;
//TODO:页面不需要是13页,因该是12页,12页至13页才是正确的绘制区域
private int animMaxPage=12;
private int animDuration=500;
private int animState=ANIM_NULL;
private boolean isCheck=false;
private static final String TAG = "RightView";

public CheckView(Context context) {
    super(context);
    init(context,null);
}

public CheckView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    init(context,attrs);
}
private void init(Context context, @Nullable AttributeSet attrs){
    mPaint=new Paint();
    mPaint.setColor(Color.YELLOW);
    mPaint.setStyle(Paint.Style.FILL);
    mPaint.setAntiAlias(true);
    okBitmap= BitmapFactory.decodeResource(context.getResources(),R.drawable.check_mark);
    mHandler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (animCurrentPage<animMaxPage&&animCurrentPage>=0){
                invalidate();
                if (animState==ANIM_NULL){
                    return;
                }
                if (animState==ANIM_CHECK){
                    animCurrentPage++;
                    Log.e(TAG, "handleMessage: 当前页面"+animCurrentPage );
                }else if (animState==ANIM_UNCHECK){
                    animCurrentPage--;
                }

                this.sendEmptyMessageDelayed(0,animDuration/animMaxPage);
            }else {
                if (isCheck){
                    animCurrentPage=animMaxPage-1;
                }else {
                    animCurrentPage=-1;
                }
                //TODO:这里不需要重绘了,当前页面减一页会导致onDraw()方法多执行一边造成页面回退,出现闪烁现象

// invalidate();
animState=ANIM_NULL;
}
}
};

}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    mWidth=w;
    mHeight=h;

}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.translate(mWidth/2,mHeight/2);
    canvas.drawCircle(0,0,240,mPaint);
    int sideLength = okBitmap.getHeight();
    // 得到图像选区 和 实际绘制位置
    Rect src = new Rect(sideLength * animCurrentPage, 0, sideLength * (animCurrentPage + 1), sideLength);
    Rect dst = new Rect(-150, -150, 150, 150);
    Log.e(TAG, "onDraw: 绘制区域:"+sideLength * animCurrentPage+"    "+0+"   "+sideLength * (animCurrentPage + 1)+"   "+sideLength );


    // 绘制
    canvas.drawBitmap(okBitmap, src, dst, mPaint);


}

public void check(){
    if (animState!=ANIM_NULL&&isCheck){
        return;
    }else {
        animState=ANIM_CHECK;
        animCurrentPage=0;
        isCheck=true;
        mHandler.sendEmptyMessageDelayed(0,animDuration/animMaxPage);
    }
}

/**
 * 取消选择
 */
public void unCheck() {
    if (animState != ANIM_NULL || (!isCheck))
        return;
    animState = ANIM_UNCHECK;
    animCurrentPage = animMaxPage - 1;
    mHandler.sendEmptyMessageDelayed(0, animDuration / animMaxPage);
    isCheck = false;
}

public void setDuration(int duration){
    if (duration<=0){
        return;
    }else {
        this.animDuration=duration;
    }
}
public void setBackGroundColor(int color){
    mPaint.setColor(color);
}

}
我主要是解决了一下页面闪烁现象,多谢楼主大大 学习了 Master!!!(手动 抱拳O(∩_∩)O )

@zstartw
Copy link

zstartw commented Aug 21, 2018

主要实现功能的代码

 // 指定图片绘制区域
Rect src = new Rect(sideLength * animCurrentPage, 0, sideLength * (animCurrentPage + 1), sideLength);
// 指定图片在屏幕上显示的区域
Rect dst = new Rect(-200, -200, 200, 200);
 // 绘制
canvas.drawBitmap(okBitmap, src, dst, null);

@lodgkk
Copy link

lodgkk commented Dec 13, 2018

不知道为什么我照着楼主的onDraw里面做,图片都无法显示,我换成这样,就可以了
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
if (canvas == null || okBitmap == null) return

    canvas.translate((mWidth / 2).toFloat(), (mHeight / 2).toFloat())

    // 得出图像边长
    val sideLength = okBitmap!!.height

    canvas.drawCircle(0f, 0f, (sideLength / 2 + 20).toFloat(), mPaint)

    // 算出图片每次需要截取的长度
    var right = sideLength / animMaxPage * animCurrentPage
    if (right > sideLength) right = sideLength

    // 算出绘制框需要显示的长度,因为是从中间点左边负的图片边长的一半加上每次变换的值
    var bRight = (0 - sideLength) / 2 + (sideLength / animMaxPage * animCurrentPage)
    if (bRight > sideLength / 2) bRight = sideLength / 2

    // 从图片的顶部坐标0,左边坐标0,底部坐标图片的长度,右边坐标是截取的长度
    val src = Rect(0, 0, right, sideLength)
    // 由于已经移动到屏幕的中间点,所以显示的区域是从中间点开始,顶部的坐标是负的图片边长的一半,底部坐标也是边长的一半
    // 左边坐标也是负的图片边长的一半,右边坐标是上面算出的长度
    val dst = Rect((0 - sideLength) / 2, (0 - sideLength) / 2, bRight, sideLength / 2)

    canvas.drawBitmap(okBitmap, src, dst, null)
}

@PaulX1029
Copy link

读取到了Bitmap 也能打印页数,绘制不同颜色的Rect也能出现,但就是没有动画,可以给我一个完整Demo吗?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests