很多时候,Android提供的控件不能满足我们所需要的显示效果,就需要复写onDraw方法,使用canvas等进行绘制,假设进入一个界面时,需要展示某三个项目的收入所占的比重,并且需要一个从顶部开始顺时针方向绘制的动画效果,下边是这个统计图案在显示过程中的截图:
很明显,这个时候,就需要通过绘制的方式来自定义控件了,代码比较简单,直接上:
自定义的IncomeDistributionView:
public class IncomeDistributionView extends View {
private Paint mPaint= null;
private RectF mRectF;
private int paintWidth;
private int drawFlag = 0;
private int oneRadian;
private int twoRadian;
public IncomeDistributionView(Context context) {
super(context);
}
public IncomeDistributionView(Context context, AttributeSet attrs) {
super(context, attrs);
initPaint();
}
private void initPaint() {
//统一设置画笔的宽度和样式
mPaint= new Paint();
paintWidth = dip2px(getContext(), 24);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(paintWidth);
mRectF = new RectF(dip2px(getContext(), 12), dip2px(getContext(), 12),
dip2px(getContext(), 218), dip2px(getContext(), 218));
}
public IncomeDistributionView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@SuppressLint("WrongCall")
@Override
protected void onDraw(final Canvas canvas) {
super.onDraw(canvas);
if(drawFlag>=0 && drawFlag<oneRadian){
mPaint.setColor(getResources().getColor(R.color.total_order_image_consulting));// 设置颜色
canvas.drawArc(mRectF, 270, drawFlag, false, mPaint);
}else if(drawFlag>=oneRadian && drawFlag <twoRadian){
mPaint.setColor(getResources().getColor(R.color.total_order_image_consulting));
canvas.drawArc(mRectF, 270, oneRadian, false, mPaint);
mPaint.setColor(getResources().getColor(R.color.total_order_telephone_consultation));
//此处的 270+oneRadian 是临时写的,这是不准确的,需要考虑 这个值大于360的情况
canvas.drawArc(mRectF, 270+oneRadian, drawFlag-oneRadian, false, mPaint);
}else if(drawFlag>=twoRadian && drawFlag <=360){
mPaint.setColor(getResources().getColor(R.color.total_order_image_consulting));
canvas.drawArc(mRectF, 270, oneRadian, false, mPaint);
mPaint.setColor(getResources().getColor(R.color.total_order_telephone_consultation));
canvas.drawArc(mRectF, 270+oneRadian, twoRadian-oneRadian, false, mPaint);
mPaint.setColor(getResources().getColor(R.color.total_order_video_consultation));
canvas.drawArc(mRectF,270+twoRadian-360, drawFlag-twoRadian, false, mPaint);
}
}
/**
* 重绘过程中的偏移角度
* @param i
*/
public void startDraw(int i) {
drawFlag = i;
}
/**
* 设置绘制起点角度
* @param radianOne
* @param radianTwo
*/
public void setDemarcation(int radianOne,int radianTwo){
oneRadian = radianOne;
twoRadian = radianTwo;
}
public static int dip2px(Context context, float dipValue) {
float ret = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dipValue, context.getResources().getDisplayMetrics());
return (int) (ret + 0.5f);
}
}
需要使用自定义view的MainActivity:
public class MainActivity extends Activity {
private IncomeDistributionView mIncomeDistributionView= null;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
mIncomeDistributionView.startDraw(msg.what);
mIncomeDistributionView.invalidate();
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
findView();
}
private void findView() {
mIncomeDistributionView = (IncomeDistributionView) findViewById(R.id.view_income_distribution);
//该逻辑只为演示效果,作用是得到两个百分比数字,进而得到对应的弧度值
int radianOne = 72;
int radianTwo = 252;
//则
mIncomeDistributionView.setDemarcation(radianOne, radianTwo);
new Thread(){
public void run() {
int i = 0;
try {
sleep(200);
while(i<=360){
mHandler.sendEmptyMessage(i);
i+=1;
sleep(3);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
在activity_main.xml文件中进行引入:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.hwgt.statisticalchart.MainActivity" >
<com.hwgt.statisticalchart.view.IncomeDistributionView
android:id="@+id/view_income_distribution"
android:layout_width="230dp"
android:layout_height="230dp"
android:layout_marginTop="23dp"
android:layout_centerHorizontal="true"
android:layout_alignParentTop="true"/>
</RelativeLayout>
逻辑还是比较简单的,首先是设定统计图案中三个颜色区域的分界点,然后,处理handler发送的消息调用invalidate方法进行重绘。