自定义视图的简单应用
1、在res/values目录下新建attrs.xml文件:
<resources> <declare-styleable name="myStyleable"> <attr name="max" format="integer"/> <attr name="progress" format="integer"/> <attr name="textSize" format="dimension"/> <attr name="smallBgColor" format="color"/> <attr name="progressColor" format="color"/> </declare-styleable> </resources>
format(自定义属性的格式)可选内容有integer、dimension(尺寸)、color、boolean、enum(枚举值)、flag(位或运算)、float、fraction(百分数)、reference(参考某一ID、默认)、string.
<declare-styleable name =
"名称">
<attr name = "background" format =
"reference" />
</declare-styleable>
eg:
<ImageView
android:layout_width = "42dip"
android:layout_height = "42dip"
android:background = "@drawable/图片ID"
/>
2、自定义视图:
public class XykjProgressBar extends View { //进度条的半径 private int radius; //圆心 private int cx, cy; //画笔 private Paint paint; //进度的最大值 private int max = 100; //进度值 private int progress; //文本大小 private int textSize; //内部小圆的背景色 private int smallBgColor = 0xff3F51B5; //进度条的颜色 private int progressColor = 0xffFF4081; public XykjProgressBar(Context context) { super(context); init(); } public XykjProgressBar(Context context, @Nullable AttributeSet attrs) { super(context, attrs); //解析自定义属性 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.myStyleable); textSize = ta.getDimensionPixelSize(R.styleable.myStyleable_textSize, 0); //sp dp dip max = ta.getInteger(R.styleable.myStyleable_max,100); progress = ta.getInteger(R.styleable.myStyleable_progress,0); smallBgColor = ta.getColor(R.styleable.myStyleable_smallBgColor,0xff3F51B5); progressColor = ta.getColor(R.styleable.myStyleable_progressColor,0xffFF4081); //释放资源 ta.recycle(); init(); } private void init() { paint = new Paint(); paint.setAntiAlias(true); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); paint.setStyle(Paint.Style.FILL); paint.setColor(smallBgColor); //画中间的小圆 canvas.drawCircle(cx, cy, radius - 10, paint); //文本 int num = 100 * progress / max; //50 100 -->50% String str = num + "%"; //获取文本的边框 Rect bound = new Rect(); paint.setTextSize(textSize); paint.getTextBounds(str, 0, str.length(), bound); int x = cx - bound.centerX(); int y = cy - bound.centerY(); paint.setColor(Color.WHITE); //画进度文本 canvas.drawText(str, x, y, paint); //进度的弧线 paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(10); paint.setColor(progressColor); //计算所跨越的弧度 int degree = 360 * progress / max; RectF rect = new RectF(cx - radius, cy - radius, cx + radius, cy + radius); //画弧线 canvas.drawArc(rect, -90, degree, false, paint); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = getSize(widthMeasureSpec); int height = getSize(heightMeasureSpec); //初始化圆心 cx = width / 2; cy = height / 2; //取最短的边的一半作为进度半径 radius = width < height ? cx : cy; radius -= 10; //如果没有默认值则,初始化文本大小 if (textSize == 0) { textSize = radius / 2; } setMeasuredDimension(width, height); } //获取尺寸方法(自定义的根据模式获取,wrap_content时设置默认值为80) private int getSize(int measureSpec) { //获取测量模式 int mode = MeasureSpec.getMode(measureSpec); int size = 80; if (mode == MeasureSpec.EXACTLY) { //精确的,固定的值,match_parent或者100 200 size = MeasureSpec.getSize(measureSpec); }/*else if(mode == MeasureSpec.AT_MOST){ //不确定,如wrap_content size = 80; }*/ return size; } public int getMax() { return max; } public void setMax(int max) { this.max = max; } public int getProgress() { return progress; } public void setProgress(int progress) { if (this.progress != progress && progress <= max) { this.progress = progress; invalidate(); } } public int getTextSize() { return textSize; } public void setTextSize(int textSize) { this.textSize = textSize; } public int getSmallBgColor() { return smallBgColor; } public void setSmallBgColor(int smallBgColor) { this.smallBgColor = smallBgColor; } public int getProgressColor() { return progressColor; } public void setProgressColor(int progressColor) { this.progressColor = progressColor; } }
3、在主界面中引用:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="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="com.xykj.myprogressbar.MainActivity"> <com.xykj.myprogressbar.XykjProgressBar android:id="@+id/progress_bar" android:layout_width="200dp" android:layout_height="200dp" app:textSize="30sp" app:smallBgColor="#ff000000"/> <Button android:id="@+id/btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Click" /> </LinearLayout>
java代码:
public class MainActivity extends AppCompatActivity implements View.OnClickListener{ XykjProgressBar pBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); pBar = (XykjProgressBar) findViewById(R.id.progress_bar); pBar.setMax(100); pBar.setProgress(10); pBar.setTextSize(50); findViewById(R.id.btn).setOnClickListener(this); } @Override public void onClick(View v) { int p = pBar.getProgress(); p+=5; pBar.setProgress(p); } }
结果如下图:
面试题:介绍下实现一个自定义View的基本流程:
1、自定义view属性,编写attrs.xml文件
2、在layout布局中引用,同时引用命名空间
3、在view的构造方法中获得我们自定义的属性,在自定义的控件中进行读取
4、重写onMeasure()方法
5、重写onDraw()方法