zoukankan      html  css  js  c++  java
  • Android打造带透明圆弧的ImageView

      这几天因为项目需求,需要在ImageView上面叠加一层透明圆弧,并且在沿着圆弧的方向显示相应的文字,效果如下图所示:

      拿到这个需求,首先想到的是自定义一个ImageView来实现此功能,即在onDraw()中绘制圆弧和文字。同时因为要保证圆弧的位置可以任意摆放,圆弧的颜色、透明度以及文字大小、颜色等都是可控的,所以增加了一些自定义属性。实现代码非常简单,如下:

    1.自定义ImageView:

      1 package com.chunk.customviewsdemo.views.ArcImageView;
      2 
      3 import android.content.Context;
      4 import android.content.res.TypedArray;
      5 import android.graphics.Canvas;
      6 import android.graphics.Paint;
      7 import android.graphics.Path;
      8 import android.graphics.RectF;
      9 import android.util.AttributeSet;
     10 import android.widget.ImageView;
     11 
     12 import com.chunk.customviewsdemo.R;
     13 
     14 /**
     15  * Description:A custom ImageView with circular arc and text
     16  * Author: XiaoYu
     17  * Date: 2016/5/10 13:55
     18  */
     19 public class ArcImageView extends ImageView {
     20     /**
     21      * The default text size.
     22      */
     23     private final float DEFAULT_TEXT_SIZE = 20;
     24     /**
     25      * The default scale value which decides the width of arc.
     26      */
     27     private final float DEFAULT_SCALE = 0.5f;
     28     /**
     29      * The default transparency of arc.
     30      */
     31     private final int DEFAULT_ARC_ALPHA =100;
     32     /**
     33      * The default width of arc.
     34      */
     35     private final int DEFAULT_ARC_WIDTH =160;
     36     /**
     37      * The default angle that the arc starts with.
     38      */
     39     private final int DEFAULT_START_ANGLE = 180;
     40     /**
     41      * The default angle that the arc.
     42      */
     43     private final int DEFAULT_SWEEP_ANGLE = 90;
     44     /**
     45      * The default distance along the path to add to the text's starting position.
     46      */
     47     private final int DEFAULT_H_OFFSET = 100;
     48     /**
     49      * The default distance above(-) or below(+) the path to position the text.
     50      */
     51     private final int DEFAULT_V_OFFSET = 20;
     52     private Context mContext;
     53     /**
     54      * The text displayed on ImageView along arc.
     55      */
     56     private String mDrawStr;
     57     /**
     58      * The font size of text.
     59      */
     60     private float mTextSize = DEFAULT_TEXT_SIZE;
     61     /**
     62      * The scale value which decides the width of arc.
     63      */
     64     private float mScale = DEFAULT_SCALE;
     65     /**
     66      * The transparency of arc.
     67      */
     68     private int mArcAlpha = DEFAULT_ARC_ALPHA;
     69     /**
     70      * The width of arc.
     71      */
     72     private int mArcWidth = DEFAULT_ARC_WIDTH;
     73     /**
     74      * The start angle of angle.
     75      */
     76     private int mStartAngle = DEFAULT_START_ANGLE;
     77     /**
     78      * The swept angle of angle.
     79      */
     80     private int mSweepAngle = DEFAULT_SWEEP_ANGLE;
     81     /**
     82      * The default distance along the path to add to the text's starting position.
     83      */
     84     private float mHOffset = DEFAULT_H_OFFSET;
     85     /**
     86      * The default distance above(-) or below(+) the path to position the text.
     87      */
     88     private float mVOffset = DEFAULT_V_OFFSET;
     89     /**
     90      * The style of arc, all styles includes LEFT_TOP, LEFT_BOTTOM, RIGHT_TOP, RIGHT_BOTTOM, CENTER。
     91      * of course, you can add your own style according to your demands.
     92      */
     93     private int mDrawStyle;
     94     /**
     95      * The color of arc.
     96      */
     97     private int mArcColor;
     98     /**
     99      * The color of text.
    100      */
    101     private int mTextColor;
    102 
    103     public ArcImageView(Context context) {
    104         super(context);
    105         this.mContext = context;
    106     }
    107 
    108     public ArcImageView(Context context, AttributeSet attrs) {
    109         super(context, attrs);
    110         this.mContext = context;
    111         obtainAttributes(attrs);
    112     }
    113 
    114     public ArcImageView(Context context, AttributeSet attrs, int defStyleAttr) {
    115         super(context, attrs, defStyleAttr);
    116         this.mContext = context;
    117         obtainAttributes(attrs);
    118     }
    119 
    120     /**
    121      * Set the text that will be drawn on arc.
    122      * @param drawStr the text content.
    123      */
    124     public void setDrawStr(String drawStr) {
    125         this.mDrawStr = drawStr;
    126         //refresh this view
    127         invalidate();
    128     }
    129 
    130     /**
    131      * Set the transparency of arc.
    132      * @param mArcAlpha the value of transparency.
    133      */
    134     public void setArcAlpha(int mArcAlpha) {
    135         this.mArcAlpha = mArcAlpha;
    136         //refresh this view
    137         invalidate();
    138     }
    139 
    140     @Override
    141     protected void onDraw(Canvas canvas) {
    142         super.onDraw(canvas);
    143         //draw arc
    144         Paint arcPaint = new Paint();
    145         arcPaint.setStrokeWidth(mArcWidth);
    146         arcPaint.setStyle(Paint.Style.STROKE);
    147         arcPaint.setColor(mArcColor);
    148         arcPaint.setAlpha(mArcAlpha);
    149         int width = getWidth();
    150         int height = getHeight();
    151         float radius;
    152         if (width > height) {
    153             radius = mScale * height;
    154         } else {
    155             radius = mScale * width;
    156         }
    157         RectF oval = new RectF();
    158 
    159         int center_x = width;
    160         int center_y = height;
    161 
    162         switch (mDrawStyle) {
    163             case 0:
    164                 center_x = 0;
    165                 center_y = 0;
    166                 mStartAngle = 90;
    167                 mSweepAngle = -90;
    168                 break;
    169             case 1:
    170                 center_x = 0;
    171                 center_y = height;
    172                 mStartAngle = 270;
    173                 mSweepAngle = 90;
    174                 break;
    175             case 2:
    176                 center_x = width;
    177                 center_y = 0;
    178                 mStartAngle = 180;
    179                 mSweepAngle = -90;
    180                 break;
    181             case 3:
    182                 center_x = width;
    183                 center_y = height;
    184                 mStartAngle = 180;
    185                 mSweepAngle = 90;
    186                 break;
    187             case 4:
    188                 center_x = width / 2;
    189                 center_y = height / 2;
    190                 mStartAngle = 270;
    191                 mSweepAngle = 90;
    192                 break;
    193         }
    194         float left = center_x - radius;
    195         float top = center_y - radius;
    196         float right = center_x + radius;
    197         float bottom = center_y + radius;
    198         oval.set(left, top, right, bottom);
    199         canvas.drawArc(oval, mStartAngle, mSweepAngle, false, arcPaint);
    200 
    201         //draw text
    202         Paint textPaint = new Paint();
    203         textPaint.setTextSize(mTextSize);
    204         textPaint.setStyle(Paint.Style.FILL);
    205         textPaint.setColor(mTextColor);
    206         Path path = new Path();
    207         path.addArc(oval, mStartAngle, mSweepAngle);
    208         canvas.drawTextOnPath(mDrawStr, path, mHOffset, mVOffset, textPaint);
    209     }
    210 
    211     /**
    212      * Obtain custom attributes that been defined in attrs.xml.
    213      * @param attrs A collection of attributes.
    214      */
    215     private void obtainAttributes(AttributeSet attrs) {
    216         TypedArray ta = mContext.obtainStyledAttributes(attrs, R.styleable.ArcImageView);
    217         mDrawStr = ta.getString(R.styleable.ArcImageView_drawStr);
    218         mTextSize = ta.getDimension(R.styleable.ArcImageView_textSize, DEFAULT_TEXT_SIZE);
    219         mArcAlpha = ta.getInteger(R.styleable.ArcImageView_arcAlpha, DEFAULT_ARC_ALPHA);
    220         mArcWidth = ta.getInteger(R.styleable.ArcImageView_arcWidth, DEFAULT_ARC_WIDTH);
    221         mStartAngle = ta.getInteger(R.styleable.ArcImageView_startAngle, DEFAULT_START_ANGLE);
    222         mSweepAngle = ta.getInteger(R.styleable.ArcImageView_startAngle, DEFAULT_SWEEP_ANGLE);
    223         mHOffset = ta.getInteger(R.styleable.ArcImageView_hOffset, DEFAULT_H_OFFSET);
    224         mVOffset = ta.getInteger(R.styleable.ArcImageView_vOffset, DEFAULT_V_OFFSET);
    225         mArcColor = ta.getColor(R.styleable.ArcImageView_arcColor, 0XCCCCCC);
    226         mTextColor = ta.getColor(R.styleable.ArcImageView_textColor, 0XFFFFFF);
    227         mDrawStyle = ta.getInt(R.styleable.ArcImageView_drawStyle, 0);
    228         ta.recycle();
    229     }
    230 }

    2.在values文件夹下的attrs.xml中自定义属性:

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <resources>
     3     <declare-styleable name="ArcImageView">
     4         <attr name="drawStr" format="string" />
     5         <attr name="textSize" format="dimension" />
     6         <attr name="arcAlpha" format="integer" />
     7         <attr name="arcWidth" format="integer" />
     8         <attr name="startAngle" format="integer" />
     9         <attr name="sweepAngle" format="integer" />
    10         <attr name="scale" format="float" />
    11         <attr name="hOffset" format="float" />
    12         <attr name="vOffset" format="float" />
    13         <attr name="drawStyle" format="enum">
    14             <enum name="LEFT_TOP" value="0" />
    15             <enum name="LEFT_BOTTOM" value="1" />
    16             <enum name="RIGHT_TOP" value="2" />
    17             <enum name="RIGHT_BOTTOM" value="3" />
    18             <enum name="CENTER" value="4" />
    19         </attr>
    20         <attr name="arcColor" format="color" />
    21         <attr name="textColor" format="color" />
    22     </declare-styleable>
    23 </resources>

    3.在MainActivity调用ArcImageView,实现代码如下:

     1 package com.chunk.customviewsdemo;
     2 
     3 import android.os.Bundle;
     4 import android.support.v7.app.AppCompatActivity;
     5 import android.view.View;
     6 import android.widget.Button;
     7 
     8 import com.chunk.customviewsdemo.views.ArcImageView.ArcImageView;
     9 
    10 public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    11     private ArcImageView aiv_one;
    12     private ArcImageView aiv_two;
    13     private ArcImageView aiv_three;
    14     private ArcImageView aiv_four;
    15     private Button btn_another_one;
    16     private int mGroup = 1;
    17 
    18     @Override
    19     protected void onCreate(Bundle savedInstanceState) {
    20         super.onCreate(savedInstanceState);
    21         setContentView(R.layout.activity_main);
    22         aiv_one = (ArcImageView) findViewById(R.id.aiv_one);
    23         aiv_one.setArcAlpha(180);
    24         aiv_two = (ArcImageView) findViewById(R.id.aiv_two);
    25         aiv_two.setArcAlpha(180);
    26         aiv_three = (ArcImageView) findViewById(R.id.aiv_three);
    27         aiv_three.setArcAlpha(180);
    28         aiv_four = (ArcImageView) findViewById(R.id.aiv_four);
    29         aiv_four.setArcAlpha(180);
    30         btn_another_one = (Button) findViewById(R.id.btn_another_one);
    31         btn_another_one.setOnClickListener(this);
    32     }
    33 
    34     @Override
    35     public void onClick(View v) {
    36         switch (v.getId()) {
    37             case R.id.btn_another_one:
    38                 if (mGroup == 1) {
    39                     aiv_one.setDrawStr("苹果");
    40                     aiv_one.setBackgroundResource(R.drawable.apple);
    41                     aiv_two.setDrawStr("柚子");
    42                     aiv_two.setBackgroundResource(R.drawable.pineapple);
    43                     aiv_three.setDrawStr("香蕉");
    44                     aiv_three.setBackgroundResource(R.drawable.banana);
    45                     aiv_four.setDrawStr("菠萝");
    46                     aiv_four.setBackgroundResource(R.drawable.pineapple);
    47                     mGroup = 2;
    48                 } else {
    49                     aiv_one.setDrawStr("牛排");
    50                     aiv_one.setBackgroundResource(R.drawable.steak);
    51                     aiv_two.setDrawStr("海鲜");
    52                     aiv_two.setBackgroundResource(R.drawable.seafood);
    53                     aiv_three.setDrawStr("奶酪");
    54                     aiv_three.setBackgroundResource(R.drawable.cheese);
    55                     aiv_four.setDrawStr("烧烤");
    56                     aiv_four.setBackgroundResource(R.drawable.barbecue);
    57                     mGroup = 1;
    58                 }
    59                 break;
    60         }
    61     }
    62 }

    4.MainActivity的布局文件如下:

      1 <LinearLayout
      2     xmlns:android="http://schemas.android.com/apk/res/android"
      3     xmlns:custom="http://schemas.android.com/apk/res-auto"
      4     android:layout_width="match_parent"
      5     android:layout_height="match_parent"
      6     android:layout_marginTop="100dp"
      7     android:layout_marginBottom="100dp"
      8     android:orientation="vertical" >
      9 
     10     <Button
     11         android:id="@+id/btn_another_one"
     12         android:layout_width="wrap_content"
     13         android:layout_height="wrap_content"
     14         android:text="换一组" />
     15 
     16     <LinearLayout
     17         android:layout_width="match_parent"
     18         android:layout_height="0dp"
     19         android:layout_weight="1"
     20         android:orientation="horizontal" >
     21 
     22         <RelativeLayout
     23             android:layout_width="0dp"
     24             android:layout_weight="1"
     25             android:layout_height="match_parent" >
     26 
     27             <com.chunk.customviewsdemo.views.ArcImageView.ArcImageView
     28                 android:id="@+id/aiv_one"
     29                 android:layout_width="match_parent"
     30                 android:layout_height="match_parent"
     31                 android:background="@drawable/steak"
     32                 custom:drawStyle="RIGHT_BOTTOM"
     33                 custom:drawStr="牛排"
     34                 custom:arcAlpha="100"
     35                 custom:arcColor="@color/gray"
     36                 custom:textColor="@color/black"
     37                 custom:textSize="20sp" />
     38         </RelativeLayout>
     39 
     40         <RelativeLayout
     41             android:layout_width="0dp"
     42             android:layout_weight="1"
     43             android:layout_height="match_parent" >
     44 
     45             <com.chunk.customviewsdemo.views.ArcImageView.ArcImageView
     46                 android:id="@+id/aiv_two"
     47                 android:layout_width="match_parent"
     48                 android:layout_height="match_parent"
     49                 android:background="@drawable/seafood"
     50                 custom:drawStyle="LEFT_BOTTOM"
     51                 custom:drawStr="海鲜"
     52                 custom:arcAlpha="100"
     53                 custom:arcColor="@color/gray"
     54                 custom:textColor="@color/black"
     55                 custom:textSize="20sp" />
     56 
     57         </RelativeLayout>
     58     </LinearLayout>
     59 
     60     <LinearLayout
     61         android:layout_width="match_parent"
     62         android:layout_height="0dp"
     63         android:layout_weight="1"
     64         android:orientation="horizontal" >
     65 
     66         <RelativeLayout
     67             android:layout_width="0dp"
     68             android:layout_weight="1"
     69             android:layout_height="match_parent" >
     70 
     71             <com.chunk.customviewsdemo.views.ArcImageView.ArcImageView
     72                 android:id="@+id/aiv_three"
     73                 android:layout_width="match_parent"
     74                 android:layout_height="match_parent"
     75                 android:background="@drawable/cheese"
     76                 custom:drawStyle="RIGHT_TOP"
     77                 custom:drawStr="奶酪"
     78                 custom:arcAlpha="100"
     79                 custom:arcColor="@color/gray"
     80                 custom:textColor="@color/black"
     81                 custom:textSize="20sp" />
     82         </RelativeLayout>
     83 
     84         <RelativeLayout
     85             android:layout_width="0dp"
     86             android:layout_weight="1"
     87             android:layout_height="match_parent" >
     88 
     89             <com.chunk.customviewsdemo.views.ArcImageView.ArcImageView
     90                 android:id="@+id/aiv_four"
     91                 android:layout_width="match_parent"
     92                 android:layout_height="match_parent"
     93                 android:background="@drawable/barbecue"
     94                 custom:drawStyle="LEFT_TOP"
     95                 custom:drawStr="烧烤"
     96                 custom:arcAlpha="100"
     97                 custom:arcColor="@color/gray"
     98                 custom:textColor="@color/black"
     99                 custom:textSize="20sp" />
    100 
    101         </RelativeLayout>
    102     </LinearLayout>
    103 </LinearLayout>

    注意,在布局文件中引入自定义属性时需要加入一行代码:xmlns:custom="http://schemas.android.com/apk/res-auto"。

    好了,需求搞定,剩下的就是搬到实际的项目当中去了。实现效果如下:

    总结一下,自定义View一般就是通过重写onDraw、onMeasure()、onLayout()等方法来进行测量、绘制,绘制的时候一般会用到Canvas、Paint、Bitmap等类,测量和绘制的过程其实就是对现实生活中绘图工作的抽象和实现,我们利用面向对象的思想将画板、画纸、画笔等工具以及绘画的动作用一行行代码加以描述就OK啦!

    由于实现过程比较简单,我就不贴源码了,大家如果对2D绘图还不是很了解,可以去搜一下相关资料或查阅相关书籍!

  • 相关阅读:
    人月神话阅读笔记03(完)
    人月神话阅读笔记02
    各种前端好用的在线工具、学习网站、插件
    垂直居中css
    输入框判断表情的输入js
    jq九宫格抽奖
    移动端中一像素的解决方案
    获取url地址栏中的参数数据
    ios中getTime()的兼容性问题
    清除Css中select的下拉箭头样式
  • 原文地址:https://www.cnblogs.com/1992monkey/p/5489065.html
Copyright © 2011-2022 走看看