android自定义view----等分饼图,实现每个块中间的间隔
2016-04-25 14:58
585 查看
android自定义view—-等分饼图,实现每个块中间的间隔
android 饼图使用比较广泛,本图是个等分饼图,各位有哪里需要用的请拿去随意用,先上图:首先看核心代码PieView
使用到画扇形的apicanvas.drawArc(rect,startAngle, angle, true, arcPaint),rect为圆的外接矩形,startAngle扇形开始角度,angle扇形角度,true为画的为扇形,arcPaint画笔;使用画布移动api,canvas.save();保存画布,保存完以后可以移动或放大缩小或旋转画布等等,本文中使用了平移画布,并且是根据一定的角度移动,最后在执行canvas.restore();还原画布;
package biz.com.piedemo; import android.annotation.TargetApi; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PointF; import android.graphics.RectF; import android.os.Build; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import java.util.List; /** * Created by cmc on 2015/12/3. */ public class PieView extends View { private int normalColor = Color.rgb(240,240,240); private int selectColor = Color.GREEN; private int normalTextColor = Color.GRAY; private int selectTextColor = Color.WHITE; private int circleColor = Color.WHITE; private Paint arcPaint; private Paint textPaint; private int selectPosition = 1; private PointF circle; private List<Data> list; private OnItemSelectListener onItemSelectListener; public PieView(Context context) { super(context); } public void setOnItemSelectListener(OnItemSelectListener onItemSelectListener) { this.onItemSelectListener = onItemSelectListener; } public List<Data> getList() { return list; } /** * 设置饼图数据、显示文字,图片 * @param list */ public void setList(List<Data> list) { this.list = list; } public void setSelectTextColor(int selectTextColor) { this.selectTextColor = selectTextColor; } public void setNormalTextColor(int normalTextColor) { this.normalTextColor = normalTextColor; } public void setSelectColor(int selectColor) { this.selectColor = selectColor; } public void setNormalColor(int normalColor) { this.normalColor = normalColor; } public PieView(Context context, AttributeSet attrs) { this(context, attrs, -1); } public PieView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.pieView); int count = ta.getIndexCount(); for(int i = 0;i<count;i++){ int index = ta.getIndex(i); switch (index){ case R.styleable.pieView_normal_color: normalColor = ta.getColor(i,Color.rgb(240,240,240)); break; case R.styleable.pieView_select_color: selectColor = ta.getColor(i,Color.GREEN); break; case R.styleable.pieView_normal_text_color: normalTextColor = ta.getColor(i,Color.GRAY); break; case R.styleable.pieView_select_text_color: selectTextColor = ta.getColor(i,Color.WHITE); break; case R.styleable.pieView_circle_color: circleColor = ta.getColor(i,Color.WHITE); break; } } init(); } private void init() { arcPaint = new Paint(); arcPaint.setAntiAlias(true); textPaint = new Paint(); textPaint.setAntiAlias(true); textPaint.setTextAlign(Paint.Align.CENTER); textPaint.setTextSize(28); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public PieView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //确定中心点 circle = new PointF(getWidth()/2f,getHeight()/2f); //确定圆半径 取高和宽小的一部分作为直径 float min = getHeight()>getWidth()?getWidth():getHeight(); //减20作为拉开间距 float arcRadio = min/2f-20; //圆的外接矩形 RectF rect = new RectF(circle.x-arcRadio,circle.y-arcRadio,circle.x+arcRadio,circle.y+arcRadio); if(list!=null&&list.size()>0) { for (int i = 0; i < list.size(); i++) { String title = ""; int bitmapReId = R.mipmap.ic_launcher; Data date = list.get(i); if (date.name != null) title = date.name; //设置选中改变图标和字体颜色 if (i == selectPosition) { textPaint.setColor(selectTextColor); arcPaint.setColor(selectColor); if (date.selectDrawbleId != 0) bitmapReId = date.selectDrawbleId; } else { arcPaint.setColor(normalColor); textPaint.setColor(normalTextColor); if (date.drawableID != 0) bitmapReId = date.drawableID; } //按角度移动画布,确定间隙 canvas.save(); //按角度移动画布, canvas.translate((float) (Math.sin((180/list.size() + 360/list.size() * i) * Math.PI / 180) * 10), -(float) (10 * Math.cos((180/list.size() + 360/list.size() * i) * Math.PI / 180))); canvas.drawArc(rect, 270 + 360/list.size() * i, 360/list.size(), true, arcPaint); canvas.restore(); canvas.save(); canvas.translate((float) (Math.sin((180/list.size() + 360/list.size() * i) * Math.PI / 180) * arcRadio / 1.5), -(float) (arcRadio / 1.5 * Math.cos((180/list.size() + 360/list.size() * i) * Math.PI / 180))); Bitmap bit = BitmapFactory.decodeResource(getResources(), bitmapReId); canvas.drawBitmap(bit, circle.x - bit.getWidth() / 2, circle.y - bit.getHeight(), arcPaint); canvas.drawText(title, circle.x, circle.y + 28, textPaint); canvas.restore(); } } //画中心圆 arcPaint.setColor(circleColor); canvas.drawCircle(circle.x, circle.y, arcRadio / 2.5f, arcPaint); } /** * 百度查到别人写的一个方法,在我多个饼图中都有使用这个方法,确认无误 * @param radiusX 圆心 * @param radiusY 圆心 * @param x1 触摸点 * @param y1 触摸点 * @return * @throws * @Title: getTouchedPointAngle * @Description: 计算触摸角度 */ private float getTouchedPointAngle(float radiusX, float radiusY, float x1, float y1) { float differentX = x1 - radiusX; float differentY = y1 - radiusY; double a = 0.0D; double t = differentY / Math.sqrt(differentX * differentX + differentY * differentY); if (differentX > 0.0F) { // 0~90 if (differentY > 0.0F) a = 6.283185307179586D - Math.asin(t); else // 270~360 a = -Math.asin(t); } else if (differentY > 0.0F) // 90~180 a = 3.141592653589793D + Math.asin(t); else { // 180~270 a = 3.141592653589793D + Math.asin(t); } return (float) (360.0D - a * 180.0D / 3.141592653589793D % 360.0D); } @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); float y = event.getY(); float cx = circle.x; float cy = circle.y; float r = getHeight(); float r1 = (float) ((getHeight()/2f-20)/2.5); switch (event.getAction()){ case MotionEvent.ACTION_DOWN: if ((x - cx) * (x - cx) + (y - cy) * (y - cy) - r * r <= 0.0F && (x - cx) * (x - cx) + (y - cy) * (y - cy) - r1 * r1 >= 0.0F) { selectPosition = getSelectPosition(getTouchedPointAngle(cx,cy,x,y)); if(onItemSelectListener!=null) onItemSelectListener.selectPosition(selectPosition,this); invalidate(); } break; } return super.onTouchEvent(event); } private int getSelectPosition(float touchedPointAngle) { Log.i("TAG",touchedPointAngle+""); //当为4块及以下时,第一块的范围为270-360+所以加上一下代码 if(list.size()<=4){ if(touchedPointAngle>270||touchedPointAngle<=(270+360/list.size())%360){ return 0; } } for(int i = 0;i<list.size();i++){ if(touchedPointAngle>(270+i*360/list.size())%360&&touchedPointAngle<=(270+(i+1)*360/list.size())%360){ return i; } } return 1; } public static class Data { public Data() { } public Data(String name, int drawableID, int selectDrawbleId) { this.name = name; this.drawableID = drawableID; this.selectDrawbleId = selectDrawbleId; } public String name; public int drawableID; public int selectDrawbleId; } public interface OnItemSelectListener{ void selectPosition(int position,PieView pieView); } }
再看layout代码
<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" xmlns:pieview="http://schemas.android.com/apk/res-auto" tools:context=".MainActivity"> <biz.com.piedemo.PieView android:id="@+id/pv" android:layout_width="match_parent" android:background="#ff0000" pieview:select_color="#0000ff" pieview:normal_color="#dddddd" pieview:normal_text_color="#0570E9" pieview:select_text_color="#ffffff" pieview:circle_color="#ffffff" android:layout_height="300dp" /> </RelativeLayout>
actvity代码
public class MainActivity extends ActionBarActivity { private PieView pv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); pv = (PieView) findViewById(R.id.pv); List<PieView.Data> list = new ArrayList<>(); list.add(new PieView.Data("第一块",R.mipmap.icon_normal,R.mipmap.icon_select)); list.add(new PieView.Data("第二块",R.mipmap.icon_normal,R.mipmap.icon_select)); list.add(new PieView.Data("第三块",R.mipmap.icon_normal,R.mipmap.icon_select)); list.add(new PieView.Data("第四块",R.mipmap.icon_normal,R.mipmap.icon_select)); list.add(new PieView.Data("第五块", R.mipmap.icon_normal,R.mipmap.icon_select)); // list.add(new PieView.Data("第六块", R.mipmap.icon_normal,R.mipmap.icon_select)); // list.add(new PieView.Data("第七块", R.mipmap.icon_normal,R.mipmap.icon_select)); // list.add(new PieView.Data("第八块", R.mipmap.icon_normal,R.mipmap.icon_select)); pv.setList(list); pv.setOnItemSelectListener(new PieView.OnItemSelectListener() { @Override public void selectPosition(int position, PieView pieView) { if (pieView.getList() != null) Toast.makeText(MainActivity.this, pieView.getList().get(position).name, Toast.LENGTH_SHORT).show(); } }); } }
代码下载链接
相关文章推荐
- Android关于OnTouch 和OnClick同时调用冲突的解决方案
- Android继承现有控件拓展实现自定义控件textView
- Android开发内存泄露之--Handler引起的内存泄露
- Android proguard遇到的若干问题以及解决思路
- ClassCastException: android.widget.LinearLayout$LayoutParams cannot be cast to android.widget.AbsLis
- Android POI 百度地图——周边检索
- Android studio Error:Plugin with id 'com.github.dcendents.android-maven' not found
- Android如何保证数据加载下一页确定当前listview的位置
- Android-Charts,Android图形图表控件
- Android保存ArrayList至SharedPreferences
- Android之玩转MPAndroidChart让(折线图、柱形图、饼状图、散列图、雷达图)优雅的舞动
- Android Scroll滑动效果实例
- 实用Jacoco代码覆盖率Android集成与使用
- Cordova6.1、ionic、android交互自定义插件
- Android启动过程深入解析
- Android Studio AIDL 自定义类型找不到问题
- Android 65K问题之Multidex原理分析及NoClassDefFoundError的解决方法
- 运行android时Unable to resolve target 'Google Inc.:Google APIs:7'错误
- android log分析
- Chromebook 也许很快就能运行所有的 Android 应用