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绘图还不是很了解,可以去搜一下相关资料或查阅相关书籍!

时间: 2024-10-01 06:29:14

Android打造带透明圆弧的ImageView的相关文章

【Android 仿微信通讯录 导航分组列表-上】使用ItemDecoration为RecyclerView打造带悬停头部的分组列表

[Android 仿微信通讯录 导航分组列表-上]使用ItemDecoration为RecyclerView打造带悬停头部的分组列表 一 概述 本文是Android导航分组列表系列上,因时间和篇幅原因分上下,最终上下合璧,完整版效果如下: 上部残卷效果如下:两个ItemDecoration,一个实现悬停头部分组列表功能,一个实现分割线(官方demo) 网上关于实现带悬停分组头部的列表的方法有很多,像我看过有主席的自定义ExpandListView实现的,也看过有人用一个额外的父布局里面套 Rec

Android开发实例透明效果设置方法

没什么android开发经验的朋友来说,实现透明效果是有一定难度的,我看见麦子学院android开发视频上面讲了三种方法来实现透明效果,这三种方法非常不错,嘿嘿,就抄下来分享给大家. 1.设置alpha View v = findViewById(R.id.content);/到你要设透明背景的layout 的id  v.getBackground().setAlpha(100);//0~255透明度值  2.用ARGB来控制 半透明<Button android:background="

Android打造通用的下拉刷新组件

还记得上一篇 blog 的内容吗?如果不记得建议先去了解一下,Android 事件处理全面剖析 ,因为下拉刷新需要用到手势的处理,而上一篇文章中,对事件处理做了很详细的说明,了解了事件的处理机制,对理解本篇文章有很大的帮助.好了,这里就当大家都已经对事件处理有了一定的了解,开始我们的下拉刷新征程. 还是老规矩,先上效果图,再根据效果图来分析实现的原理: 一 .分析原理 我们都知道,listView 控件为我们提供了 addHeaderView.和 addFootView 的方法,我们通过此方法可

android自带的处理Bitmap out Memory 的处理,第三方开源的那个更方便,自己练习的话还是很好的

/** * @author [email protected] * @time 20140606 */ package com.intbird.utils; import java.lang.ref.WeakReference; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFa

Android自带样式

Android系统自带样式: android:theme="@android:style/Theme.Dialog" 将一个Activity显示为对话框模式 android:theme="@android:style/Theme.NoTitleBar" 不显示应用程序标题栏 android:theme="@android:style/Theme.NoTitleBar.Fullscreen" 不显示应用程序标题栏,并全屏 android:theme

android 自带主题样式(theme )

android:theme="@android:style/Theme.Dialog" 将一个Activity显示为能话框模式 android:theme="@android:style/Theme.NoTitleBar" 不显示应用程序标题栏 android:theme="@android:style/Theme.NoTitleBar.Fullscreen" 不显示应用程序标题栏,并全屏 android:theme="Theme.Li

Android实现带箭头的自定义Progressbar

一.闲话: Android原生的进度条可以根据不同的主题有不同的视觉效果,但任何一种主题下的进度条和应用程序的视觉配合起来都显得格格不入,所以多数时候我们需要自定义Progressbar,最简单的是在布局文件中通过"android:progressDrawable"为Progressbar换背景和进度图片,换图后的效果类似于这样: 但你会发现,进度图片像是被截断了一样,看上去同样不美观,所以现在很多应用都会在进度条上玩花样,做出各种各样的效果,本例介绍的是在进度条的头部加上光晕箭头的效

Android 设计一个菱形形状的Imageview组件.

网上没有资料,特来请教下大神 Android 设计一个菱形形状的Imageview组件. >> android 这个答案描述的挺清楚的:http://www.goodpm.net/postreply/android/1010000007107851/Android设计一个菱形形状的Imageview组件.html

android自带的浏览器如何下载apk包

============问题描述============ 如题! 目前android上其它的浏览器因为自己做过处理,所以下载没问题.. 可是android自带的浏览器下载有时候下载错误.有时候下载的是.htm文件,恶心啊,貌似把apk当成恶意软件了,请问大神们该怎么处理.. 和contentType设置有关吗,我换了好多个,没用啊,我的服务端是用java写的 ============解决方案1============ response.setContentType("application/vn