zoukankan      html  css  js  c++  java
  • 自己定义View学习之12/7(进度条之混合模式)


    今天重点内容是我们学习自己定义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开发学习总结(一)——搭建最新版本的Android开发环境
    数据库服务器编码,数据库编码,数据库表编码,数据库表字段编码
    webservice(二)简单实例
    webservice(一) 概念
    JAVA的StringBuffer类
    Log4J日志配置详解
    如何配置使用 Log4j
    使用MyBatis Generator自动创建代码
    Spring MVC POST中文乱码解决方案
    JSP开发中对jstl的引用方式(标签库引用)
  • 原文地址:https://www.cnblogs.com/claireyuancy/p/7346597.html
Copyright © 2011-2022 走看看