最近研究自定义View,于是做了这个demo,供大家参考
参考了一位博主文章:http://blog.csdn.net/lilong85362952/article/details/41447967
自定义View的代码:
public class DrawView extends View implements ViewRefreshInterface, OnTouchListener {
private RectF rectF;
private List colors;
private List mList;
// 圆心
private Point point;
// 半径
private int radius = 0;
// view刷新
private int a = 0;
private int refeshAngle = 0;
private int number = 0;
private boolean isPause;
Thread thread = new Thread();
private ViewRefreshUtil viewRefreshUtil;
private ViewRefreshUtil.ViewRefreshInterfaceEntity viewRefreshInterface;
private ViewClickListener viewClickListener;
private Context mContext;
public DrawView(Context context) {
super(context);
init(context);
}
public DrawView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public DrawView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
@SuppressLint("ClickableViewAccessibility")
private void init(Context context) {
this.mContext = context;
colors = new ArrayList();
mList = new ArrayList();
colors.add(Color.RED);
colors.add(Color.GREEN);
colors.add(Color.BLUE);
colors.add(Color.YELLOW);
viewRefreshUtil = ViewRefreshUtil.getRefreshUtil();
viewRefreshInterface = viewRefreshUtil.addViewRefreshInterface(this);
this.setOnTouchListener(this);
DisplayMetrics dm = new DisplayMetrics();
((Activity) mContext).getWindowManager().getDefaultDisplay().getMetrics(dm);
isPause = false;
}
@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setAntiAlias(true);// 抗锯齿
paint.setStyle(Style.STROKE);// Style.FILL: 实心, STROKE:空心, FILL_OR_STROKE:同时实心与空心
// paint.setStrokeCap(Cap.ROUND);// 画笔样式:圆形 Cap.ROUND, 方形 Cap.SQUARE
// paint.setStrokeJoin(Join.ROUND);// 平滑效果
paint.setStrokeWidth(15);
// paint.setColor(Color.BLUE);
// canvas.drawLine(0, 50, 450, 50, paint);// 画线
// canvas.drawRect(0, 0, 20, 60, paint);// 画矩形
// canvas.drawCircle(100, 50, 50, paint);// 画圆
// canvas.drawOval(rectF, paint);// 画椭圆或者圆
a += 1;
refeshAngle += 1;
int temAngle = 0;
paint.setStyle(Style.FILL);
paint.setStrokeWidth(14);
for (int i = 0; i < number; i++) {
paint.setColor(colors.get(i));
temAngle += mList.get(i).getEndAngle() - mList.get(i).getStartAngle();
if (temAngle >= a) {
drawMyView(canvas, paint, rectF, mList.get(i).getStartAngle(), refeshAngle);
if (refeshAngle == mList.get(i).getEndAngle() - mList.get(i).getStartAngle()) {
refeshAngle = 0;
number = (number < mList.size()) ? number + 1 : mList.size();
}
} else {
drawMyView(canvas, paint, rectF, mList.get(i).getStartAngle(), Math.abs(mList.get(i).getEndAngle() - mList.get(i).getStartAngle()));
}
}
}
private void drawMyView(Canvas canvas, Paint paint, RectF rectF, int startAngle, int endAngle) {
paint.setStrokeJoin(Join.MITER);
paint.setStrokeCap(Cap.SQUARE);
canvas.drawArc(rectF, startAngle, endAngle, true, paint);
}
@SuppressLint("DrawAllocation")
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int measureWidth = getMeasureWH(widthMeasureSpec);
int measureHeigh = getMeasureWH(heightMeasureSpec);
if (measureWidth > measureHeigh) {
radius = measureHeigh / 2;
} else {
radius = measureWidth / 2;
}
if (getMeasuredWidth() != 0 && getMeasuredHeight() != 0) {
rectF = new RectF(0, 0, radius * 2, radius * 2);
// this.start();
}
if (measureWidth > measureHeigh) {
setMeasuredDimension(measureHeigh, measureHeigh);
} else {
setMeasuredDimension(measureWidth, measureWidth);
}
}
private int getMeasureWH(int measureSpec) {
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
return specSize;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
public void setData(List list) {
if (!viewRefreshInterface.isRefresh() && !isPause) {
this.mList = list;
this.number = 1;
// this.start();
}
}
public boolean isRefresh() {
return viewRefreshInterface.isRefresh();
}
// 开始
public void start() {
if (isPause) {
viewRefreshInterface.setRefresh(true);
viewRefreshUtil.startViewRefresh(viewRefreshInterface);
isPause = false;
}
if (!viewRefreshInterface.isRefresh()) {
viewRefreshInterface.setRefresh(true);
viewRefreshUtil.startViewRefresh(viewRefreshInterface);
isPause = false;
}
}
// 暂停
public void pause() {
if (viewRefreshInterface.isRefresh() && !isPause) {
viewRefreshInterface.setRefresh(false);
isPause = true;
}
}
// 停止
public void stop() {
viewRefreshInterface.setRefresh(false);
a = 0;
refeshAngle = 0;
number = 0;
init(mContext);
postInvalidate();
}
@Override
public void refresh() {
if (a >= 360) {
viewRefreshInterface.setRefresh(false);
} else {
postInvalidate();
}
}
@SuppressLint("DrawAllocation")
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
point = new Point((right - left) / 2 + left, (bottom - top) / 2 + top);
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_UP:
double x = Math.pow(point.x - event.getRawX(), 2);
double y = Math.pow(point.y - event.getRawY(), 2);
if (!viewRefreshInterface.isRefresh() && Math.sqrt(x + y) <= radius) {
int tanX = (int) Math.abs(event.getRawX() - point.x);
int tanY = (int) Math.abs(event.getRawY() - point.y);
double clickAngle = getangle(tanX, tanY, (int) event.getRawX() - point.x, point.y - (int) event.getRawY());
int mClickAngle = (int) clickAngle - 90;
for (int i = 0; i < mList.size(); i++) {
if (mClickAngle >= mList.get(i).getStartAngle() && mClickAngle <= mList.get(i).getEndAngle()) {
viewClickListener.clickListener(mList.get(i));
break;
}
}
}
break;
}
return true;
}
// 根据点击位置获取夹角
private double getangle(int x, int y, int downx, int downy) {
double angle = (float) 0.0;
if (downx > 0 && downy < 0) {
double c = (double) y / (double) x;
double d = Math.toDegrees(Math.atan(c));
angle = d + 90;
} else if (downx <= 0 && downy <= 0) {
double c = (double) x / (double) y;
double d = Math.toDegrees(Math.atan(c));
angle = d + 180;
} else if (downx < 0 && downy >= 0) {
double c = (double) y / (double) x;
double d = Math.toDegrees(Math.atan(c));
angle = d + 270;
} else {
double c = (double) x / (double) y;
double d = Math.toDegrees(Math.atan(c));
angle = d;
}
return angle;
}
public void setViewClickListenrt(ViewClickListener clickListener) {
this.viewClickListener = clickListener;
}
public interface ViewClickListener {
public void clickListener(SectorItem item);
}
}
这里有一些东西需要注意一下(这里不做详细说明):
1、当你在xml中为这个view设置margin属性的时候,在onLayout中获取的top,left,right,bottom的值都是你设置的2倍,所以再做一些计算时要注意,
2、在使用canvas.drawArc()方法画圆时,是以水平右方向顺时针画的,所以我在画圆的时候起始位置的角度为:-90,,竖直方向开始画圆,
3、onMeasure()这个方法在什么时候调用,调用几次,getMeasuredHeight()、getHeight()这两个方法区别,MeasureSpecMode()中几个不同Mode也是需要注意,
4、在画这个圆时,会有点慢,如果想改变速率,需要注意 refeshAngle 和 a 这两个参数,因为扇形时整数度数,我是一度一度慢慢绘制的,修改时需要注意
如果不需要慢慢绘制这个圆可以直接用for循环调用drawMyView(canvas, paint, rectF, mList.get(i).getStartAngle(), mList.get(i).getEndAngle());直接回执完整的圆,省去了 绘制的时间
ViewRefreshUtil代码:
public class ViewRefreshUtil implements Runnable {
private Thread thread;
private static ViewRefreshUtil viewRefreshUtil;
private ArrayList viewRefreshInterfaces;
public static ViewRefreshUtil getRefreshUtil() {
if (null == viewRefreshUtil) {
viewRefreshUtil = new ViewRefreshUtil();
}
return viewRefreshUtil;
}
private ViewRefreshUtil() {
viewRefreshInterfaces = new ArrayList();
}
public ViewRefreshInterfaceEntity addViewRefreshInterface(ViewRefreshInterface viewRefreshInterface) {
ViewRefreshInterfaceEntity viewRefreshInterfaceEntity = new ViewRefreshInterfaceEntity();
viewRefreshInterfaceEntity.setViewRefreshInterface(viewRefreshInterface);
viewRefreshInterfaces.add(viewRefreshInterfaceEntity);
return viewRefreshInterfaceEntity;
}
public void startViewRefresh(ViewRefreshInterfaceEntity viewRefreshInterfaceEntity) {
viewRefreshInterfaceEntity.setRefresh(true);
if (null == thread || !thread.isAlive()) {
thread = new Thread(this);
thread.start();
}
}
public void stopViewRefresh(ViewRefreshInterfaceEntity viewRefreshInterfaceEntity) {
viewRefreshInterfaceEntity.setRefresh(false);
}
public interface ViewRefreshInterface {
void refresh();
}
@Override
public void run() {
int i = 1;
while (i != 0) {
i=0;
for (ViewRefreshInterfaceEntity viewRefreshInterfaceEntity : viewRefreshInterfaces) {
if (viewRefreshInterfaceEntity.isRefresh()) {
viewRefreshInterfaceEntity.getViewRefreshInterface().refresh();
i++;
}
}
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class ViewRefreshInterfaceEntity {
private boolean isRefresh = false;
private ViewRefreshInterface viewRefreshInterface;
public boolean isRefresh() {
return isRefresh;
}
public void setRefresh(boolean isRefresh) {
this.isRefresh = isRefresh;
}
public ViewRefreshInterface getViewRefreshInterface() {
return viewRefreshInterface;
}
public void setViewRefreshInterface(ViewRefreshInterface viewRefreshInterface) {
this.viewRefreshInterface = viewRefreshInterface;
}
}
}
public class SectorItem implements Serializable {
private int startAngle;
private int endAngle;
private String name;
public int getStartAngle() {
return startAngle;
}
public void setStartAngle(int startAngle) {
this.startAngle = startAngle;
}
public int getEndAngle() {
return endAngle;
}
public void setEndAngle(int endAngle) {
this.endAngle = endAngle;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
mainactivity代码:
public class MainActivity extends Activity implements OnClickListener {
private DrawView drawView;
private Button start, pause, stop;
private List list;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
drawView = (DrawView) findViewById(R.id.dv);
start = (Button) findViewById(R.id.start);
pause = (Button) findViewById(R.id.pause);
stop = (Button) findViewById(R.id.stop);
start.setOnClickListener(this);
pause.setOnClickListener(this);
stop.setOnClickListener(this);
drawView.setViewClickListenrt(new ViewClickListener() {
@Override
public void clickListener(SectorItem item) {
Toast.makeText(MainActivity.this, "You Click :" + item.getName() + " Area !", Toast.LENGTH_SHORT).show();
}
});
}
private void initData() {
list = new ArrayList();
SectorItem item = new SectorItem();
item.setStartAngle(-90);
item.setEndAngle(0);
item.setName("Red");
list.add(item);
item = new SectorItem();
item.setStartAngle(0);
item.setEndAngle(80);
item.setName("Green");
list.add(item);
item = new SectorItem();
item.setStartAngle(80);
item.setEndAngle(150);
item.setName("BLUE");
list.add(item);
item = new SectorItem();
item.setStartAngle(150);
item.setEndAngle(270);
item.setName("YELLOW");
list.add(item);
drawView.setData(list);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (drawView.isRefresh()) {
drawView.stop();
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.start:
initData();
drawView.start();
break;
case R.id.pause:
drawView.pause();
break;
case R.id.stop:
drawView.stop();
break;
}
}
}
mainactivity 的布局:
功能很简单,进入页面,点击start按钮开始竖直顺时针方向画圆,圆内有四种不同颜色的扇形,点击pause按钮暂停画圆,点击stop按钮停止画圆并清空view,当我们点击圆内不同颜色的扇形时,用Toast打印我们点击的扇形的颜色
最后,未经允许禁止转载