自己定义View学习之12/7(进度条之混合模式)
2017-08-11 16:29
204 查看
今天重点内容是我们学习自己定义view里面的混合模式。事实上我们的画布就跟photoshop一样。是个图层关系,一层盖着一层。这样就导致有非常多种覆盖模式,这就是我们今天的主题。“混合模式”。
好,如今我们来看下这个模式的说明图:canvas原有的图片 能够理解为背景 就是dst
新画上去的图片 能够理解为前景 就是src
从上面我们能够看到PorterDuff.Mode为枚举类,一共同拥有16个枚举值:
1.PorterDuff.Mode.CLEAR
所绘制不会提交到画布上。
2.PorterDuff.Mode.SRC
显示上层绘制图片
3.PorterDuff.Mode.DST
显示下层绘制图片
4.PorterDuff.Mode.SRC_OVER
正常绘制显示,上下层绘制叠盖。
5.PorterDuff.Mode.DST_OVER
上下层都显示。
下层居上显示。
6.PorterDuff.Mode.SRC_IN
取两层绘制交集。显示上层。
7.PorterDuff.Mode.DST_IN
取两层绘制交集。
显示下层。
8.PorterDuff.Mode.SRC_OUT
取上层绘制非交集部分。
9.PorterDuff.Mode.DST_OUT
取下层绘制非交集部分。
10.PorterDuff.Mode.SRC_ATOP
取下层非交集部分与上层交集部分
11.PorterDuff.Mode.DST_ATOP
取上层非交集部分与下层交集部分
12.PorterDuff.Mode.XOR
异或:去除两图层交集部分
13.PorterDuff.Mode.DARKEN
取两图层所有区域。交集部分颜色加深
14.PorterDuff.Mode.LIGHTEN
取两图层所有,点亮交集部分颜色
15.PorterDuff.Mode.MULTIPLY
取两图层交集部分叠加后颜色
16.PorterDuff.Mode.SCREEN
取两图层所有区域,交集部分变为透明色
我决定以以下2个效果来作为联系和实现以下请看效果。1、一个是进度条转完以波纹动画的方式显示实物。2、是一款进度条,当进度覆盖文字的时候,覆盖到哪里,哪里的文字的一部分就显示成白色:
第一种效果:
接下来我们就来看这个gif的代码,事实上非常easy主要实现方式呢就是圆形载入条是以Canvas画扇形的方式画出,仅仅是圆心空心而已。载入完之后呢外面的大圆就是Canvas以画圆的方式画出。仅仅是混合模式是CLEAR也是清除的意思。占用大小刚好就是载入条的大小,然后小圆的大小也是载入条的大小,刚好覆盖在大圆上面。
接着就启动循环载入知道所有显示。大圆扩散显示(由于是CLEAR模式所以,覆盖到的地方全是透明的)。小圆缩小显示:
package com.wyw.lodingdemo; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.PorterDuff.Mode; import android.graphics.PorterDuffXfermode; import android.graphics.RectF; import android.os.Handler; import android.util.AttributeSet; import android.view.View; public class LoadingView extends View { public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } public LoadingView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public LoadingView(Context context) { super(context); init(); } private Paint paint; /** 设置矩阵的坐标点 */ private RectF rectF; /** 当前进度 */ private int current = 0; /** 横向中心X轴 */ private float centerX = 0; /** 竖向中心Y轴 */ private float centerY = 0; /** 园半径 */ private float circleRadius; /** 是否完毕 */ private boolean isComplete = false; /** 完毕之后显示的图片 */ private Bitmap bitmap; private Matrix matrix; // 缩放比率 private float widthRate; private float heightRate; /** bitmap画笔 */ private Paint Bpaint; private int size; /** 白屏显示的画布 */ private Canvas mCanvas; /** 消失画笔(大圆) */ private Paint Gpaint_big; /** 消失画笔(小圆) */ private Paint Gpaint_small; private Bitmap fgBitmap; private Bitmap frontBitmap; /** 消失的园半径 */ private float gone_circleRadius_big = 0; /** 消失的园半径 */ private float gone_circleRadius_small = 0; @SuppressLint("DrawAllocation") @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { centerX = (right - left) / 2; centerY = (bottom - top) / 2; rectF = new RectF(centerX - circleRadius, centerY - circleRadius, centerX + circleRadius, centerY + circleRadius);// 弧形 super.onLayout(changed, left, top, right, bottom); } private void init() { size = Math.min(getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels); paint = new Paint();// 布局xml里面引用 paint.setColor(Color.parseColor("#fe871a")); paint.setAntiAlias(true);// 设置抗锯齿 paint.setStrokeWidth(getInt(1f, size)); paint.setStyle(Style.STROKE);// 设置圆心掏空 // 设置画笔形状 圆形,须要先设置画笔样式 SYROKE 或者 FILL_AND_STROKE paint.setStrokeCap(Paint.Cap.ROUND); circleRadius = getInt(7f, size); } /** 获取传入颜色,高度。宽度的Bitmap */ public Bitmap CreateBitmap(int color, int width, int height) { int[] rgb = new int[width * height]; for (int i = 0; i < rgb.length; i++) { rgb[i] = color; } return Bitmap.createBitmap(rgb, width, height, Config.ARGB_4444); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (!isComplete) {// 没完毕 canvas.drawArc(rectF, 0, current, false, paint); } else {// 已完毕 if (bitmap != null && isComplete) { if (matrix == null) { initParameters(); matrix.reset(); matrix.postScale(widthRate, heightRate); // 绘制白色背景图 mCanvas.drawBitmap(frontBitmap, 0, 0, null); } canvas.drawBitmap(bitmap, matrix, Bpaint); // 绘制前景 canvas.drawBitmap(fgBitmap, 0, 0, null); // mCanvas.drawArc(left, top, right, bottom, startAngle, // sweepAngle, useCenter, Gpaint); mCanvas.drawCircle(centerX, centerY, gone_circleRadius_big, Gpaint_big); // 绘制前景 canvas.drawCircle(centerX, centerY, gone_circleRadius_small, Gpaint_small); if (gone_circleRadius_big < centerX * 1.5f || gone_circleRadius_small > 0) { handler.post(drawRunnable); } } } } private Handler handler = new Handler(); private Runnable drawRunnable = new Runnable() { @Override public void run() { gone_circleRadius_big += centerX * 1.5f / 50f; gone_circleRadius_small -= circleRadius / 50f; invalidate(); } }; /** 初始化matrix */ private void initParameters() { matrix = new Matrix(); Bpaint = new Paint(); Bpaint.setAntiAlias(true); gone_circleRadius_big = circleRadius; gone_circleRadius_small = circleRadius; Gpaint_small = new Paint(); // 防锯齿 Gpaint_small.setAntiAlias(true); Gpaint_small.setColor(Color.BLACK); Gpaint_big = new Paint(); // 防锯齿 Gpaint_big.setAntiAlias(true); // 设置混合模式为DST_IN Gpaint_big.setXfermode(new PorterDuffXfermode(Mode.CLEAR)); // 生成前景图Bitmap 这里拿的宽高要在onDraw里面才干拿到哦。 fgBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_4444); frontBitmap = CreateBitmap(Color.BLACK, getWidth(), getHeight()); mCanvas = new Canvas(fgBitmap); if (bitmap != null) { float iw = bitmap.getWidth(); float ih = bitmap.getHeight(); float width = this.getWidth(); float height = this.getHeight(); // 初始放缩比率 widthRate = width / iw; heightRate = height / ih; } } /** 是否完毕 */ public void setComplete(boolean isComplete, Bitmap bitmap) { this.isComplete = isComplete; this.bitmap = bitmap; invalidate(); } /** * 设置当前进度 * * @param current * 进度 */ public void setCurrentProgress(float current, float max) { this.current = (int) ((360f / max) * current); invalidate(); } /** * 获取占屏幕的百分比 * * @param value * 使用size的百分比 * @param size * 最大值 * @return 依据百分算出的大小 */ private int getInt(float value, int size) { try { return Math.round(value * (float) size / 100f); } catch (Exception ignore) { return 0; } } }
另外一种效果:
好,我们来看下代码,我这里的默认模式是SCREEN。SCREEN呢就是覆盖的时候覆盖部分会是白色。这里我的文字是SCREEN模式。所以呢当我的进度条覆盖到文字的时候。覆盖的部分就会变成白色。
这里呢我把所有的模式和不同的颜色都加上了,详细怎么理解怎么定义能够下载demo亲自去尝试,去切换看看。那些混合模式究竟都是哪些效果。
package com.wyw.loadingdemob; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.FontMetricsInt; import android.graphics.PorterDuffXfermode; import android.graphics.Paint.Style; import android.graphics.PorterDuff.Mode; import android.graphics.RectF; import android.util.AttributeSet; import android.view.View; public class LoadingViewb extends View { public LoadingViewb(Context context) { super(context); init(); } public LoadingViewb(Context context, AttributeSet attrs) { super(context, attrs); init(); } public LoadingViewb(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } // 背景圆角矩形画笔 private Paint paint_bg; // 背景圆角矩形 private RectF rect_bg; // 字体画笔 private Paint paint_txt; // 前景圆角 private Paint paint_front; // 前景圆角矩形 private RectF rect_front; // 结束位置 private int endX; // 起始位置 private int startX; // 当前位置 private int currentX; // 竖向中间位置 private int centerY; // 横向中间位置 private int centerX; // 要显示的文字 private String text = "0%"; // 文字竖向居中的数值 private int txt_center_y = 0; @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { //開始位置(由于是圆角所以会突出一部分所以開始位置得加上屏幕的百分之5) startX = 0 + getInt(5f); //结束位置(由于是圆角所以会突出一部分所以開始位置得减去屏幕的百分之5) endX = right - left - getInt(5f); //拿到y轴中心点 centerY = (bottom - top) / 2; //拿到x轴中心点 centerX = (right - left) / 2; super.onLayout(changed, left, top, right, bottom); } private void init() { paint_bg = new Paint(); paint_bg.setColor(Color.parseColor("#fe871a")); // 设置抗锯齿 paint_bg.setAntiAlias(true); paint_bg.setStrokeWidth(getInt(1f)); // 设置圆心掏空 paint_bg.setStyle(Style.STROKE); // 设置画笔形状 圆形。须要先设置画笔样式 STROKE 或者 FILL_AND_STROKE paint_bg.setStrokeCap(Paint.Cap.ROUND); paint_txt = new Paint(); paint_txt.setColor(Color.parseColor("#fe871a")); paint_txt.setTextSize(getInt(5f)); // 设置抗锯齿 paint_txt.setAntiAlias(true); // 设置混合模式为SCREEN paint_txt.setXfermode(new PorterDuffXfermode(Mode.SCREEN)); // 以下这行是实现字体水平居中 paint_txt.setTextAlign(Paint.Align.CENTER); paint_front = new Paint(); paint_front.setColor(Color.parseColor("#fe871a")); // 设置抗锯齿 paint_front.setAntiAlias(true); // 设置混合模式为SRC_ATOP paint_front.setXfermode(new PorterDuffXfermode(Mode.SRC_ATOP)); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (rect_bg == null) { rect_bg = new RectF(startX, centerY - getInt(5f), endX, centerY + getInt(5f)); rect_front = new RectF(startX, centerY - getInt(5f), currentX, centerY + getInt(5f)); // 实现字体竖向居中 FontMetricsInt fontMetrics = paint_txt.getFontMetricsInt(); txt_center_y = (centerY * 2 - fontMetrics.bottom - fontMetrics.top) / 2; } canvas.drawRoundRect(rect_bg, getInt(10f), getInt(10f), paint_bg); canvas.drawRoundRect(rect_front, getInt(10f), getInt(10f), paint_front); canvas.drawText(text, centerX, txt_center_y, paint_txt); } // 设置当前进度 public void setCurrentProgress(float current, float max) { //由于起点不是0,所以总长度须要减去起点 (endX-startX) currentX = (int) (((float) (endX-startX) / max) * current); text = (int) ((float) currentX / (float) (endX-startX) * 100) + "%"; //由于起点不是0所以须要加上起点的 rect_front.right = currentX+startX; invalidate(); } // 设置字体颜色 public void setTextColor(int color) { paint_txt.setColor(color); //重置数据 currentX = 0; text = "0%"; if (rect_front != null) { rect_front.right = currentX; } invalidate(); } // 设置重叠模式 public void setMode(String mode) { if (mode.equals("clear")) { // 设置混合模式为CLEAR paint_txt.setXfermode(new PorterDuffXfermode(Mode.CLEAR)); } else if (mode.equals("Src")) { // 设置混合模式为SRC paint_txt.setXfermode(new PorterDuffXfermode(Mode.SRC)); } else if (mode.equals("Dst")) { // 设置混合模式为DST paint_txt.setXfermode(new PorterDuffXfermode(Mode.DST)); } else if (mode.equals("srcOver")) { // 设置混合模式为SRC_OVER paint_txt.setXfermode(new PorterDuffXfermode(Mode.SRC_OVER)); } else if (mode.equals("DstOver")) { // 设置混合模式为DST_OVER paint_txt.setXfermode(new PorterDuffXfermode(Mode.DST_OVER)); } else if (mode.equals("SrcIn")) { // 设置混合模式为SRC_IN paint_txt.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); } else if (mode.equals("DstIn")) { // 设置混合模式为DST_IN paint_txt.setXfermode(new PorterDuffXfermode(Mode.DST_IN)); } else if (mode.equals("SrcOut")) { // 设置混合模式为SRC_OUT paint_txt.setXfermode(new PorterDuffXfermode(Mode.SRC_OUT)); } else if (mode.equals("DstOutr")) { // 设置混合模式为DST_OUT paint_txt.setXfermode(new PorterDuffXfermode(Mode.DST_OUT)); } else if (mode.equals("SrcATop")) { // 设置混合模式为SRC_ATOP paint_txt.setXfermode(new PorterDuffXfermode(Mode.SRC_ATOP)); } else if (mode.equals("DstATop")) { // 设置混合模式为DST_ATOP paint_txt.setXfermode(new PorterDuffXfermode(Mode.DST_ATOP)); } else if (mode.equals("Xor")) { // 设置混合模式为XOR paint_txt.setXfermode(new PorterDuffXfermode(Mode.XOR)); } else if (mode.equals("Darken")) { // 设置混合模式为DARKEN paint_txt.setXfermode(new PorterDuffXfermode(Mode.DARKEN)); } else if (mode.equals("Lighten")) { // 设置混合模式为LIGHTEN paint_txt.setXfermode(new PorterDuffXfermode(Mode.LIGHTEN)); } else if (mode.equals("Multiply")) { // 设置混合模式为MULTIPLY paint_txt.setXfermode(new PorterDuffXfermode(Mode.MULTIPLY)); } else if (mode.equals("Screen")) { // 设置混合模式为SCREEN paint_txt.setXfermode(new PorterDuffXfermode(Mode.SCREEN)); } //重置数据 currentX = 0; text = "0%"; if (rect_front != null) { rect_front.right = currentX; } invalidate(); } /** * 获取占屏幕的百分比 * * @param value * 使用size的百分比 * @param size * 最大值 * @return 依据百分算出的大小 */ private int getInt(float value) { int size = Math.min(getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels); try { return Math.round(value * (float) size / 100f); } catch (Exception ignore) { return 0; } } }
本篇博客就到这里,假设有有疑问的欢迎留言讨论。同一时候希望大家多多关注我的博客。多多支持我。
尊重原创转载请注明:(http://blog.csdn.net/u013895206) !
以下是地址传送门:
第一种效果下载地址:http://download.csdn.net/detail/u013895206/9479008
另外一种效果下载地址:http://download.csdn.net/detail/u013895206/9479013
相关文章推荐
- Android学习个人笔记1-Layout界面布局-xml,java混合模式-自定义view
- Android 自己定义View学习(2)
- Esp8266学习之旅⑦ 了解softAP热点配网模式原理,仿“机智云”定义自己的热点配网模式协议。(带Demo)
- hadoop学习;自己定义Input/OutputFormat;类引用mapreduce.mapper;三种模式
- 自己在项目中的学习总结:利用工厂模式+反射机制+缓存机制,实现动态创建不同的数据层对象接口
- Android自己定义ViewGroup打造各种风格的SlidingMenu
- android学习七(创建自己定义控件)
- AlertDialog自己定义View的使用方法+怎样改变弹出框的大小
- andorid自己定义ViewPager之——子ViewPager滑到边缘后直接滑动父ViewPager
- Android自己定义组件系列【4】——自己定义ViewGroup实现双側滑动
- 自己定义ViewGroup控件(一)----->流式布局进阶(一)
- 设计模式学习日志(12)-Flyweight享元(结构型模式)
- 自己定义的View曲线图 多点触控 canvas
- 自定义View学习之12/4(仿IOS联系人列表)
- Qt Model/View 学习笔记 (二)——Qt Model/View模式举例
- 【学习笔记javascript设计模式与开发实践(享元模式)----12】
- MVVM设计模式相关--Silverlight商业应用程序开发学习笔记(12)
- JS学习之写一个自己定义的类
- 随记12——我的简单自定义View值之简单色彩斑斓的进度条和简单的SeekBar
- 设计模式学习-每日一记(12.轻量模式)