摘要:效果如下图展示效果不好,实际体验无卡顿自定义属性早目录下,命名为命名随意,但规范命名为自定义属性如下,注意不要与自带的命名重复。
效果如下gif图展示效果不好,实际体验无卡顿
早Values目录下New-values resource file,命名为attrs.xml(命名随意,但规范命名为attrs.xml)
自定义属性如下,注意format不要与Android自带的命名重复。
2.编写自定义View
import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.View; import com.cyq.customview2.R; import com.cyq.customview2.utils.MeasureUtils; @SuppressWarnings("all") public class QQStepView extends View { private int mOuterColor = Color.parseColor("#2196F3"); private int mInnerColor = Color.parseColor("#F44336"); private int mStepTextColor = Color.parseColor("#EC407A"); private int mBorderWidth = 20;//px private int mStepTextSize = 18;//px private int mSeptMax = 10000; private int mSeptCurrent = 0; private Paint mOutPaint; private Paint mInnerPaint; private Paint mTextPaint; public QQStepView(Context context) { this(context, null); } public QQStepView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public QQStepView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.QQStepView); mOuterColor = array.getColor(R.styleable.QQStepView_outerColor, mOuterColor); mInnerColor = array.getColor(R.styleable.QQStepView_innerColor, mInnerColor); mStepTextColor = array.getColor(R.styleable.QQStepView_stepTextColor, mStepTextColor); mBorderWidth = (int) array.getDimension(R.styleable.QQStepView_borderWidth, MeasureUtils.dp2px(mBorderWidth, this)); mStepTextSize = array.getDimensionPixelSize(R.styleable.QQStepView_stepTextSize, MeasureUtils.sp2px(mStepTextSize, this)); array.recycle(); mOutPaint = new Paint(); mOutPaint.setAntiAlias(true); mOutPaint.setStrokeWidth(mBorderWidth); mOutPaint.setColor(mOuterColor); mOutPaint.setStyle(Paint.Style.STROKE); mOutPaint.setStrokeCap(Paint.Cap.ROUND);//圆角 mInnerPaint = new Paint(); mInnerPaint.setAntiAlias(true); mInnerPaint.setStrokeWidth(mBorderWidth); mInnerPaint.setColor(mInnerColor); mInnerPaint.setStyle(Paint.Style.STROKE);//实心 mInnerPaint.setStrokeCap(Paint.Cap.ROUND);//圆角 mTextPaint = new Paint(); mTextPaint.setAntiAlias(true); mTextPaint.setStyle(Paint.Style.STROKE); mTextPaint.setColor(mStepTextColor); mTextPaint.setTextSize(mStepTextSize); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) { //用户设置的是wrap_content,此时设置一个默认宽高100 width = height = MeasureUtils.dp2px(200, this); } setMeasuredDimension(width > height ? height : width, width > height ? height : width); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int center = getWidth() / 2; int radius = getWidth() / 2 - mBorderWidth; RectF rectF = new RectF(mBorderWidth, mBorderWidth, center + radius, center + radius); canvas.drawArc(rectF, 135, 270, false, mOutPaint); if (mSeptMax == 0) return; float sweepAngle = (float) mSeptCurrent / mSeptMax; canvas.drawArc(rectF, 135, 270 * sweepAngle, false, mInnerPaint); String stepText = mSeptCurrent + ""; Rect textBounds = new Rect(); mTextPaint.getTextBounds(stepText, 0, stepText.length(), textBounds); int dx = getWidth() / 2 - textBounds.width() / 2; int baseLine = MeasureUtils.measureBaseLine(mTextPaint, stepText, this); canvas.drawText(stepText, dx, baseLine, mTextPaint); } public void setmSeptMax(int mSeptMax) { this.mSeptMax = mSeptMax; } public synchronized void setmSeptCurrent(int mSeptCurrent) { this.mSeptCurrent = mSeptCurrent; //重绘 invalidate(); } }
import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.View; import com.cyq.customview2.R; import com.cyq.customview2.utils.MeasureUtils; @SuppressWarnings("all") public class MyProgressBar extends View { private int mLiftColor = Color.parseColor("#F44336"); private int mRightColor = Color.parseColor("#E0E0E0"); private int mProgressTextColor = Color.parseColor("#616161"); private int mProgressTextSize = 12;//px 后续再考虑需不需要转换成sp private int mProgressBounds = 1;//px private int mCurrentProgress, mMaxProgress = 100;//默认最大刻度为100 private Paint mLeftPaint, mRightPaint, mTextPaint; public MyProgressBar(Context context) { this(context, null); } public MyProgressBar(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public MyProgressBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyProgressBar); mLiftColor = array.getColor(R.styleable.MyProgressBar_leftColor, mLiftColor); mRightColor = array.getColor(R.styleable.MyProgressBar_rightColor, mRightColor); mProgressTextColor = array.getColor(R.styleable.MyProgressBar_progressTextColor, mProgressTextColor); mProgressTextSize = array.getDimensionPixelSize(R.styleable.MyProgressBar_progressTextSize, mProgressTextSize); array.recycle(); mLeftPaint = new Paint(); mLeftPaint.setAntiAlias(true); mLeftPaint.setColor(mLiftColor); mRightPaint = new Paint(); mRightPaint.setAntiAlias(true); mRightPaint.setColor(mRightColor); mTextPaint = new Paint(); mTextPaint.setAntiAlias(true); mTextPaint.setStyle(Paint.Style.STROKE); mTextPaint.setColor(mProgressTextColor); mTextPaint.setTextSize(mProgressTextSize); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widht = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(widht, height); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mRightPaint.setStrokeWidth(getHeight()); RectF rightRect = new RectF(0, 0, getWidth(), getHeight()); canvas.drawRoundRect(rightRect, getHeight() / 2, getHeight() / 2, mRightPaint); mLeftPaint.setStrokeWidth(getHeight()); float progress = (float) mCurrentProgress / (mMaxProgress * 10); int radius = getHeight() / 2; RectF rectF = new RectF(0, 0, progress * getWidth(), getHeight()); canvas.drawRoundRect(rectF, radius, radius, mLeftPaint); //画文字随着进度条右移 String text = (float) mCurrentProgress / 10 + "%"; int dx = getHeight() / 2; Rect textBounds = new Rect(); mTextPaint.getTextBounds(text, 0, text.length(), textBounds); int baseLine = MeasureUtils.measureBaseLine(mTextPaint, text, this); canvas.drawText(text, progress * getWidth() + 10, baseLine, mTextPaint); } public void setProgress(int mCurrentProgress) { this.mCurrentProgress = mCurrentProgress; //重绘 invalidate(); } public void setMaxProgress(int mMaxProgress) { this.mMaxProgress = mMaxProgress; } public int getProgress() { return mCurrentProgress; } }3.为自定义View添加动画
首先在xml中使用我们的自定义布局和自定义属性
通过属性动画动态增加进度
import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.animation.DecelerateInterpolator; import com.cyq.customview2.R; import butterknife.BindView; import butterknife.ButterKnife; public class QQSportActivity extends AppCompatActivity { @BindView(R.id.custom_QQ_step) QQStepView customQQStep; @BindView(R.id.custom_progressbar) MyProgressBar customProgressbar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_qqsport); ButterKnife.bind(this); customQQStep.setmSeptMax(10000); //属性动画 ValueAnimator valueAnimator = ObjectAnimator.ofFloat(0, 8765); valueAnimator.setDuration(2000); valueAnimator.setInterpolator(new DecelerateInterpolator());//插值器 valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float currentStep = (Float) animation.getAnimatedValue(); customQQStep.setmSeptCurrent((int) currentStep); } }); valueAnimator.start(); //属性动画 ValueAnimator valueAnimator2 = ObjectAnimator.ofFloat(0, 780); valueAnimator2.setDuration(2000); valueAnimator2.setInterpolator(new DecelerateInterpolator());//插值器 valueAnimator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float currentStep = (Float) animation.getAnimatedValue(); customProgressbar.setProgress((int) currentStep); } }); valueAnimator2.start(); } }
获取文字基线和sp,dp转xp的工具类如下;
import android.graphics.Paint; import android.graphics.Rect; import android.util.TypedValue; import android.view.View; public class MeasureUtils { /** * drawText获取基线 * * @param textPaint * @param text * @param view * @return */ public static int measureBaseLine(Paint textPaint, String text, View view) { Rect textBounds = new Rect(); textPaint.getTextBounds(text, 0, text.length(), textBounds); Paint.FontMetricsInt fontMetricsInt = textPaint.getFontMetricsInt(); int dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom; int baseLine = view.getHeight() / 2 + dy; return baseLine; } public static int sp2px(int sp, View view) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, view.getResources().getDisplayMetrics()); } public static int dp2px(int dp, View view) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, view.getResources().getDisplayMetrics()); } }
1.sp,dp,xp的转换
2.进度文字接近100%时不向右边移动,并且文字和进度重叠部分动态变色
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/2831.html
摘要:项目规划本项目为基于微信手机应用平台的一款运动互动型小程序,实现了用户即时运动步数群内与个人动态的发布,小程序前端采用原生框架,后端采用基于的框架,数据库采用,对象存储采用七牛云,服务器采用阿里,域名采用认证。 1. 项目规划 本项目为基于微信手机应用平台的一款运动互动型小程序,实现了用户即时运动步数群内PK与个人动态的发布,小程序前端采用原生框架,后端采用基于Node的koa2框架,...
摘要:项目规划本项目为基于微信手机应用平台的一款运动互动型小程序,实现了用户即时运动步数群内与个人动态的发布,小程序前端采用原生框架,后端采用基于的框架,数据库采用,对象存储采用七牛云,服务器采用阿里,域名采用认证。 1. 项目规划 本项目为基于微信手机应用平台的一款运动互动型小程序,实现了用户即时运动步数群内PK与个人动态的发布,小程序前端采用原生框架,后端采用基于Node的koa2框架,...
摘要:卷积满足交换操作,因此在一般的维空间输入,自编码可以被用来训练解码编码。事实上,解码卷积的超参数是由编码框架确定的由于卷积跨越每个特征图,并且产生具有的维度,因此经过滤波器之后产生相同的空间范围。 作者:chen_h微信号 & QQ:862251340微信公众号:coderpai简书地址:https://www.jianshu.com/p/ec4... 这篇教程是翻译Paolo Ga...
摘要:原文链接项目中经常会用到加载数据的显示图,除了设计根据自身设计的动画,一般用的比较多的是仿照的菊花加载图,当然一些条件下还会涉及到加载成功失败情况的显示,还有显示文字。使用来加载动画转圈,这里使用文件定义转圈动画,属性进行加载。 原文链接:https://mp.weixin.qq.com/s/wBbQgOfr59wntNK9ZJ5iRw 项目中经常会用到加载数据的loading显示图...
阅读 352·2023-04-26 01:42
阅读 3072·2021-11-22 11:56
阅读 2194·2021-10-08 10:04
阅读 635·2021-09-24 10:37
阅读 9221·2021-09-22 15:49
阅读 2967·2019-08-30 15:52
阅读 1572·2019-08-29 13:44
阅读 342·2019-08-28 17:51