Android的遮罩层(蒙板)效果 setXfermode

2023-10-17 21:20

本文主要是介绍Android的遮罩层(蒙板)效果 setXfermode,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

       Android的遮罩效果就是把一张图片盖在另一张图片的上面,通过控制任意一张图片的显示百分比实现遮罩效果。下面我使用两张一样的图片来实现一个类似于 Android 的progressbar 的填充效果。使用遮罩效果来实现progressbar的效果的好处是,我们可以只改变图片就可以更改progress的进度填充效果,并且我们可以实现任意形式的填充效果,就比如横竖填充,扇形逆/顺时填充针等。

      网上有很多介绍Android 遮罩效果的列子,但是都是横竖的填充效果,下面我来实现一个扇形填充效果,如下图:


    我现在要做的就是用这两种图去实现一个progressbar效果.好了原来不解释了直接上代码吧:

    一.Activity代码
package com.gplus.mask.test;import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;import com.gplus.mask.widget.MaskProgress;
import com.gplus.mask.widget.MaskProgress.AnimateListener;public class GplusMask extends Activity{float progressFromCode  = 150;float progressFromXml  = 150;MaskProgress maskProgressFromeCode;MaskProgress maskProgressFromeXml;private boolean isAnimateFinish = true;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);RelativeLayout parent = (RelativeLayout) findViewById(R.id.parent);maskProgressFromeCode = new MaskProgress(this);initialProgress(maskProgressFromeCode);RelativeLayout.LayoutParams rp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);parent.addView(maskProgressFromeCode, rp);maskProgressFromeCode.initial();maskProgressFromeXml = (MaskProgress) findViewById(R.id.maskView);}private void initialProgress(MaskProgress maskProgress){//设置最大值maskProgress.setMax(300);//初始填充量为一半//初始化填充progress时的填充动画时间,越大越慢maskProgress.setTotaltime(3);//progress背景图maskProgress.setBackgroundResId(R.drawable.untitled1);//progress填充内容图片maskProgress.setContentResId(R.drawable.untitled2);//Progress开始的填充的位置360和0为圆最右、90圆最下、180为圆最右、270为圆最上(顺时针方向为正)maskProgress.setStartAngle(0);maskProgress.setAnimateListener(animateListener);//初始化时必须在setMax设置之后再设置setProgressmaskProgress.setProgress(175);}Handler handler = new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);float newProgress = maskProgressFromeCode.getProgress() - 4;if(newProgress <= 0){//随机绘制效果float max = (float) (Math.random() * 900 + 1000);float progress = (float) (max * Math.random());maskProgressFromeCode.setMax(max);maskProgressFromeCode.setProgress(progress);maskProgressFromeCode.setTotaltime((float) (Math.random()*10));maskProgressFromeCode.setStartAngle((float) (Math.random()*360));maskProgressFromeCode.initial();return;}maskProgressFromeCode.setProgress(newProgress);maskProgressFromeCode.updateProgress();handler.sendEmptyMessageDelayed(0, 50);}};AnimateListener animateListener = new AnimateListener() {@Overridepublic void onAnimateFinish() {handler.sendEmptyMessageDelayed(0, 500);}};
}
   二.activity布局文件main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res/com.gplus.mask.test"android:layout_width="fill_parent"android:layout_height="fill_parent"android:orientation="vertical" ><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:orientation="vertical" ><com.gplus.mask.widget.MaskProgressandroid:id="@+id/maskView"android:layout_width="200dp"android:layout_height="200dp"app:anim_time="20"app:max="180"app:progress="135"app:progress_background="@drawable/untitled1"app:progress_content="@drawable/untitled2"app:start_angle="0" android:layout_centerInParent="true"/></RelativeLayout><RelativeLayoutandroid:id="@+id/parent"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:orientation="vertical" /></LinearLayout>
    三.View的实现效果MaskProgress.java
package com.gplus.mask.widget;import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.graphics.PorterDuff.Mode;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.View;/*** @author huangxin*/
public class MaskProgress extends View{/** 每次setProgress时进度条前进或者回退到所设的值时都会有一段动画。* 该接口用于监听动画的完成,你应该设置监听器监听到动画完成后,才再一次调用 * setProgress方法* */public static interface AnimateListener{public void onAnimateFinish();}private float totalTime = 5;//sprivate final static int REFRESH = 10;//millsprivate float step;private float max = 360;private float currentProgress;private float destProgress = 0;private float realProgress = 0;private float oldRealProgress = 0;private int backgroundResId;private int contentResId;private float startAngle = 270;private Bitmap bg;private Bitmap ct;private Paint paint;private int radius;private int beginX;private int beginY;private int centerX;private int centerY;private RectF rectF;private PorterDuffXfermode srcIn;private double rate;boolean initialing = false;AnimateListener animateListener;public MaskProgress(Context context) {this(context, null);}public MaskProgress(Context context, AttributeSet attrs) {this(context, attrs, R.attr.maskProgressStyle);}public MaskProgress(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);init(context, attrs, defStyle);}public void setAnimateListener(AnimateListener animateListener) {this.animateListener = animateListener;}public void setProgress(float destProgress) {if(destProgress > max)try {throw new Exception("progress can biger than max");} catch (Exception e) {e.printStackTrace();}this.destProgress = destProgress;oldRealProgress = realProgress;realProgress = (float) (destProgress * rate);}public float getProgress(){return destProgress;}public void setTotaltime(float totalTime) {this.totalTime = totalTime;step = 360 / (totalTime * 1000 / REFRESH);}public static int getRefresh() {return REFRESH;}public void setMax(float max) {this.max = max;rate = 360 / max;}public void setStartAngle(float startAngle) {this.startAngle = startAngle;}public void setBackgroundResId(int backgroundResId) {this.backgroundResId = backgroundResId;bg = BitmapFactory.decodeResource(getResources(), backgroundResId);}public void setContentResId(int contentResId) {this.contentResId = contentResId;ct = BitmapFactory.decodeResource(getResources(), contentResId);}public void updateProgress(){invalidate();}/** 初始化,第一次给MaskProgress设值时,从没有填充到,填充到给定的值时* 有一段动画* */public void initial(){initialing = true;new CirculateUpdateThread().start();}public float getMax() {return max;}private void init(Context context, AttributeSet attrs, int defStyle){TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.maskProgressBar, defStyle, 0);if (typedArray != null) {try {setMax(typedArray.getFloat(R.styleable.maskProgressBar_max, max));setProgress(typedArray.getFloat(R.styleable.maskProgressBar_progress, destProgress));setTotaltime(typedArray.getFloat(R.styleable.maskProgressBar_anim_time, totalTime));setStartAngle(typedArray.getFloat(R.styleable.maskProgressBar_start_angle, startAngle));setContentResId(typedArray.getResourceId(R.styleable.maskProgressBar_progress_content, R.drawable.untitled2));setBackgroundResId(typedArray.getResourceId(R.styleable.maskProgressBar_progress_background, R.drawable.untitled1));} finally {typedArray.recycle();}   }paint = new Paint();paint.setDither(true);paint.setAntiAlias(true);rate = 360 / max;currentProgress = 0;realProgress = (float) (destProgress * rate);srcIn = new PorterDuffXfermode(Mode.SRC_IN);step = 360 / (totalTime * 1000 / REFRESH);bg = BitmapFactory.decodeResource(getResources(), backgroundResId);ct = BitmapFactory.decodeResource(getResources(), contentResId);Log.w("init", "max: " + max + "\n" + "destProgress: " + destProgress +"\n"+"totalTime: "+ totalTime+"\n"+"startAngle: "+ startAngle);initialing = true;new CirculateUpdateThread().start();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawBitmap(bg, 0, (getHeight() - bg.getHeight()) / 2, paint);int rc = canvas.saveLayer(0, (getHeight() - bg.getHeight()) / 2, bg.getWidth(), (getHeight() + bg.getHeight()) / 2, null, Canvas.ALL_SAVE_FLAG);paint.setFilterBitmap(false);if(initialing){canvas.drawArc(rectF, startAngle, currentProgress, true, paint);}else{canvas.drawArc(rectF, startAngle, realProgress, true, paint);}paint.setXfermode(srcIn);canvas.drawBitmap(ct, 0, (getHeight() - ct.getHeight()) / 2, paint);paint.setXfermode(null);canvas.restoreToCount(rc);}public int[] getRectPosition(int progress){int[] rect = new int[4]; rect[0] = beginX;rect[1] = beginY;rect[2] = (int)(centerX + radius * Math.cos(progress * Math.PI /180));rect[3] = (int)(centerY + radius * Math.sin(progress * Math.PI /180));Log.w("getRectPosition", "30: " + Math.sin(30 * Math.PI /180));Log.w("getRectPosition", "X: " + rect[2] + "  " + "Y: " + rect[3]);return rect;}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);int tmp = w >= h ? h : w;radius = tmp / 2;beginX = w / 2;beginY = 0;centerX = tmp / 2;centerY = tmp / 2;Bitmap bg_ = resizeBitmap(bg, tmp, tmp);Bitmap ct_ = resizeBitmap(ct, tmp, tmp);rectF = new RectF(0, (getHeight() - bg_.getHeight()) / 2, bg_.getWidth(), (getHeight() + bg_.getHeight()) / 2);bg.recycle();ct.recycle();bg = bg_;ct = ct_;}private Bitmap resizeBitmap(Bitmap src, int w, int h){int width =  src.getWidth();int height = src.getHeight();int scaleWidht = w / width;int scaleHeight = h / height;Matrix matrix = new Matrix();matrix.postScale(scaleWidht, scaleHeight);Bitmap result = Bitmap.createScaledBitmap(src, w, h, true);src = null;return result;}class CirculateUpdateThread extends Thread{@Overridepublic void run() {while(initialing){postInvalidate();if(currentProgress < realProgress){currentProgress += step * rate;if(currentProgress > realProgress)currentProgress = realProgress;}else{				// new Thread(new Runnable() {//// @Override// public void run() {// while (true) {// postInvalidate();// if (currentProgress > 0) {// currentProgress -= step * rate;// } else {// currentProgress = 0;// new CirculateUpdateThread().start();// break;// }// try {// Thread.sleep(REFRESH);// } catch (Exception e) {// e.printStackTrace();// }// }// }// }).start();currentProgress = 0;initialing = false;if(animateListener != null)animateListener.onAnimateFinish();}try{Thread.sleep(REFRESH);}catch(Exception e){e.printStackTrace();}}}} 
}
   四.该Veiw自定义的属性文件attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="maskProgressBar"><attr name="max" format="float" /><attr name="progress" format="float" /><attr name="start_angle" format="float" /><attr name="progress_background" format="reference" /><attr name="progress_content" format="reference" /><attr name="anim_time" format="float" /></declare-styleable><attr name="maskProgressStyle" format="reference" /></resources>
    效果图如下,上面小的是定义xml的,下面大的是从代码中添加的




这篇关于Android的遮罩层(蒙板)效果 setXfermode的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/228005

相关文章

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

防近视护眼台灯什么牌子好?五款防近视效果好的护眼台灯推荐

在家里,灯具是属于离不开的家具,每个大大小小的地方都需要的照亮,所以一盏好灯是必不可少的,每个发挥着作用。而护眼台灯就起了一个保护眼睛,预防近视的作用。可以保护我们在学习,阅读的时候提供一个合适的光线环境,保护我们的眼睛。防近视护眼台灯什么牌子好?那我们怎么选择一个优秀的护眼台灯也是很重要,才能起到最大的护眼效果。下面五款防近视效果好的护眼台灯推荐: 一:六个推荐防近视效果好的护眼台灯的

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使

Android Environment 获取的路径问题

1. 以获取 /System 路径为例 /*** Return root of the "system" partition holding the core Android OS.* Always present and mounted read-only.*/public static @NonNull File getRootDirectory() {return DIR_ANDR

遮罩,在指定元素上进行遮罩

废话不多说,直接上代码: ps:依赖 jquer.js 1.首先,定义一个 Overlay.js  代码如下: /*遮罩 Overlay js 对象*/function Overlay(options){//{targetId:'',viewHtml:'',viewWidth:'',viewHeight:''}try{this.state=false;//遮罩状态 true 激活,f