android 自定义view实现刮刮卡效果
来源:互联网 发布:编译linux内核 编辑:程序博客网 时间:2024/06/06 04:07
感觉好久没写博客了,最近也是很烦,现在可以要好好学习,把自己的心态调整好,
今天实现一个刮刮卡效果,主要用到的知识点还是canvas和paint,Path这几个类,不熟悉的可以先把这三个中用到什么方法,熟悉下,也就是把api熟悉了,知道它是干嘛用的,
其实刮刮卡和橡皮擦的功能很像,我之前博客也写过关于android涂鸦方面的,如果那个看懂了,刮刮卡就很容易看的懂,我还是先写一个简单的涂鸦功能,
package com.simple;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Path;import android.graphics.Rect;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;/** * Created by admin on 2017/5/3. */public class ScratchCardView extends View { private int width; private int height; private String text = "猜猜她是谁"; private Paint paint; private Path path; private float downX,downY; private float tempX,tempY; public ScratchCardView(Context context) { this(context,null); } public ScratchCardView(Context context, AttributeSet attrs) { this(context, attrs,0); } public ScratchCardView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initPaint(); } private void initPaint() { paint = new Paint(); paint.setAntiAlias(true); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(2); paint.setTextSize(24); path = new Path(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); width = w; height = h; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawPath(path,paint); } private void drawText(Canvas canvas) { Rect rect = new Rect(); paint.getTextBounds(text, 0, text.length(), rect); int textWidth = rect.width(); int textHeight = rect.height(); float x = width/2-textWidth/2; float y = height/2+textHeight/2; paint.setColor(Color.parseColor("#9370DB")); canvas.drawText(text,x,y,paint); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: downX = event.getX(); downY = event.getY(); path.moveTo(downX,downY); invalidate(); tempX = downX; tempY = downY; break; case MotionEvent.ACTION_MOVE: float moveX = event.getX(); float moveY = event.getY(); path.quadTo(tempX,tempY,moveX,moveY); invalidate(); tempX = moveX; tempY = moveY; break; } return true; }}布局文件:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" > <com.simple.ScratchCardView android:layout_width="540dp" android:layout_height="300dp" android:layout_centerInParent="true" android:background="@drawable/bg" ></com.simple.ScratchCardView></RelativeLayout>效果图:
这个就是刮刮卡效果中的擦除功能,只是你给paint设置的颜色不同而已,
比如如何创建一个可绘制的空的画布canvas呢?
上面我们是在系统的canvas上去绘制一些文字的,但是要在自己创建的画布上绘制东西,怎么创建?其实很简单
myBitmap = Bitmap.createBitmap(700,400, Bitmap.Config.ARGB_8888);
myCanvas = new Canvas(myBitmap);
这就二行代码就可以了,然后通过系统的canvas,把这个mBitmap绘制上去就ok,比如怎么把几张图合并成一张图,就这么这么干了,下面四张图是我叫美工切的:
然后通过代码把这四张图合并成一张图入下:
package com.simple;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.Path;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;/** * Created by admin on 2017/5/3. */public class ScratchCardView extends View { private static final String TAG ="ScratchCardView" ; private int width; private int height; private String text = "猜猜她是谁"; private Paint paint; private Path path; private float downX,downY; private float tempX,tempY; private Canvas myCanvas; private Bitmap myBitmap; private Bitmap bitmapa; private Bitmap bitmapb; private Bitmap bitmapc; private Bitmap bitmapd; public ScratchCardView(Context context) { this(context,null); } public ScratchCardView(Context context, AttributeSet attrs) { this(context, attrs,0); } public ScratchCardView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initBitmap(); initPaint(); } private void initBitmap() { bitmapa = BitmapFactory.decodeResource(getResources(),R.drawable.a); bitmapb = BitmapFactory.decodeResource(getResources(),R.drawable.b); bitmapc = BitmapFactory.decodeResource(getResources(),R.drawable.c); bitmapd = BitmapFactory.decodeResource(getResources(),R.drawable.d); } private void initPaint() { paint = new Paint(); paint.setAntiAlias(true); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(2); paint.setTextSize(24); paint.setDither(true); path = new Path(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); width = w; height = h; myBitmap = Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888); myCanvas = new Canvas(myBitmap); } @Override protected void onDraw(Canvas canvas) { drawBitmap(); drawPath(); canvas.drawBitmap(myBitmap,0,0,null); super.onDraw(canvas); } private void drawPath() { myCanvas.drawPath(path,paint); } private void drawBitmap() { myCanvas.drawBitmap(bitmapa,0,0,null); myCanvas.drawBitmap(bitmapb,bitmapa.getWidth(),0,null); myCanvas.drawBitmap(bitmapc,0,bitmapa.getHeight(),null); myCanvas.drawBitmap(bitmapd,bitmapc.getWidth(),bitmapb.getHeight(),null); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: downX = event.getX(); downY = event.getY(); path.moveTo(downX,downY); invalidate(); tempX = downX; tempY = downY; break; case MotionEvent.ACTION_MOVE: float moveX = event.getX(); float moveY = event.getY(); path.quadTo(tempX,tempY,moveX,moveY); invalidate(); tempX = moveX; tempY = moveY; break; } return true; }}布局文件:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" > <com.simple.ScratchCardView android:layout_width="450dp" android:layout_height="360dp" android:layout_centerInParent="true" ></com.simple.ScratchCardView></RelativeLayout>我们看到布局文件中没有什么背景图片了,说明这是合并成的:
合并的原理其实很简单:
如果做过tv端的,对倒影会有点影响,其实就是根据这个原理做的,这也是拼图小游戏中的一个小功能。还有是不是类似明星给你在衣服上签名一样.
现在我们更进一步就是怎么在一张被盖住的图片上进行擦除,比如底层是一张图片,这图片上层有一层背景色,然后把上层的背景色擦除就可以看到下层的美女了,激动吧!
package com.simple;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Path;import android.graphics.PorterDuff;import android.graphics.PorterDuffXfermode;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;/** * Created by admin on 2017/5/3. */public class ScratchCardView extends View { private static final String TAG ="ScratchCardView" ; private int width; private int height; private String text = "猜猜她是谁"; private Paint paint; private Path path; private float downX,downY; private float tempX,tempY; private Canvas myCanvas; private Bitmap myBitmap; private Bitmap bitmapa; private Bitmap bitmapb; private Bitmap bitmapc; private Bitmap bitmapd; private Bitmap bitmap; public ScratchCardView(Context context) { this(context,null); } public ScratchCardView(Context context, AttributeSet attrs) { this(context, attrs,0); } public ScratchCardView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initBitmap(); initPaint(); } private void initBitmap() { bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.bg); bitmapa = BitmapFactory.decodeResource(getResources(),R.drawable.a); bitmapb = BitmapFactory.decodeResource(getResources(),R.drawable.b); bitmapc = BitmapFactory.decodeResource(getResources(),R.drawable.c); bitmapd = BitmapFactory.decodeResource(getResources(),R.drawable.d); } private void initPaint() { paint = new Paint(); paint.setAntiAlias(true); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(20); paint.setTextSize(24); paint.setDither(true); path = new Path(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); width = w; height = h; myBitmap = Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888); myCanvas = new Canvas(myBitmap); myCanvas.drawColor(Color.GREEN); } @Override protected void onDraw(Canvas canvas) { canvas.drawBitmap(bitmap,0,0,null);//底层图 drawPath();//这个path是绘制在myvanvas画布上的 canvas.drawBitmap(myBitmap,0,0,null); super.onDraw(canvas); } private void drawPath() { paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); myCanvas.drawPath(path,paint); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: downX = event.getX(); downY = event.getY(); path.moveTo(downX,downY); invalidate(); tempX = downX; tempY = downY; break; case MotionEvent.ACTION_MOVE: float moveX = event.getX(); float moveY = event.getY(); path.quadTo(tempX,tempY,moveX,moveY); invalidate(); tempX = moveX; tempY = moveY; break; } return true; }}效果图:
这看起来是不是离呱呱卡效果近了,其实完全可以做一个最简单的刮刮卡,就是把文字和低层图片放在一起,
我现在的底图是:
上面的代码一点都没动,然后效果是这样的:
这样做很low,而且实际效果也不好,但却是一种实现方案.能实现这个效果最关键的一点是paint中的一个方法:
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
这是设置了paint的图形混合模式,这个PorterDuff.Mode的类中有很多个变量,大概十几种吧,具体每个什么意思,最好是自己写demo去体会,光记住是没用的.
DST_OUT:只在源图像和目标图像不相交的地方绘制目标图像,在相交的地方根据源图像的alpha进行过滤,源图像完全不透明则完全过滤,完全透明则不过滤
我们这个paint画笔是作用于Path上的,path是我们要绘制的目标图像,下面的底图是源图像,
在这里我画个图更好理解了:
这样刮刮卡我们只要把图片去掉,换成绘制的文字就ok了,
整个代码如下:
package com.simple;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Path;import android.graphics.PorterDuff;import android.graphics.PorterDuffXfermode;import android.graphics.Rect;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;/** * Created by admin on 2017/5/3. */public class ScratchCardView extends View { private static final String TAG ="ScratchCardView" ; private int width; private int height; private String text = "苍老师晚上约你"; private Paint textPaint; private Paint paint; private Path path; private float downX,downY; private float tempX,tempY; private Canvas myCanvas; private Bitmap myBitmap; public ScratchCardView(Context context) { this(context,null); } public ScratchCardView(Context context, AttributeSet attrs) { this(context, attrs,0); } public ScratchCardView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initPaint(); } private void initPaint() { paint = new Paint(); paint.setAntiAlias(true); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(6); paint.setTextSize(24); paint.setDither(true); textPaint = new Paint(); textPaint.setAntiAlias(true); textPaint.setStyle(Paint.Style.FILL); textPaint.setStrokeWidth(20); textPaint.setTextSize(24); textPaint.setDither(true); textPaint.setColor(Color.BLACK); path = new Path(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); width = w; height = h; myBitmap = Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888); myCanvas = new Canvas(myBitmap); myCanvas.drawColor(Color.GREEN); } @Override protected void onDraw(Canvas canvas) {// canvas.drawBitmap(bitmap,0,0,null);//底层图 drawText(canvas); drawPath();//这个path是绘制在myvanvas画布上的 canvas.drawBitmap(myBitmap,0,0,null); super.onDraw(canvas); } private void drawText(Canvas canvas) { Rect rect = new Rect(); textPaint.getTextBounds(text, 0, text.length(), rect); int textWidth = rect.width(); int textHeight = rect.height(); float x = width/2-textWidth/2; float y = height/2+textHeight/2; canvas.drawText(text,x,y,textPaint); } private void drawPath() { paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); myCanvas.drawPath(path,paint); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: downX = event.getX(); downY = event.getY(); path.moveTo(downX,downY); invalidate(); tempX = downX; tempY = downY; break; case MotionEvent.ACTION_MOVE: float moveX = event.getX(); float moveY = event.getY(); path.quadTo(tempX,tempY,moveX,moveY); invalidate(); tempX = moveX; tempY = moveY; break; } return true; }}效果:
github:https://github.com/zhouguizhi/scratchcard
- Android 自定义View 实现刮刮卡效果
- android 自定义view实现刮刮卡效果
- 自定义View实现刮刮卡效果
- Android自定义View-刮刮卡效果
- android自定义view实现progressbar的效果
- Android 自定义view实现水波纹效果
- Android:自定义View实现水波进度效果
- android 自定义view实现水波纹效果
- Android 自定义view实现水波纹效果
- android自定义view实现5.0 Ripple效果
- Android 自定义view实现水波纹效果
- android自定义view实现公章效果
- Android自定义View实现刮刮乐效果
- Android 自定义Animation实现View摇摆效果
- Android:自定义view 实现雷达扫描效果
- Android自定义View实现开关效果
- Android自定义View实现时钟效果ClockView
- Android自定义View实现八卦图效果
- HDU5973(威佐夫博弈+Java大数)
- mongodb[零]准备数据,方便测试
- 应用图标数字
- 安装zookeeper
- qt信号关联
- android 自定义view实现刮刮卡效果
- DTLS编写样例一coap协议
- 三个水杯 搜索题 bfs
- 解决ubuntu下面firefox安装银联插件的问题
- android音视频系列操作,录制,压缩
- H5万能选择器:iosselect
- 写高质量OC代码52建议总结:31.在dealloc方法中只释放引用并解除监听
- “惊群”,看看nginx是怎么解决它的
- 大数据查询网址(整理)