美文网首页
自定义控件之五维图

自定义控件之五维图

作者: shada | 来源:发表于2016-07-09 18:51 被阅读426次

    先看效果

    Paste_Image.png

    做起来很简单。就是用三角函数,算出五边形五个定点的坐标,然后根据左边连线就行了。根据看图。

    images.png

    具体代码如下:

      class FiveDimensionView extends View {
        private Paint pentagonPaint;
        private Paint coverPaint;
        private TextPaint textPaint;
        private Path path;
        private Entity entity;
        private float distance;
        private Path coverPath;
        public FiveDimensionView(Context context) {
            this(context,null);
        }
        public FiveDimensionView(Context context, AttributeSet attrs) {
            this(context, attrs,0);
        }
        public FiveDimensionView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.FiveDimensionView);
            //五边形边的宽度
            float pentagonWidth=array.getDimension(R.styleable.FiveDimensionView_pentagon_width,dp2px(1));
            //五边形边的颜色
            int pentagonColor=array.getColor(R.styleable.FiveDimensionView_pentagon_color, Color.RED);
            //覆盖区域的颜色
            int coverColor=array.getColor(R.styleable.FiveDimensionView_cover_color,Color.BLUE); 
           //字体颜色
            int textColor=array.getColor(R.styleable.FiveDimensionView_text_color,Color.BLACK);
            //字体大小
            float textSize=array.getDimension(R.styleable.FiveDimensionView_text_size,13);
            //字体距离五边形顶点的长度
            distance = array.getDimension(R.styleable.FiveDimensionView_text_distance,dp2px(5));
            array.recycle();
            //正五边形
            pentagonPaint = new Paint();
            pentagonPaint.setAntiAlias(true);
            pentagonPaint.setColor(pentagonColor);
            pentagonPaint.setStyle(Paint.Style.STROKE);
            pentagonPaint.setStrokeWidth(pentagonWidth);
            //覆盖区域
            coverPaint = new Paint();
            coverPaint.setAntiAlias(true);
            coverPaint.setStyle(Paint.Style.FILL_AND_STROKE);
            coverPaint.setColor(coverColor);
            //文字
            textPaint = new TextPaint();
            textPaint.setColor(textColor);
            textPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,textSize,context.getResources().getDisplayMetrics()));
            textPaint.setAntiAlias(true);
            path = new Path();
            coverPath = new Path();
        } 
       @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int widthSize=MeasureSpec.getSize(widthMeasureSpec);
            int widthMode=MeasureSpec.getMode(widthMeasureSpec);
            int heightSize=MeasureSpec.getSize(heightMeasureSpec);
            int heightMode=MeasureSpec.getMode(heightMeasureSpec);
            int width=0,height=0;
            if(widthMode==MeasureSpec.AT_MOST){
                width=dp2px(250);
            }else{
                width=widthSize;
            }
            if(heightMode==MeasureSpec.AT_MOST){
                height=dp2px(250);
            }else{
                height=heightSize;
            } 
           setMeasuredDimension(width,height);
        }
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            //半径
            float radius=Math.min(getWidth(),getHeight())/2*0.8f;
            canvas.save();
            //原点移至当前view的中心
            canvas.translate(getWidth()/2,getHeight()/2);
            List<PointF> points = getPoints(radius);
            //绘制五边形边
            for(int i = 0; i< points.size(); i++){
                PointF pointF = points.get(i);
                if(i==0){
                    path.moveTo(pointF.x,pointF.y);
                }else{
                    path.lineTo(pointF.x,pointF.y);
                }
            }
            path.close();
            canvas.drawPath(path,pentagonPaint);
            //绘制圆心和顶点的连线
            for(PointF pointF:points){
                path.moveTo(0,0);
                path.lineTo(pointF.x,pointF.y);
                canvas.drawPath(path,pentagonPaint);
                path.reset();
            }
            if(entity==null){
                entity=new Entity();
                entity.setTotal(1);
                List<DisEntity>list=new ArrayList<>();
                list.add(new DisEntity("第一",0));
                list.add(new DisEntity("第二",0)); 
                list.add(new DisEntity("第三",0));
                list.add(new DisEntity("第四",0));
                list.add(new DisEntity("第五",0));
                entity.setList(list);
            }
            List<DisEntity> list = entity.getList();
            //绘制覆盖区域
            for(int i = 0; i< points.size(); i++){
                PointF pointF = points.get(i);
                float rate=list.get(i).getScore()*1.0f/entity.getTotal();
                if(i==0){
                    coverPath.moveTo(pointF.x*rate,pointF.y*rate);
                }else{
                    coverPath.lineTo(pointF.x*rate,pointF.y*rate);
                }
            }
            coverPath.close();
            canvas.drawPath(coverPath,coverPaint);
            //绘制文字
            for (int i=0;i<points.size();i++){
                PointF pointF = points.get(i);
                String title = list.get(i).getTitle();
                Rect bounds = new Rect();
                //获取字体宽高
                textPaint.getTextBounds(title,0,title.length(),bounds);
                float textWidth = bounds.width();
                int textHeight= bounds.height();
                switch (i){
                    case 0:
                        canvas.drawText(title,pointF.x-textWidth/2,pointF.y-distance,textPaint);
                        break;
                    case 1:
                        canvas.drawText(title,pointF.x+distance,pointF.y+textHeight/2,textPaint);
                        break;
                    case 2:
                        canvas.drawText(title,pointF.x+distance-textWidth/2,pointF.y+distance+textHeight,textPaint);                    break;
                    case 3:
                        canvas.drawText(title,pointF.x-distance-textWidth/2,pointF.y+textHeight+distance,textPaint);
                        break;
                    case 4:
                        canvas.drawText(title,pointF.x-distance-textWidth,pointF.y+textHeight/2,textPaint);
                        break;
                }
            }
            canvas.restore();
        }
        //获取正五边形五个顶点
        private List<PointF> getPoints(float radius){
            List<PointF>points=new ArrayList<>();
            points.add(new PointF(0,-radius));//第0个点
            //第1个点
            points.add(new PointF((float)(radius*Math.cos(Math.toRadians(18))),-(float)(radius*Math.sin(Math.toRadians(18)))));
            //第2个点
            points.add(new PointF((float)(radius*Math.sin(Math.toRadians(36))),(float)(radius*Math.cos(Math.toRadians(36)))));
            //第3个点
            points.add(new PointF((float)(-radius*Math.sin(Math.toRadians(36))),(float)(radius*Math.cos(Math.toRadians(36)))));
            //第4个点
            points.add(new PointF((float)(-radius*Math.cos(Math.toRadians(18))),-(float)(radius*Math.sin(Math.toRadians(18)))));
            return points;
        }
        public Entity getEntity() {
            return entity;
        }
        public void setEntity(Entity entity) {
            this.entity = entity;
            invalidate();
        }
        private int dp2px(int dp){
            return (int) (getContext().getResources().getDisplayMetrics().density*dp+0.5);
        }
    }
    

    代码中用到的实体类

    public class Entity {
        //集合中是顶点上文字和文字所对应的分数
        private List<DisEntity> list;
        //total是总分,根据分数和总分的比值,得到覆盖区域的顶点
        private int total;
        public List<DisEntity> getList() {
            return list;
        }
        public void setList(List<DisEntity> list) {
            this.list = list;
        }
        public int getTotal() {
            return total;
        } 
       public void setTotal(int total) {
            this.total = total;
        }
    }
    
    public class DisEntity {
        private String title;
        private int score;
        public DisEntity(String title, int score) {
            this.title = title;
            this.score = score;
        }
        public String getTitle() {
            return title;
        } 
       public void setTitle(String title) {
            this.title = title;
        }
        public int getScore() {
            return score;
        }
        public void setScore(int score) {
            this.score = score;
        }
    }
    

    自定义控件在布局中的使用

    <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:app="http://schemas.android.com/apk/res-auto"
        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="example.com.dimensionview.MainActivity">
       <example.com.dimensionview.FiveDimensionView
           android:id="@+id/five"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"/>
    </RelativeLayout>
    
    public class MainActivity extends AppCompatActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            FiveDimensionView five= (FiveDimensionView)findViewById(R.id.five);
            Entity entity=new Entity();
            entity.setTotal(10);
            List<DisEntity>list=new ArrayList<>();
            list.add(new DisEntity("第1",4));
            list.add(new DisEntity("第2",5));
            list.add(new DisEntity("第3",6));
            list.add(new DisEntity("第4",7));
            list.add(new DisEntity("第5",8));
            entity.setList(list);
            five.setEntity(entity);    }}
    

    自定义属性

      <declare-styleable name="FiveDimensionView">
        <attr name="pentagon_width" format="dimension"></attr> 
       <attr name="pentagon_color" format="color"></attr>
        <attr name="cover_color" format="color"></attr>
        <attr name="text_size" format="dimension"></attr>
        <attr name="text_color" format="color"></attr>
        <attr name="text_distance" format="dimension"></attr>
    </declare-styleable>
    

    相关文章

      网友评论

          本文标题:自定义控件之五维图

          本文链接:https://www.haomeiwen.com/subject/ntzrjttx.html