软件世界网 购物 网址 三丰软件 | 小说 美女秀 图库大全 游戏 笑话 | 下载 开发知识库 新闻 开发 图片素材
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
移动开发 架构设计 编程语言 Web前端 互联网
开发杂谈 系统运维 研发管理 数据库 云计算 Android开发资料
  软件世界网 -> 移动开发 -> 自定义View学习之12/7(进度条之混合模式) -> 正文阅读

[移动开发]自定义View学习之12/7(进度条之混合模式)



今天重点内容是我们学习自定义view里面的混合模式,其实我们的画布就跟photoshop一样,是个图层关系,一层盖着一层,这样就导致有很多种覆盖模式,这就是我们今天的主题,“混合模式”。



好,现在我们来看下这个模式的说明图:
[img]http://img.blog.csdn.net/20160401153521214
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、是一款进度条,当进度覆盖文字的时候,覆盖到哪里,哪里的文字的一部分就显示成白色:

第一种效果:


[img]http://img.blog.csdn.net/20160401151729582

接下来我们就来看这个gif的代码,其实很简单主要实现方式呢就是圆形加载条是以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;
        }
    }
}

第二种效果:


[img]http://img.blog.csdn.net/20160401151741832[img]http://img.blog.csdn.net/20160401155417143

好,我们来看下代码,我这里的默认模式是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


......显示全文...
    点击查看全文


上一篇文章      下一篇文章      查看所有文章
2016-04-02 20:51:48  
移动开发 最新文章
深入了解android中的消息机制Handler
Android
Libgdx之BitmapFont字体
AndroidApp发布到应用市场的流程
Android开发找工作之前先看看这些知识点吧
View的事件分发机制解析
简单介绍了解白鹭引擎Egret
Cocos2d
android获取本地图片(二)
动画特效七:碰撞动画
360图书馆 软件开发资料 文字转语音 购物精选 软件下载 美食菜谱 新闻资讯 电影视频 小游戏 Chinese Culture 股票 租车
生肖星座 三丰软件 视频 开发 短信 中国文化 网文精选 搜图网 美图 阅读网 多播 租车 短信 看图 日历 万年历 2018年1日历
2018-1-16 21:26:13
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  软件世界网 --