> 文章列表 > 【Android】之【自定义View实践】

【Android】之【自定义View实践】

【Android】之【自定义View实践】

这里以一个进度条的加载为例子,先看效果(运行效果是动态变化的)

一、自定义属性

首先在res->values目录下新建attrs资源文件,如下图:

【Android】之【自定义View实践】
内容如下:

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="ProgressBar">
<!--       圆弧的颜色--><attr name="innerBackground" format="color"/><attr name="outerBackground" format="color"/>
<!--       圆弧的大小--><attr name="roundWidth" format="dimension"/>
<!--       字体大小、颜色--><attr name="progressTextSize" format="dimension"/><attr name="progressTextColor" format="color"/></declare-styleable>
</resources> 

二、在Layout文件中引用自定义View

这里要注意引入自定义View属性的命名空间的方式

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:custom="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"android:orientation="vertical"><com.example.viewtest.ProgressBarandroid:id="@+id/progress_bar"custom:progressTextSize="20sp"custom:progressTextColor="#ff7788"custom:innerBackground="#ee9933"custom:outerBackground="#229933"custom:roundWidth="5dp"android:layout_width="match_parent"android:layout_height="match_parent"/><!--    测试按钮--><Buttonandroid:id="@+id/test"android:layout_width="100dp"android:layout_height="50dp"android:layout_marginTop="30dp"android:layout_gravity="center"android:text="测试"android:background="@color/black"android:textColor="@color/white"/></LinearLayout> 

三、 创建一个类继承View

public class ProgressBar extends View {private static final String TAG = "ProgressBar";//声明自定义属性private int mInnerBackground = Color.RED;private int mOuterBackground = Color.GREEN;private int mRoundWidth = 30;private int mProgressTextSize = 70;private int mProgressTextColor = Color.GREEN;//创建画笔private Paint mInnerPaint=new Paint();private Paint mOutterPaint = new Paint();private Paint mTextPaint = new Paint();//进度条的最大进度private int mMax=100;//当前进度private int mCurrentProgress=50;//new对象的时候调用该方法public ProgressBar(Context context) {super(context);}//在布局中使用   xml文件中使用public ProgressBar(Context context, @Nullable AttributeSet attrs) {super(context, attrs);}//  在layout中调用  自定义样式、有固定style的时候使用public ProgressBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);//获取自定义属性TypedArray array= context.obtainStyledAttributes(attrs,R.styleable.ProgressBar);mInnerBackground=array.getColor(R.styleable.ProgressBar_innerBackground,mInnerBackground);mOuterBackground=array.getColor(R.styleable.ProgressBar_outerBackground,mOuterBackground);mProgressTextColor= array.getColor(R.styleable.ProgressBar_progressTextColor,mProgressTextColor);mProgressTextSize= (int) array.getDimension(R.styleable.ProgressBar_progressTextSize,sp2px(mProgressTextSize));mRoundWidth= (int) array.getDimension(R.styleable.ProgressBar_roundWidth,dip2px(mRoundWidth));array.recycle();//        mInnerPaint = new Paint();}private float sp2px(int sp) {return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,sp,getResources().getDisplayMetrics());}private float dip2px(int dip) {return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dip,getResources().getDisplayMetrics());}public ProgressBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);}/* onMeasure*/@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);//拿到宽高int width = MeasureSpec.getSize(widthMeasureSpec);int height = MeasureSpec.getSize(heightMeasureSpec);//存储view 的宽高 在这里取最小值 保证是一个正方形即可setMeasuredDimension(Math.min(width,height),Math.min(width,height));}/* onDraw*/@Overrideprotected void onDraw(Canvas canvas) {mInnerPaint.setAntiAlias(true);//抗锯齿mInnerPaint.setColor(mInnerBackground);mInnerPaint.setStrokeWidth(mRoundWidth);//线条宽度mInnerPaint.setStyle(Paint.Style.STROKE);//空心mOutterPaint.setAntiAlias(true);//抗锯齿mOutterPaint.setColor(mOuterBackground);mOutterPaint.setStrokeWidth(mRoundWidth);//线条宽度mOutterPaint.setStyle(Paint.Style.STROKE);//空心mOutterPaint.setAntiAlias(true);//抗锯齿mTextPaint.setColor(mProgressTextColor);mTextPaint.setStrokeWidth(mRoundWidth);mTextPaint.setTextSize(mProgressTextSize);//        super.onDraw(canvas);//先画内圆int center = getWidth()/2;Log.d(TAG, "onDraw: "+center);canvas.drawCircle(center,center,center-mRoundWidth/2,mInnerPaint);//再画外层圆RectF rectF=new RectF(0+mRoundWidth/2,0+mRoundWidth/2,getWidth()-mRoundWidth/2,getHeight()-mRoundWidth/2);if (mCurrentProgress==0){return;}float percent = (float) mCurrentProgress/mMax;canvas.drawArc(rectF,0,percent*360,false,mOutterPaint);//画进度文字String text=((int)(percent*100))+"%";Rect textBounds=new Rect();mTextPaint.getTextBounds(text,0,text.length(),textBounds);int x= getWidth()/2-textBounds.width()/2;Paint.FontMetricsInt fontMetrics=mTextPaint.getFontMetricsInt();int dy=(fontMetrics.bottom-fontMetrics.top)/2 - fontMetrics.bottom;int baseLineY=getHeight()/2+dy;canvas.drawText(text,x,baseLineY,mTextPaint);}public synchronized void setMax(int max){if (max<0){Log.d(TAG, "setMax: max<0 不合法"+max);}this.mMax=max;}public synchronized void setProgress(int process){if (process<0){Log.d(TAG, "setMax: max<0 不合法"+process);}this.mCurrentProgress=process;invalidate();//刷新}
} 

实现自定义View有那些方式
① 继承View,例如折线图等。
② 继承ViewGroup,例如流式布局等。
③ 继承现有的View,例如TextView、ListView等。

四、在Activity中调用

public class MainActivity extends AppCompatActivity {private ProgressBar mProgressBar;private Button mTest;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initData();}private void initData() {mTest=findViewById(R.id.test);mProgressBar=(ProgressBar) findViewById(R.id.progress_bar);mProgressBar.setMax(1000);mTest.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {test();}});}private void test() {//值不断变化ValueAnimator animator= ObjectAnimator.ofFloat(0,1000);animator.setDuration(3000);animator.start();animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {float progress = (float) animation.getAnimatedValue();mProgressBar.setProgress((int) progress);}});}
} 

五、参考

  • Android自定义View
  • 【Android学习】—自定义view的流程以及实践
  • Android自定义View入门(一)
  • Android 自定义View 之 Mac地址输入框

DNS科普网