AndroidNote
AndroidNote copied to clipboard
示例代码_CheckView
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);
}
}
在
public void handleMessage(Message msg)
中,应该在
this.sendEmptyMessageDelayed(0, animDuration / animMaxPage);
前面或者后面invalidate();,不然是看不到动画的,每更新一张picture都刷新一下。
挺好
赞一个
感谢分享!
good
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);
}
}
这是我的代码 为什么图片没有执行显示呢
注意这里:
Rect dst = new Rect(200, 200, 200, 200);
@GcsSloop 是这里的原因 Thanks
刚看到你的信息,解决了就好。
在 2016-10-21 19:28:46,"Liulixin" [email protected] 写道:
@GcsSloop 是这里的原因 Thanks
— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.
第一个构造方法中使用super在按钮点击事件会报空指针异常,需要改为this(context,null)就不报异常了,但仍无法显示动画啊。从始至终,一直没有动画效果。本人是一个小白,没有办法了。 public CheckView(Context context) { super(context, null); //报异常 }
如果你不是直接继承的 View,那么上层View 可能没有两个参数的构造函数,使用 super(context, null); 就可能报错。
另外,想要显示动画效果需要调用 check 活着 unCheck 方法,直接加载 View 是没有效果的。
@GcsSloop 我在按钮上已经加入了点击事件了,并且在logCat有打印当前的页码数,只是没有动画效果。所以,我现在也不知道哪里出现了问题。
检查你的图片和绘制区域的大小是否正确。
1.先在本应该绘制图片等区域绘制一种和背景不同颜色看是否正确。 2.检查图片是否读取成功。 3.检查图片截取大小是否正确。 4.检查是否是硬件加速的问题。 https://github.com/GcsSloop/AndroidNote/issues/7
学习了
图片在那能找到?
你好,有一点不是很明白,当你选定图片的区域绘制到实际的位置的时候图片会自动按照绘制区域的大小进行缩放啊,怎么会达成你说的那种效果呢? @GcsSloop
例如截取的部分是 100 x 100 的大小,但绘制区域是 100 x 200 大小,那么图片高度会放大到原来的两倍,以填充所有的区域。
我有个问题,如果一个文字 比如 ‘好’ 女 是绿色 子是红色怎么实现
如果是左右分的,没有交叉部分的文字,就用遮罩,绘制两次,第一次用绿色,区域只包括左边,第二次用红色,区域只包括右边。
我按照上面的代码,运行怎么都没有动画效果,在activity中给button设置一个点击时间,调用checkview.check(),但是还是没有动画。
@zhouminxia 1.资源文件对吗? 2. 剪裁区域和绘制区域是否修改过? 3. handler 正确执行了吗。
为什么我运行的时候报错呢, 说图片资源文件长度太长
换个手机测试一下吧,我也用了 博主的这个 是 完全好用的。你可以看一下。 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
@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;
}
赞
为啥我的显示效果和你的效果不太一样
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 )
主要实现功能的代码
// 指定图片绘制区域
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);
不知道为什么我照着楼主的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)
}
读取到了Bitmap 也能打印页数,绘制不同颜色的Rect也能出现,但就是没有动画,可以给我一个完整Demo吗?
