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

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

1.自定义ImageView:

 package com.chunk.customviewsdemo.views.ArcImageView;

 import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.widget.ImageView; import com.chunk.customviewsdemo.R; /**
* Description:A custom ImageView with circular arc and text
* Author: XiaoYu
* Date: 2016/5/10 13:55
*/
public class ArcImageView extends ImageView {
/**
* The default text size.
*/
private final float DEFAULT_TEXT_SIZE = 20;
/**
* The default scale value which decides the width of arc.
*/
private final float DEFAULT_SCALE = 0.5f;
/**
* The default transparency of arc.
*/
private final int DEFAULT_ARC_ALPHA =100;
/**
* The default width of arc.
*/
private final int DEFAULT_ARC_WIDTH =160;
/**
* The default angle that the arc starts with.
*/
private final int DEFAULT_START_ANGLE = 180;
/**
* The default angle that the arc.
*/
private final int DEFAULT_SWEEP_ANGLE = 90;
/**
* The default distance along the path to add to the text's starting position.
*/
private final int DEFAULT_H_OFFSET = 100;
/**
* The default distance above(-) or below(+) the path to position the text.
*/
private final int DEFAULT_V_OFFSET = 20;
private Context mContext;
/**
* The text displayed on ImageView along arc.
*/
private String mDrawStr;
/**
* The font size of text.
*/
private float mTextSize = DEFAULT_TEXT_SIZE;
/**
* The scale value which decides the width of arc.
*/
private float mScale = DEFAULT_SCALE;
/**
* The transparency of arc.
*/
private int mArcAlpha = DEFAULT_ARC_ALPHA;
/**
* The width of arc.
*/
private int mArcWidth = DEFAULT_ARC_WIDTH;
/**
* The start angle of angle.
*/
private int mStartAngle = DEFAULT_START_ANGLE;
/**
* The swept angle of angle.
*/
private int mSweepAngle = DEFAULT_SWEEP_ANGLE;
/**
* The default distance along the path to add to the text's starting position.
*/
private float mHOffset = DEFAULT_H_OFFSET;
/**
* The default distance above(-) or below(+) the path to position the text.
*/
private float mVOffset = DEFAULT_V_OFFSET;
/**
* The style of arc, all styles includes LEFT_TOP, LEFT_BOTTOM, RIGHT_TOP, RIGHT_BOTTOM, CENTER。
* of course, you can add your own style according to your demands.
*/
private int mDrawStyle;
/**
* The color of arc.
*/
private int mArcColor;
/**
* The color of text.
*/
private int mTextColor; public ArcImageView(Context context) {
super(context);
this.mContext = context;
} public ArcImageView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
obtainAttributes(attrs);
} public ArcImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
obtainAttributes(attrs);
} /**
* Set the text that will be drawn on arc.
* @param drawStr the text content.
*/
public void setDrawStr(String drawStr) {
this.mDrawStr = drawStr;
//refresh this view
invalidate();
} /**
* Set the transparency of arc.
* @param mArcAlpha the value of transparency.
*/
public void setArcAlpha(int mArcAlpha) {
this.mArcAlpha = mArcAlpha;
//refresh this view
invalidate();
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//draw arc
Paint arcPaint = new Paint();
arcPaint.setStrokeWidth(mArcWidth);
arcPaint.setStyle(Paint.Style.STROKE);
arcPaint.setColor(mArcColor);
arcPaint.setAlpha(mArcAlpha);
int width = getWidth();
int height = getHeight();
float radius;
if (width > height) {
radius = mScale * height;
} else {
radius = mScale * width;
}
RectF oval = new RectF(); int center_x = width;
int center_y = height; switch (mDrawStyle) {
case 0:
center_x = 0;
center_y = 0;
mStartAngle = 90;
mSweepAngle = -90;
break;
case 1:
center_x = 0;
center_y = height;
mStartAngle = 270;
mSweepAngle = 90;
break;
case 2:
center_x = width;
center_y = 0;
mStartAngle = 180;
mSweepAngle = -90;
break;
case 3:
center_x = width;
center_y = height;
mStartAngle = 180;
mSweepAngle = 90;
break;
case 4:
center_x = width / 2;
center_y = height / 2;
mStartAngle = 270;
mSweepAngle = 90;
break;
}
float left = center_x - radius;
float top = center_y - radius;
float right = center_x + radius;
float bottom = center_y + radius;
oval.set(left, top, right, bottom);
canvas.drawArc(oval, mStartAngle, mSweepAngle, false, arcPaint); //draw text
Paint textPaint = new Paint();
textPaint.setTextSize(mTextSize);
textPaint.setStyle(Paint.Style.FILL);
textPaint.setColor(mTextColor);
Path path = new Path();
path.addArc(oval, mStartAngle, mSweepAngle);
canvas.drawTextOnPath(mDrawStr, path, mHOffset, mVOffset, textPaint);
} /**
* Obtain custom attributes that been defined in attrs.xml.
* @param attrs A collection of attributes.
*/
private void obtainAttributes(AttributeSet attrs) {
TypedArray ta = mContext.obtainStyledAttributes(attrs, R.styleable.ArcImageView);
mDrawStr = ta.getString(R.styleable.ArcImageView_drawStr);
mTextSize = ta.getDimension(R.styleable.ArcImageView_textSize, DEFAULT_TEXT_SIZE);
mArcAlpha = ta.getInteger(R.styleable.ArcImageView_arcAlpha, DEFAULT_ARC_ALPHA);
mArcWidth = ta.getInteger(R.styleable.ArcImageView_arcWidth, DEFAULT_ARC_WIDTH);
mStartAngle = ta.getInteger(R.styleable.ArcImageView_startAngle, DEFAULT_START_ANGLE);
mSweepAngle = ta.getInteger(R.styleable.ArcImageView_startAngle, DEFAULT_SWEEP_ANGLE);
mHOffset = ta.getInteger(R.styleable.ArcImageView_hOffset, DEFAULT_H_OFFSET);
mVOffset = ta.getInteger(R.styleable.ArcImageView_vOffset, DEFAULT_V_OFFSET);
mArcColor = ta.getColor(R.styleable.ArcImageView_arcColor, 0XCCCCCC);
mTextColor = ta.getColor(R.styleable.ArcImageView_textColor, 0XFFFFFF);
mDrawStyle = ta.getInt(R.styleable.ArcImageView_drawStyle, 0);
ta.recycle();
}
}

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

 <?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ArcImageView">
<attr name="drawStr" format="string" />
<attr name="textSize" format="dimension" />
<attr name="arcAlpha" format="integer" />
<attr name="arcWidth" format="integer" />
<attr name="startAngle" format="integer" />
<attr name="sweepAngle" format="integer" />
<attr name="scale" format="float" />
<attr name="hOffset" format="float" />
<attr name="vOffset" format="float" />
<attr name="drawStyle" format="enum">
<enum name="LEFT_TOP" value="0" />
<enum name="LEFT_BOTTOM" value="1" />
<enum name="RIGHT_TOP" value="2" />
<enum name="RIGHT_BOTTOM" value="3" />
<enum name="CENTER" value="4" />
</attr>
<attr name="arcColor" format="color" />
<attr name="textColor" format="color" />
</declare-styleable>
</resources>

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

 package com.chunk.customviewsdemo;

 import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button; import com.chunk.customviewsdemo.views.ArcImageView.ArcImageView; public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private ArcImageView aiv_one;
private ArcImageView aiv_two;
private ArcImageView aiv_three;
private ArcImageView aiv_four;
private Button btn_another_one;
private int mGroup = 1; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
aiv_one = (ArcImageView) findViewById(R.id.aiv_one);
aiv_one.setArcAlpha(180);
aiv_two = (ArcImageView) findViewById(R.id.aiv_two);
aiv_two.setArcAlpha(180);
aiv_three = (ArcImageView) findViewById(R.id.aiv_three);
aiv_three.setArcAlpha(180);
aiv_four = (ArcImageView) findViewById(R.id.aiv_four);
aiv_four.setArcAlpha(180);
btn_another_one = (Button) findViewById(R.id.btn_another_one);
btn_another_one.setOnClickListener(this);
} @Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_another_one:
if (mGroup == 1) {
aiv_one.setDrawStr("苹果");
aiv_one.setBackgroundResource(R.drawable.apple);
aiv_two.setDrawStr("柚子");
aiv_two.setBackgroundResource(R.drawable.pineapple);
aiv_three.setDrawStr("香蕉");
aiv_three.setBackgroundResource(R.drawable.banana);
aiv_four.setDrawStr("菠萝");
aiv_four.setBackgroundResource(R.drawable.pineapple);
mGroup = 2;
} else {
aiv_one.setDrawStr("牛排");
aiv_one.setBackgroundResource(R.drawable.steak);
aiv_two.setDrawStr("海鲜");
aiv_two.setBackgroundResource(R.drawable.seafood);
aiv_three.setDrawStr("奶酪");
aiv_three.setBackgroundResource(R.drawable.cheese);
aiv_four.setDrawStr("烧烤");
aiv_four.setBackgroundResource(R.drawable.barbecue);
mGroup = 1;
}
break;
}
}
}

4.MainActivity的布局文件如下:

 <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="100dp"
android:layout_marginBottom="100dp"
android:orientation="vertical" > <Button
android:id="@+id/btn_another_one"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="换一组" /> <LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal" > <RelativeLayout
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent" > <com.chunk.customviewsdemo.views.ArcImageView.ArcImageView
android:id="@+id/aiv_one"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/steak"
custom:drawStyle="RIGHT_BOTTOM"
custom:drawStr="牛排"
custom:arcAlpha="100"
custom:arcColor="@color/gray"
custom:textColor="@color/black"
custom:textSize="20sp" />
</RelativeLayout> <RelativeLayout
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent" > <com.chunk.customviewsdemo.views.ArcImageView.ArcImageView
android:id="@+id/aiv_two"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/seafood"
custom:drawStyle="LEFT_BOTTOM"
custom:drawStr="海鲜"
custom:arcAlpha="100"
custom:arcColor="@color/gray"
custom:textColor="@color/black"
custom:textSize="20sp" /> </RelativeLayout>
</LinearLayout> <LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal" > <RelativeLayout
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent" > <com.chunk.customviewsdemo.views.ArcImageView.ArcImageView
android:id="@+id/aiv_three"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/cheese"
custom:drawStyle="RIGHT_TOP"
custom:drawStr="奶酪"
custom:arcAlpha="100"
custom:arcColor="@color/gray"
custom:textColor="@color/black"
custom:textSize="20sp" />
</RelativeLayout> <RelativeLayout
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent" > <com.chunk.customviewsdemo.views.ArcImageView.ArcImageView
android:id="@+id/aiv_four"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/barbecue"
custom:drawStyle="LEFT_TOP"
custom:drawStr="烧烤"
custom:arcAlpha="100"
custom:arcColor="@color/gray"
custom:textColor="@color/black"
custom:textSize="20sp" /> </RelativeLayout>
</LinearLayout>
</LinearLayout>

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

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

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

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

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

  1. Android:手把手教你打造可缩放移动的ImageView(下)

    在上一篇Android:手把手教你打造可缩放移动的ImageView最后提出了一个注意点:当自定义的MatrixImageView如ViewPager.ListView等带有滑动效果的ViewGrou ...

  2. Android 打造炫目的圆形菜单 秒秒钟高仿建行圆形菜单

    原文:Android 打造炫目的圆形菜单 秒秒钟高仿建行圆形菜单 转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/43131133, ...

  3. 调用Android自带日历功能(日历列表单、添加一个日历事件)

    调用Android自带日历功能  觉得这篇文章不错,转载过来. 转载:http://blog.csdn.net/djy1992/article/details/9948393 Android手机配备有 ...

  4. Android自带样式

    Android系统自带样式: android:theme="@android:style/Theme.Dialog" 将一个Activity显示为对话框模式 android:the ...

  5. Android实现带图标的ListView

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/bear_huangzhen/article/details/23991119 Android实现带图 ...

  6. 使用Android自带的资源

    Android自带的资源文件有 :https://developer.android.google.cn/reference/android/R.html 代码中使用如下: 1.查看源代码的资源文件 ...

  7. 记一次使用 android 自带 WebView 做富文本编辑器之API、机型的兼容及各种奇葩bug的解决

    转载请声明出处(http://www.cnblogs.com/linguanh/) 目录 1,测试设备介绍 2,开源项目richeditor及CrossWalk的选择 3,遇到的bug及其解决方法 4 ...

  8. Android自带的theme

    android:theme="@android:style/Theme.Dialog" 将一个Activity显示为能话框模式 android:theme="@andro ...

  9. Android 自带图标库 android.R.drawable

    在xml文件中调用. android:title="@string/secure_connect"android:orderInCategory="100"an ...

随机推荐

  1. Android外派(安卓外派) — 长年提供安卓开发工程师外派业务(可签合同)

    北京动点飞扬长年提供安卓工程师外派业务. 平均技术情况如下: 1.2~3年以上Android平台开发经验2.熟练掌握java技术,熟悉面向对象编程设计3.熟悉Android应用开发框架及Activit ...

  2. 真实赛车3,SPEEDRUSH TV 第3季,第3阶段(第3天),直线加速赛

    与其跳过,不如金币升级引擎和车身.因为后边紧跟一场计时赛.

  3. 使用仓库管理器——Sonatype Nexus的九大理由

    目前有很多组织使用了一些工具依赖于Maven仓库,但他们并没有采用一个仓库管理器,对于这一点我十分惊讶.可能没人提出来这一点,没人站出来告诉别人使用一个仓库管理器能带来什么好处.我经常能从很多不使用M ...

  4. rdynamic和-whole-archive

    遇到如下情况,主程序通过dlopen来打开.so文件,但是.so用到了主程序的log函数. 编译so时,通过引用主程序头文件来编译通过,头文件有log函数声明: extern "C" ...

  5. 25 个超棒的 HTML5 & JavaScript 游戏引擎开发库

    就像在汽车中,引擎完成主要的工作,使汽车看起来不可思议.游戏引擎同理,游戏开发者完成细节的工作,使游戏看起来真实.吸引人眼球.游戏引擎负责其余的事情.早期,游戏开发者通常从草图做起,花费高昂,且不容易 ...

  6. apache 做http代理

    1.修改 http.conf 文件 ,增加 监听端口 Listen 开启需要的扩展 LoadModule proxy_module modules/mod_proxy.so LoadModule pr ...

  7. Centos 7 修改SSH端口号

    注意!这里的Centos版本是7   step1 修改/etc/ssh/sshd_config vi /etc/ssh/sshd_config #Port 22         //这行去掉#号 Po ...

  8. jquery实现的下拉和收缩代码实例

    <!DOCTYPE html>  <html>  <head>  <meta charset=" utf-8">  <meta ...

  9. Java多线程之后台线程

    将线程设置成后台线程Daemons 主线程结果后,后台线程将自动结果. package wzh.test; import java.util.concurrent.TimeUnit; class Si ...

  10. Android开发者需要面对的8大挑战

    移动开发变得越来越受欢迎,但移动开发者正面临着一系列挑战.本文将介绍的是Android开发者需要面对的8个不利因素,例如缺乏硬件标准化,以及软件碎片.为Android OS开发app,给予了开发人员极 ...