您的位置:首页 > 其它

自定义VIew

2016-07-15 23:42 281 查看

自定义View实现圆形进度条

在开始自定义View前需要先了解一些背景知识通过Android官方API我们可以了解到

Implementing a Custom View

To implement a custom view, you will usually begin by providing overrides for some of the standard methods that the framework calls on all views. You do not need to override all of these methods. In fact, you can start by just overriding
onDraw(android.graphics.Canvas)
.

CategoryMethodsDescription
CreationConstructorsThere is a form of the constructor that are called when the view is created from code and a form that is called when the view is inflated from a layout file. The second form should parse and apply any attributes defined in the layout file.
onFinishInflate()
Called after a view and all of its children has been inflated from XML.
Layout
onMeasure(int, int)
Called to determine the size requirements for this view and all of its children.
onLayout(boolean, int, int, int, int)
Called when this view should assign a size and position to all of its children.
onSizeChanged(int, int, int, int)
Called when the size of this view has changed.
Drawing
onDraw(android.graphics.Canvas)
Called when the view should render its content.
Event processing
onKeyDown(int, KeyEvent)
Called when a new hardware key event occurs.
onKeyUp(int, KeyEvent)
Called when a hardware key up event occurs.
onTrackballEvent(MotionEvent)
Called when a trackball motion event occurs.
onTouchEvent(MotionEvent)
Called when a touch screen motion event occurs.
Focus
onFocusChanged(boolean, int, android.graphics.Rect)
Called when the view gains or loses focus.
onWindowFocusChanged(boolean)
Called when the window containing the view gains or loses focus.
Attaching
onAttachedToWindow()
Called when the view is attached to a window.
onDetachedFromWindow()
Called when the view is detached from its window.
onWindowVisibilityChanged(int)
Called when the visibility of the window containing the view has changed.
这是官方API关于实现View的一些描述。里面介绍了每个方法的作用,这里就不挨个解释了,有兴趣可以自己去查看官方文档,要自定义VIew其实最关键的是重写onDraw方法。

下面开始做这样一个小的Demo。分为如下几个步骤:
1.自定义属性资源,在android中我们可以通过配置XML来给VIew设置相关的属性
 2.新建MyView类继承VIew
 3.将MyView添加到activity_main.xml文件

1.在res/value文件夹下新建属性文件attrs.xml

declare-styleable标签声明属性集。
attr声明属性
这里自定义View实现圆形进度条所以配置如下属性:
圆环的颜色:roundColor
进度的颜色:round
圆环的宽度(直径):roundWidth
中间显示字体的颜色:textColor
中间显示字体的大小:textSize
最大进度:max
是否显示圆环进度中心的字体:textIsDisplayable
圆环的风格(实心或空心):style


<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyView">
<attr name="roundColor" format="color"/>
<attr name="roundProgressColor" format="color"/>
<attr name="roundWidth" format="dimension"/>
<attr name="textColor" format="color"/>
<attr name="textSize" format="dimension"/>
<attr name="max" format="integer"/>
<attr name="textIsDisplayable" format="boolean"/>
<attr name="style">
<enum name="STROKE" value="0"></enum>
<enum name="FILL" value="1"></enum>
</attr>
</declare-styleable>
</resources>


2.自定义View重写onDraw是关键参数Canvas代表的是画布在画布上我们可以通过Paint画自己想画的一些东西。但是在画之前需要先设置
画笔的一些属性。
自定义View实现圆环进度条是为了给其他父类控件使用因此需要对外暴露设置和取的这些属性的方法,但是其中的进度属性需要我们注意
因为在使用过程中进度一般是随时间而变化的会不断使用get、set方法来操作它,联系到在Android中主线程用来跟新界面,而不会有费时
操作来获取不断更新的进度每次进度更新后我们会通知主线程重新绘制。使用synchronized修饰progress属性的get、set方法保证在跟新
进度属性的时候不会有获取操作。

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.View;

import com.example.administrator.defineviewbymyself.R;

/**
* Created by Administrator on 2016/7/15 0015.
*
* 对于View类
* extends Object
* implements Drawable.Callback KeyEvent.Callback AccessibilityEventSource
*/
public class MyView extends View {

/*
* 字体内容
* */
String my_text;

/*
* 画笔对象的引用
* */
private Paint mPaint;
/*
* 圆环颜色
* */
private int roundColor;
/*
* 圆环进度的颜色
* */
private int roundProgressColor;
/*
* 圆环宽度
* */
private float roundWidth;
/*
* 中间进度百分比的字符串颜色的颜色
* */
private int textColor;
/*
* 中间进度百分比的字符串颜色的大小
* */
private float textSize;
/*
* 最大进度
* */
private Integer max;
/*
* 是否显示中间进度
* */
private boolean textIsDisplayable;
/*
* 进度风格,实心或空心
* */
private int style;
/*
* 当前进度
* */
//这里把进度设置为50只是为了示例能够看到效果
   private int progress = 50;
public static final int STROKE = 0;
public static final int FILL = 1;

/*
* 该构造方法在Java代码中创建MyView对象调用
* @param Context来字
* */
public MyView(Context context) {
this(context,null);
}
/*
*在布局文件中设置MyView系统会调用该方法
* AttributeSet attrs与属性相关的一些东西
* 在资源文件中配置
* */
public MyView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}

/*
* int defStyleAttr MyView的默认样式
* */
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);

mPaint = new Paint();

TypedArray mTypedArray = context.obtainStyledAttributes(attrs,R.styleable.MyView);
//获取自定义属性或默认值
roundColor = mTypedArray.getColor(R.styleable.MyView_roundColor, Color.RED);
roundProgressColor = mTypedArray.getColor(R.styleable.MyView_roundProgressColor,Color.GREEN);
textColor = mTypedArray.getColor(R.styleable.MyView_textColor,Color.GREEN);
textSize = mTypedArray.getDimension(R.styleable.MyView_textSize,15);
roundWidth = mTypedArray.getDimension(R.styleable.MyView_roundWidth,5);
max = mTypedArray.getInteger(R.styleable.MyView_max,100);
textIsDisplayable = mTypedArray.getBoolean(R.styleable.MyView_textIsDisplayable,true);
style = mTypedArray.getInt(R.styleable.MyView_style,0);

mTypedArray.recycle();
}

/*
重写onDraw是自定义View的关键
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

/*
* 画最外层的大圆环
* */
int centre = getWidth()/2;//圆心坐标
int radius = (int) (centre - roundWidth/2);//圆环半径
mPaint.setColor(roundColor);//设置圆环的颜色
mPaint.setStyle(Paint.Style.STROKE);//设置空心
mPaint.setStrokeWidth(roundWidth);//设置圆环的宽度
mPaint.setAntiAlias(true);//消除锯齿
canvas.drawCircle(centre,centre,radius,mPaint);//画出圆环

/*
* 画进度百分比
* */
mPaint.setStrokeWidth(0);//清楚上面的设置空心线宽
mPaint.setColor(textColor);//设置字体颜色
mPaint.setTextSize(textSize);//设置字体大小
mPaint.setTypeface(Typeface.DEFAULT_BOLD);//设置字体
int percent = (int) ((float)progress/(float)max*100);//中间的进度百分比,先转换成float在进行除法运算,不然都为0
float textWidth = mPaint.measureText(percent+"%");
if(textIsDisplayable && percent != 0 && style == STROKE){
canvas.drawText(percent + "%", centre - textWidth / 2, centre + textSize/2, mPaint); //画出进度百分比
}

/*
* 画圆弧,画圆环的进度
* */
//设置进度是实心还是空心
mPaint.setStrokeWidth(roundWidth);//设置圆环的宽度
mPaint.setColor(roundProgressColor);//设置进度的颜色
RectF oval = new RectF(centre-radius,centre-radius,centre+radius,centre+radius);//用于定义的圆弧的形状和大小的界限

/*
* STROKE:代表空心
* FILL:代表实心
* */
switch (style){
case STROKE:{
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawArc(oval,0,360*progress/max,false,mPaint);;
break;
}
case FILL:{
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
if(progress !=0)
canvas.drawArc(oval, 0, 360 * progress / max, true, mPaint);  //根据进度画圆弧
break;
}
}
}

public synchronized  int getMax(){
return max;
}

/*
* 设置进度的最大值
* @param max
* */
public synchronized void setMax(){
if(max < 0){
throw new IllegalArgumentException("max not less than 0");
}
this.max = max;
}

/*
* 获取进度,需要同步
* @return
* */
public synchronized int getProgress(){
return progress;
}

/**
* 设置进度,此为线程安全控件,由于考虑多线的问题,需要同步
* 刷新界面调用postInvalidate()能在非UI线程刷新
* @param progress
*/
public synchronized void setProgress(int progress) {
if(progress < 0){
throw new IllegalArgumentException("progress not less than 0");
}
if(progress > max){
progress = max;
}
if(progress <= max){
this.progress = progress;
postInvalidate();
}

}

public String getMy_text() {
return my_text;
}

public void setMy_text(String my_text) {
this.my_text = my_text;
}

public int getRoundColor() {
return roundColor;
}

public void setRoundColor(int roundColor) {
this.roundColor = roundColor;
}

public int getRoundProgressColor() {
return roundProgressColor;
}

public void setRoundProgressColor(int roundProgressColor) {
this.roundProgressColor = roundProgressColor;
}

public float getRoundWidth() {
return roundWidth;
}

public void setRoundWidth(float roundWidth) {
this.roundWidth = roundWidth;
}

public int getTextColor() {
return textColor;
}

public void setTextColor(int textColor) {
this.textColor = textColor;
}

public float getTextSize() {
return textSize;
}

public void setTextSize(float textSize) {
this.textSize = textSize;
}

public boolean isTextIsDisplayable() {
return textIsDisplayable;
}

public void setTextIsDisplayable(boolean textIsDisplayable) {
this.textIsDisplayable = textIsDisplayable;
}

public int getStyle() {
return style;
}

public void setStyle(int style) {
this.style = style;
}
public void init(){
mPaint = new Paint();
}
}

3.配置activity_main.xml
其中xmls:myview="com\example\administrator\defineviewbymyself\my_view"是定义MyView类的地方。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:myview="com\example\administrator\defineviewbymyself\my_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.administrator.defineviewbymyself.MainActivity">

<com.example.administrator.defineviewbymyself.my_view.MyView
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
4.MainActivity相关代码就补贴上来了。只需要把activity_main.xml关联进去即可。
最后实现效果

想要实现其他效果只需要在onDraw()方法设置即可
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: