首页 > 系统 > Android > 正文

Android实现遮罩层(蒙板)效果

2019-10-21 21:36:49
字体:
来源:转载
供稿:网友

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

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

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;  @Override protected 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设置之后再设置setProgress maskProgress.setProgress(175); }  Handler handler = new Handler(){  @Override public 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() {  @Override public 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" >   <RelativeLayout    android:layout_width="match_parent"    android:layout_height="0dp"    android:layout_weight="1"    android:orientation="vertical" >     <com.gplus.mask.widget.MaskProgress      android: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>   <RelativeLayout    android: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;//s   private final static int REFRESH = 10;//mills  private 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(); }  @Override protected 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; }  @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(widthMeasureSpec, heightMeasureSpec); }  @Override protected 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{  @Override public 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,遮罩层,蒙板

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持VEVB武林网。


注:相关教程知识阅读请移步到Android开发频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表