今天重点内容是我们学习自己定义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

自己定义View学习之12/7(进度条之混合模式)的更多相关文章

  1. Android 自己定义View学习(2)

    上一篇学习了基本使用方法,今天学一下略微复杂一点的.先看一下效果图 为了完毕上面的效果还是要用到上一期开头的四步 1,属性应该要有颜色,要有速度 <?xml version="1.0& ...

  2. 我的Android进阶之旅------>Android自定义View实现带数字的进度条(NumberProgressBar)

    今天在Github上面看到一个来自于 daimajia所写的关于Android自定义View实现带数字的进度条(NumberProgressBar)的精彩案例,在这里分享给大家一起来学习学习!同时感谢 ...

  3. android学习笔记20——ProgressDialog进度条对话框

    ProgressDialog==>进度条对话框 ProgressDialog本身就代表一个进度条对话框,程序只需要创建ProgressDialog实例,并将其显示出来就是一个进度条对话框:开发者 ...

  4. [Xcode 实际操作]四、常用控件-(12)环形进度条控件的使用

    目录:[Swift]Xcode实际操作 本文将演示环形进度条控件的使用. 在项目导航区,打开视图控制器的代码文件[ViewController.swift] import UIKit class Vi ...

  5. ftk学习记录(一个进度条文章)

    [ 声明:版权全部,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 首先.在開始今天的文章之前.我们还是给朋友们展示一下前面一段代码的执行效果.效果例如以下, w ...

  6. Android学习笔记_76_Android ProgressBar 进度条

    android 进度条的样式  例1:(默认样式(中等圆形))Xml代码 <ProgressBar      android:id="@+id/progressBar1"   ...

  7. Android View 之进度条+拖动条+星级评论条....

    PS:将来的你会感谢现在奋斗的自己.... 学习内容: 1.进度条 2.拖动条 3.星级评论条 1.进度条...       进图条这东西想必大家是很熟悉的...为了使用户不会觉得应用程序死掉了,因此 ...

  8. Android多种样式的进度条

    原创 2016年04月26日 16:46:35 标签: android / clip / 进度条 / 8473 编辑 删除 ---- The mark of the immature man is t ...

  9. 进度条(ProgressBar)的功能与用法

    进度条也是UI界面中一种非常实用的组件,通常用于向用户显示某个耗时操作完成的的百分比.进度条可以动态的显示进度,因此避免长时间的执行某个耗时的操作,让用户感觉程序失去了响应,从而更好的提高用户界面的友 ...

随机推荐

  1. JQuery缓冲加载图片插件lazyload.js的使用方法

    lazyload.js是一个基于JQuery的插件,可以用来缓冲加载图片.如果一个网页很长并且有很多图片的话,下载图片就需要很多时间,那么就会影响整个网页的加载速度,而这款延迟加载插件,会通过你的滚动 ...

  2. DFA 算法实现关键词匹配

    起因: 从网页中爬去的页面.须要推断是否跟预设的关键词匹配(是否包括预设的关键词),并返回全部匹配到的关键词 . 眼下pypi 上两个实现 ahocorasick https://pypi.pytho ...

  3. jquery制作一个简单的轮播

    效果图: 演示地址: http://ae6623.cn/demo/slider/index.html 思路: 利用css的定位属性 left 进行调整图片的显示,每次点击上一页下一页按钮的时候,-图片 ...

  4. YII插件

    dropDownList: Yii中可以采用CHtml类来实现,也可以用CActiveForm来实现.一.用CHtml来实现.VIEW中实现: <?php echo CHtml::dropDow ...

  5. 关于oracle redo log buffer 你所不知道的东西

    [ora11@lixora ~]$ sqlplus / as sysdba SQL*Plus: Release 11.2.0.1.0 Production on Wed Oct 8 09:57:50 ...

  6. NYOJ 113 字符串替换(C++STL解法)

    字符串替换 时间限制:3000 ms  |            内存限制:65535 KB 难度:2 描写叙述 编写一个程序实现将字符串中的全部"you"替换成"we& ...

  7. ZH奶酪:Ubuntu客户端通过SSH方式远程登录Ubuntu服务器

    1.概述 传统的远程登录(telnet,rlogin)时不安全的,他们在网络上用明文传输口令和数据,SSH则是安全的,openssh提供两种级别的验证方式. (1)基于口令的安全验证:知道服务器的帐号 ...

  8. head 命令(转)

    原文:http://www.cnblogs.com/peida/archive/2012/11/06/2756278.html head 与 tail 就像它的名字一样的浅显易懂,它是用来显示开头或结 ...

  9. C++AMP介绍(一)

    C++AMP介绍(一) 最后更新日期:2014-05-02 阅读前提: 环境:Windows 8.1 64bit英文版,Visual Studio 2013 Professional Update1英 ...

  10. webpack配置上线地址

    webpack配置上线地址主要使用output配置项下的publicPath. webpack.config.js配置文件为: var htmlWebpackPlugin = require('htm ...