import androID.animation.Animator;import androID.animation.AnimatorSet;import androID.animation.ObjectAnimator;import androID.animation.ValueAnimator;import androID.content.Context;import androID.content.res.TypedArray;import androID.graphics.Bitmap;import androID.graphics.BitmapShader;import androID.graphics.Canvas;import androID.graphics.color;import androID.graphics.Matrix;import androID.graphics.Paint;import androID.graphics.PorterDuff;import androID.graphics.PorterDuffXfermode;import androID.graphics.Shader;import androID.util.AttributeSet;import androID.util.displayMetrics;import androID.util.Log;import androID.vIEw.VIEw;import androID.vIEw.WindowManager;import androID.vIEw.animation.DecelerateInterpolator;import androID.vIEw.animation.linearInterpolator;import androIDx.annotation.floatRange;import com.beans.base.R;import com.beans.base.top.GlobalVariableKt;import org.greenrobot.eventbus.EventBus;import java.util.ArrayList;import java.util.List;import static com.beans.base.top.GlobalVariableKt.floatVIEwComplete;import static com.beans.base.top.GlobalVariableKt.getfloatVIEwHeight;import static com.beans.base.top.GlobalVariableKt.getfloatVIEwWIDth;import static com.beans.base.top.GlobalVariableKt.setfloatVIEwHeight;import static com.beans.base.top.GlobalVariableKt.setfloatVIEwWIDth;/** * @Author yangtianfu * @CreateTime 2020/3/24 11:26 * @Describe 自定义浮动vIEw,显示充电中电池电量 */public class floatVIEw extends VIEw{ /************************** 以下是内部使用的参数 ***************************/ private static final String TAG = "floatVIEw"; /** * 默认峰值取到最高,为了保证没有锯齿的出现,规则是只能缩小不能拉伸。 * 理论上峰值为0.5f为最佳,但是因为数值保留精度的差异, * 这里取最小值0.45 ,兼容1%屏幕高度,小于1%已经快看不到效果了 */ private static final float DEFAulT_AMPli_RATIO = 0.45f; //默认水平高度的比例,作为基准进行 *** 作 private static final float DEFAulT_HEIGHT_RATIO = 0.5f; //默认正弦的水平距离,作为基准进行 *** 作 private static final float DEFAulT_LENGTH_RATIO = 1.0f; //默认两个正弦波浪的水平距离比例(0f-1.0f) private static final float DEFAulT_disTANCE_RATIO = 0.125f; //最小值 private static final float DEFAulT_MIN_VALUE = 0.00000001f; //最大振幅 private static final float DEFAulT_MAX_AMPli_VALUE = 0.5f; //默认的水平高度,需要在getHeight()>0的时候才能缓存下来 private float mDefaultHeight; //波浪偏移:正弦平移距离比例(0f-1.0f) private float mShiftRatio = 1.0f; //振幅临时的数值,用来自动调整振幅高度 private float mLastAmplitudeRatio = 0.1f;//默认值 /************************** 以下是外部设置的参数 ***************************/ //波浪幅度:正弦的高度比例(amplitudeRatio + heightRatio <= 1 体验最佳) private float amplitudeRatio = 0.1f; //波浪高度:正弦起点高度比例(amplitudeRatio + heightRatio <= 1 体验最佳) private float heightRatio = DEFAulT_HEIGHT_RATIO; //双波浪距离:两个正弦波浪的水平距离比例(0f-1.0f) private float distanceRatio = DEFAulT_disTANCE_RATIO; //波浪频率:正弦的水平距离比例(0f-1.0f) private float frequency = 1.0f; //波浪升高到指定高度需要的动画时间 private int heightTime = 1000; //水平偏移一个画布长度需要的时间 private int shiftTime = 2000; //外圆边距 private int borderWIDth = 0; //外圆边颜色 private int bordercolor = color.parsecolor("#44FFFFFF"); //后面正弦的默认颜色,需要一定的不透明度 private int behindcolor = color.parsecolor("#28FFFFFF"); //前面正弦的默认颜色,需要一定的不透明度 private int frontcolor ;// private int frontcolor = color.parsecolor("#01e767"); //背景色 private int backgroundcolor = color.parsecolor("#00FFFFFF"); //默认形状为原型 private Shape shape = Shape.CIRCLE; /************************** 以下是内部属性 ***************************/ // 重复波浪的容器 private BitmapShader mWaveShader; // 重复波浪的容器 private BitmapShader mWaveShader2; // shader matrix private Matrix mShaderMatrix; private Matrix mShaderMatrix2; // 画波浪的画笔 private Paint mVIEwPaint; // 画波浪的画笔2 private Paint mVIEwPaint2; // 画边界的画笔 private Paint mborderPaint; // 集合动画 private AnimatorSet mAnimatorSet; /** * 这里不能调用super(context) * 因为早期的项目可能用的AppCompatActivity,getContex()得到的是Contextwrapper代理,并不是Context实例 * super(context, attrs, defStyle)方法在内部自动转换为Context,比较安全 * 自定义view统一走的时候super(context, attrs, defStyle)方法 */ public floatVIEw(Context context) { this(context, null, 0); } public floatVIEw(Context context, AttributeSet attrs) { this(context, attrs, 0); } public floatVIEw(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(attrs); //开启硬件离屏缓存:解决黑色问题,效率比关闭硬件加速高。 setLayerType(LAYER_TYPE_HARDWARE, null); } @OverrIDe protected voID onDetachedFromWindow() { super.onDetachedFromWindow(); //VIEw被窗体移除的时候释放动画资源 if (mAnimatorSet != null) { mAnimatorSet.end(); mAnimatorSet.cancel(); } } @OverrIDe public voID onWindowFocusChanged(boolean hasFoucus) { super.onWindowFocusChanged(hasFoucus); //VIEw焦点变化 if (mAnimatorSet != null) { if (hasFoucus) { if (mAnimatorSet.isstarted()) { mAnimatorSet.resume(); } else { mAnimatorSet.start(); } } else { mAnimatorSet.pause(); } } } @OverrIDe protected voID onSizeChanged(int w, int h, int olDW, int oldh) { super.onSizeChanged(w, h, olDW, oldh); //用作布局中显示绘制第一帧静态图像 createShader(-1); //绘制完第一帧之后就可以启动动画了 if (mAnimatorSet != null) mAnimatorSet.start(); } @OverrIDe protected voID onMeasure(int wIDthMeasureSpec, int heightmeasureSpec) { super.onMeasure(wIDthMeasureSpec, heightmeasureSpec); } @OverrIDe protected voID onDraw(Canvas canvas) { if (mWaveShader != null && mWaveShader2 != null && getWIDth() > 0 && getHeight() > 0) { //shader为空则设置shader if (mVIEwPaint.getShader() == null) { mVIEwPaint.setShader(mWaveShader); } if (mVIEwPaint2.getShader() == null) { mVIEwPaint2.setShader(mWaveShader2); } // 根据 frequency 和 amplitudeRatio 拉伸高度与长度的倍数 mShaderMatrix.setScale(frequency, amplitudeRatio / DEFAulT_AMPli_RATIO, 0, mDefaultHeight); // 根据 mShiftRatio 和 heightRatio 进行水平平移指定长度 mShaderMatrix.postTranslate(mShiftRatio * getWIDth() * 1f, (DEFAulT_HEIGHT_RATIO - heightRatio) * getHeight()); // 根据 frequency 和 amplitudeRatio 拉伸高度与长度的倍数 mShaderMatrix2.setScale(frequency, amplitudeRatio / DEFAulT_AMPli_RATIO, 0, mDefaultHeight); // 根据 mShiftRatio 和 heightRatio 进行水平平移指定长度,第二个曲线的频率设置为两倍,达到生动的波浪效果 mShaderMatrix2.postTranslate(mShiftRatio * getWIDth() * 2f, (DEFAulT_HEIGHT_RATIO - heightRatio) * getHeight()); // 将属性Matrix应用到shader中生效 mWaveShader.setLocalMatrix(mShaderMatrix); mWaveShader2.setLocalMatrix(mShaderMatrix2); //设置边界以及绘制背景的形状 float borderWIDth = mborderPaint == null ? 0f : mborderPaint.getstrokeWIDth(); switch (shape) { case CIRCLE: //绘制外边界圆 if (borderWIDth > 0) { canvas.drawCircle(getWIDth() / 2f, getHeight() / 2f, (getWIDth() - borderWIDth) / 2f - 1f, mborderPaint); } float radius = getWIDth() / 2f - borderWIDth; Paint paint = new Paint(); paint.setcolor(backgroundcolor); canvas.drawCircle(getWIDth() / 2f, getHeight() / 2f, radius, paint); //绘制内边界圆 canvas.drawCircle(getWIDth() / 2f, getHeight() / 2f, radius, mVIEwPaint); canvas.drawCircle(getWIDth() / 2f, getHeight() / 2f, radius, mVIEwPaint2); break; case SQUARE: setBackgroundcolor(backgroundcolor); //绘制外边界方形 if (borderWIDth > 0) { canvas.drawRect(borderWIDth / 2f, borderWIDth / 2f, getWIDth() - borderWIDth / 2f - 0.5f, getHeight() - borderWIDth / 2f - 0.5f, mborderPaint); } //绘制内边界方形 canvas.drawRect(borderWIDth, borderWIDth, getWIDth() - borderWIDth, getHeight() - borderWIDth, mVIEwPaint); canvas.drawRect(borderWIDth, borderWIDth, getWIDth() - borderWIDth, getHeight() - borderWIDth, mVIEwPaint2); break; } } else { mVIEwPaint.setShader(null); mVIEwPaint2.setShader(null); } } /** * 绘制默认两个静态波浪线 */ private voID createShader(int newFrontcolor) { Log.e(TAG, "createShader: 尺寸:" +getWIDth() + getHeight() ); int wIDth,height; if (getWIDth() != 0 && getHeight() != 0){ setfloatVIEwWIDth(getWIDth()); setfloatVIEwHeight(getHeight()); wIDth = getWIDth(); height = getHeight(); //UI绘制完成后再更新颜色,不然getWIDth()为0 EventBus.getDefault().post(floatVIEwComplete); }else { wIDth = getfloatVIEwWIDth(); height = getfloatVIEwHeight(); } double mDefaultAngularFrequency = 2.0f * Math.PI / DEFAulT_LENGTH_RATIO / wIDth; float mDefaultAmplitude = height * DEFAulT_AMPli_RATIO; mDefaultHeight = height * DEFAulT_HEIGHT_RATIO; //用bitmap作画布,方便裁剪出圆形 Bitmap bitmap = Bitmap.createBitmap(wIDth, height, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); Bitmap bitmap2 = Bitmap.createBitmap(wIDth, height, Bitmap.Config.ARGB_8888); Canvas canvas2 = new Canvas(bitmap2); //初始化波浪画笔 Paint wavePaint = new Paint(); wavePaint.setstrokeWIDth(2); wavePaint.setAntiAlias(true); wavePaint.setFilterBitmap(true); // 将默认的波浪绘制到bitmap,按照公式:y=Asin(ωx+φ)+h 进行绘制正弦 final int endX = wIDth + 1; final int endY = height + 1; float[] waveY = new float[endX]; if (newFrontcolor != -1){ Log.e(TAG, "createShader: 自定义颜色" ); wavePaint.setcolor(newFrontcolor); }else { Log.e(TAG, "createShader: 初始化颜色" ); wavePaint.setcolor(frontcolor); } //绘制前正弦 for (int beginX = 0; beginX < endX; beginX++) { double wx = beginX * mDefaultAngularFrequency; float beginY = (float) (mDefaultHeight + mDefaultAmplitude * Math.sin(wx)); canvas.drawline(beginX, beginY, beginX, endY, wavePaint); waveY[beginX] = beginY; } //绘制后正弦 if (newFrontcolor != -1){ Log.e(TAG, "createShader: 自定义正弦颜色" ); wavePaint.setcolor(newFrontcolor); }else { Log.e(TAG, "createShader: 默认正弦颜色" ); wavePaint.setcolor(frontcolor); } Log.e(TAG, "createShader: frontcolor == "+frontcolor ); wavePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER)); final int wave2Shift = (int) (wIDth * DEFAulT_disTANCE_RATIO); for (int beginX = 0; beginX < endX; beginX++) { canvas2.drawline(beginX, waveY[(beginX + wave2Shift) % endX], beginX, endY, wavePaint); } // 利用 bitamp 创建 shader mWaveShader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP); mVIEwPaint.setShader(mWaveShader); mWaveShader2 = new BitmapShader(bitmap2, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP); mVIEwPaint2.setShader(mWaveShader2); } /** * 初始化 * * @param attrs 布局属性 */ private voID init(AttributeSet attrs) { if (attrs != null) { //初始化布局属性 TypedArray typedArray = getContext().gettheme().obtainStyledAttributes(attrs, R.styleable.WaveVIEw, 0, 0); //高度只能大于等于0以及小于等于1 float heightRatio = typedArray.getfloat(R.styleable.WaveVIEw_wa_heightRatio, this.heightRatio); if (heightRatio >= 0 && heightRatio <= 1.0f) { this.heightRatio = heightRatio; } else { Log.e(TAG, "invalID heightRatio"); } //振幅只能大于0以及小于等于0.5 float amplitudeRatio = typedArray.getfloat(R.styleable.WaveVIEw_wa_amplitudeRatio, this.amplitudeRatio); if (amplitudeRatio > DEFAulT_MIN_VALUE && amplitudeRatio <= DEFAulT_MAX_AMPli_VALUE) { this.amplitudeRatio = amplitudeRatio; this.mLastAmplitudeRatio = this.amplitudeRatio; } else { Log.e(TAG, "invalID amplitudeRatio"); } //根据合法性调整振幅 this.amplitudeRatio = adjustAmplitudeRatio(this.heightRatio, this.amplitudeRatio, this.mLastAmplitudeRatio); //波形密度检查 int frequency = typedArray.getInteger(R.styleable.WaveVIEw_wa_frequency, 1); if (frequency > 0) { this.frequency = 2.0f / ((int) Math.pow(2, frequency - 1)); } else { Log.e(TAG, "invalID frequency"); } //边界宽度 int borderWIDth = typedArray.getcolor(R.styleable.WaveVIEw_wa_borderWIDth, this.borderWIDth); if (borderWIDth >= 0) { this.borderWIDth = borderWIDth; } else { Log.e(TAG, "invalID borderWIDth"); } //其他参数 heightTime = typedArray.getInteger(R.styleable.WaveVIEw_wa_heightTime, heightTime); shiftTime = typedArray.getInteger(R.styleable.WaveVIEw_wa_shiftTime, shiftTime); frontcolor = typedArray.getcolor(R.styleable.WaveVIEw_wa_frontcolor, frontcolor); behindcolor = typedArray.getcolor(R.styleable.WaveVIEw_wa_behindcolor, behindcolor); shape = typedArray.getInt(R.styleable.WaveVIEw_wa_shape, 0) == 0 ? shape : Shape.SQUARE; bordercolor = typedArray.getcolor(R.styleable.WaveVIEw_wa_bordercolor, bordercolor); backgroundcolor = typedArray.getcolor(R.styleable.WaveVIEw_wa_background, backgroundcolor); typedArray.recycle(); } //初始化画笔 mShaderMatrix = new Matrix(); mShaderMatrix2 = new Matrix(); mVIEwPaint = new Paint(); //设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰 mVIEwPaint.setDither(true); mVIEwPaint.setAntiAlias(true); mVIEwPaint.setFilterBitmap(true); mVIEwPaint2 = new Paint(); mVIEwPaint2.setDither(true); mVIEwPaint2.setAntiAlias(true); mVIEwPaint2.setFilterBitmap(true); mAnimatorSet = new AnimatorSet(); //边界画笔 mborderPaint = new Paint(); mborderPaint.setAntiAlias(true); mborderPaint.setDither(true); mborderPaint.setFilterBitmap(true); mborderPaint.setStyle(Paint.Style.stroke); mborderPaint.setcolor(bordercolor); mborderPaint.setstrokeWIDth(borderWIDth); //初始化动画 List<Animator> animators = new ArrayList<>(); //水平平移动画,指定时间偏移一个画布长度 animators.add(getShiftAnimator(this.shiftTime)); //竖直平移动画,指定时间偏移到默认高度 animators.add(getHeightAnimator(this.heightTime)); //集合动画播放 此处默认不开启// mAnimatorSet.playTogether(animators); } /** * 得到屏幕尺寸 * * @return 尺寸 */ private displayMetrics getScreenMetrics() { WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); displayMetrics displayMetrics = new displayMetrics(); windowManager.getDefaultdisplay().getMetrics(displayMetrics); return displayMetrics; } /** * 获取水平偏移相对整个画布长度比例(范围:0 ~ 1) * * @return float 高度比例 */ private float getShiftRatio() { return mShiftRatio; } /** * 设置水平偏移的相对整个画布长度比例(范围:0 ~ 1) * * @param waveShiftRatio 水平偏移的长度比例 */ private voID setShiftRatio(@floatRange(from = 0.0f, to = 1.0f) float waveShiftRatio) { if (mShiftRatio != waveShiftRatio) { mShiftRatio = waveShiftRatio; invalIDate(); } } /** * 获取水平偏移动画 * * @param shiftTime 动画时间 */ private ObjectAnimator getShiftAnimator(int shiftTime) { //水平平移动画,指定时间偏移一个画布长度 ObjectAnimator waveShiftAnim = ObjectAnimator.offloat(this, "shiftRatio", 0f, 2f); waveShiftAnim.setRepeatCount(ValueAnimator.INFINITE); waveShiftAnim.setDuration(shiftTime); waveShiftAnim.setRepeatMode(ValueAnimator.RESTART); waveShiftAnim.setInterpolator(new linearInterpolator()); return waveShiftAnim; } /** * 获取竖直偏移动画 * * @param heightTime 动画时间 */ private ObjectAnimator getHeightAnimator(int heightTime) { //竖直平移动画,指定时间偏移到默认高度 ObjectAnimator waveLevelAnim = ObjectAnimator.offloat(this, "heightRatio", 0f, getHeightRatio()); waveLevelAnim.setDuration(heightTime); waveLevelAnim.setInterpolator(new DecelerateInterpolator()); return waveLevelAnim; } /** * 获取波浪高度比例(范围:0 ~ 1) * * @return float 高度比例 */ private float getHeightRatio() { return heightRatio; } /** * 设置波浪相对整个画布高度比例(范围:0 ~ 1),amplitudeRatio + heightRatio <= 1 体验最佳 * * @param heightRatio 高度比例 */ public voID setHeightRatio(@floatRange(from = 0.0f, to = 1.0f) float heightRatio) { if (heightRatio > 1f) { heightRatio = 1f; } if (this.heightRatio != heightRatio && heightRatio >= 0) { this.heightRatio = heightRatio; //得到合理的振幅 this.amplitudeRatio = adjustAmplitudeRatio(this.heightRatio, this.amplitudeRatio, this.mLastAmplitudeRatio); //invalIDate(); } } /** * 调整振幅,保证平滑处理 * * @return float 最后输出的振幅 */ private float adjustAmplitudeRatio(float heightRatio, float amplitudeRatio, float lastAmplitudeRatio) { float ratio = amplitudeRatio; //恢复上次修改的值 if (ratio != lastAmplitudeRatio) { ratio = lastAmplitudeRatio; } //微调 if ((ratio + heightRatio > 1)) { //最高不能超过整个画布,且振幅不为0 ratio = 1f - heightRatio + DEFAulT_MIN_VALUE; } else { //振幅不能大于高度 if (heightRatio < lastAmplitudeRatio) { ratio = heightRatio; } } return ratio; } /** * 设置两个正弦波浪的距离相对一个波浪长度的比例(范围:0 ~ 1) * * @param distanceRatio 距离比例 */ private voID setdistanceRatio(@floatRange(from = 0.0f, to = 1.0f) float distanceRatio) { if (this.distanceRatio != distanceRatio && getWIDth() > 0 && getHeight() > 0) { this.distanceRatio = distanceRatio; //需要重新创建shader mWaveShader = null; createShader(-1); //invalIDate(); } } /* -------------------------------------------- public -------------------------------------------- */ /** * 设置画布背景的形状:圆形或者方形 * * @param Shape 形状的枚举类 */ public voID setShape(Shape Shape) { if (this.shape != Shape) { this.shape = Shape; //invalIDate(); } } /** * 设置振幅相对整个画布高度比例(范围:0 ~ 0.5),amplitudeRatio + heightRatio <= 1 体验最佳 * * @param amplitudeRatio 振幅比例 */ public voID setAmplitudeRatio(@floatRange(from = DEFAulT_MIN_VALUE, to = DEFAulT_MAX_AMPli_VALUE) float amplitudeRatio) { if (this.amplitudeRatio != amplitudeRatio && amplitudeRatio <= DEFAulT_MAX_AMPli_VALUE && amplitudeRatio >= DEFAulT_MIN_VALUE) { this.mLastAmplitudeRatio = amplitudeRatio; //得到合理的振幅 this.amplitudeRatio = adjustAmplitudeRatio(heightRatio, amplitudeRatio, mLastAmplitudeRatio); invalIDate(); } } /** * 波浪密度也即是频率:求水平容纳波浪个数,一个上下波峰表示一个波浪数 * * @param frequency 水平波浪数目 */ public voID setFrequency(int frequency) { if (frequency <= 0) { frequency = 1; } //求2的次方 int powNumber = (int) Math.pow(2, frequency - 1); //求倒数 float backNumber = 2.0f / powNumber; if (backNumber != frequency) { this.frequency = backNumber; //invalIDate(); } } /** * 设置前波浪的颜色 * * @param frontcolor 前波浪颜色 */ public voID setFrontcolor(int frontcolor) { if (getfloatVIEwWIDth() > 0 && getfloatVIEwHeight() > 0 && this.frontcolor != frontcolor) { this.frontcolor = frontcolor; //需要重新创建shader mWaveShader = null; createShader(frontcolor);// invalIDate(); } } /** * 设置后波浪的颜色 * * @param behindcolor 后波浪颜色 */ public voID setBehindcolor(int behindcolor) { if (getWIDth() > 0 && getHeight() > 0 && this.behindcolor != behindcolor) { this.behindcolor = behindcolor; //需要重新创建shader mWaveShader = null; createShader(-1);// invalIDate(); } } /** * 设置偏移动画时间 * * @param shiftTime 动画时间 */ public voID setShiftTime(int shiftTime) { this.shiftTime = shiftTime; if (mAnimatorSet != null) { mAnimatorSet.end(); } mAnimatorSet = new AnimatorSet(); mAnimatorSet.play(getShiftAnimator(this.shiftTime)); mAnimatorSet.start(); } /** * 设置边界的宽度(像素单位) * * @param wIDth 宽度 */ public voID setborderWIDth(int wIDth) { mborderPaint.setstrokeWIDth(wIDth); //invalIDate(); } /** * 设置边界的颜色 * * @param color 颜色 */ public voID setbordercolor(int color) { mborderPaint.setcolor(color); //invalIDate(); } //波浪背景娿形状,圆形与方形 public enum Shape { CIRCLE, SQUARE }}
总结 以上是内存溢出为你收集整理的Canvas绘制自定义view的颜色PorterDuffXfermode的选择全部内容,希望文章能够帮你解决Canvas绘制自定义view的颜色PorterDuffXfermode的选择所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)