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

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;

@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实现遮罩层(蒙板)效果 的全部内容, 来源链接: utcz.com/p/241286.html

回到顶部