欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2022-06-04 12:19:06
android的遮罩效果就是把一张图片盖在另一张图片的上面,通过控制任意一张图片的显示百分比实现遮罩效果。下面我使用两张一样的图片来实现一个类似于 android 的pro...

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实现遮罩层(蒙板)效果

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