Android使用ImageView 制作透明圆弧实例代码
程序员文章站
2024-03-02 17:18:16
这几天因为项目需求,需要在imageview上面叠加一层透明圆弧,并且在沿着圆弧的方向显示相应的文字,效果如下图所示:
拿到这个需求,首先想到的是自定义一...
这几天因为项目需求,需要在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: // : */ public class arcimageview extends imageview { /** * the default text size. */ private final float default_text_size = ; /** * the default scale value which decides the width of arc. */ private final float default_scale = .f; /** * the default transparency of arc. */ private final int default_arc_alpha =; /** * the default width of arc. */ private final int default_arc_width =; /** * the default angle that the arc starts with. */ private final int default_start_angle = ; /** * the default angle that the arc. */ private final int default_sweep_angle = ; /** * the default distance along the path to add to the text's starting position. */ private final int default_h_offset = ; /** * the default distance above(-) or below(+) the path to position the text. */ private final int default_v_offset = ; 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 : center_x = ; center_y = ; mstartangle = ; msweepangle = -; break; case : center_x = ; center_y = height; mstartangle = ; msweepangle = ; break; case : center_x = width; center_y = ; mstartangle = ; msweepangle = -; break; case : center_x = width; center_y = height; mstartangle = ; msweepangle = ; break; case : center_x = width / ; center_y = height / ; mstartangle = ; msweepangle = ; 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, xcccccc); mtextcolor = ta.getcolor(r.styleable.arcimageview_textcolor, xffffff); mdrawstyle = ta.getint(r.styleable.arcimageview_drawstyle, ); ta.recycle(); } }
2.在values文件夹下的attrs.xml中自定义属性:
<?xml version="." encoding="utf-"?> <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="" /> <enum name="left_bottom" value="" /> <enum name="right_top" value="" /> <enum name="right_bottom" value="" /> <enum name="center" value="" /> </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.v.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 = ; @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(); aiv_two = (arcimageview) findviewbyid(r.id.aiv_two); aiv_two.setarcalpha(); aiv_three = (arcimageview) findviewbyid(r.id.aiv_three); aiv_three.setarcalpha(); aiv_four = (arcimageview) findviewbyid(r.id.aiv_four); aiv_four.setarcalpha(); 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 == ) { 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 = ; } 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 = ; } 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="dp" android:layout_marginbottom="dp" 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="dp" android:layout_weight="" android:orientation="horizontal" > <relativelayout android:layout_width="dp" android:layout_weight="" 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="" custom:arccolor="@color/gray" custom:textcolor="@color/black" custom:textsize="sp" /> </relativelayout> <relativelayout android:layout_width="dp" android:layout_weight="" 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="" custom:arccolor="@color/gray" custom:textcolor="@color/black" custom:textsize="sp" /> </relativelayout> </linearlayout> <linearlayout android:layout_width="match_parent" android:layout_height="dp" android:layout_weight="" android:orientation="horizontal" > <relativelayout android:layout_width="dp" android:layout_weight="" 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="" custom:arccolor="@color/gray" custom:textcolor="@color/black" custom:textsize="sp" /> </relativelayout> <relativelayout android:layout_width="dp" android:layout_weight="" 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="" custom:arccolor="@color/gray" custom:textcolor="@color/black" custom:textsize="sp" /> </relativelayout> </linearlayout> </linearlayout>
注意,在布局文件中引入自定义属性时需要加入一行代码:xmlns:custom="http://schemas.android.com/apk/res-auto"。
好了,需求搞定,剩下的就是搬到实际的项目当中去了。实现效果如下:
总结一下,自定义view一般就是通过重写ondraw、onmeasure()、onlayout()等方法来进行测量、绘制,绘制的时候一般会用到canvas、paint、bitmap等类,测量和绘制的过程其实就是对现实生活中绘图工作的抽象和实现,我们利用面向对象的思想将画板、画纸、画笔等工具以及绘画的动作用一行行代码加以描述就ok啦!
由于实现过程比较简单,我就不贴源码了,大家如果对2d绘图还不是很了解,可以去搜一下相关资料或查阅相关书籍!