Android重寫View實(shí)現(xiàn)全新的控件
通常情況下,Android實(shí)現(xiàn)自定義控件無(wú)非三種方式。
?、瘛⒗^承現(xiàn)有控件,對(duì)其控件的功能進(jìn)行拓展。
?、颉F(xiàn)有控件進(jìn)行組合,實(shí)現(xiàn)功能更加強(qiáng)大控件。
?、蟆⒅貙慥iew實(shí)現(xiàn)全新的控件
本文來(lái)討論最難的一種自定義控件形式,重寫View來(lái)實(shí)現(xiàn)全新的控件。
首先,我們要明白在什么樣的情況下,需要重寫View來(lái)實(shí)現(xiàn)一種全新的控件,一般當(dāng)我們遇到了原生控件無(wú)法滿足我們現(xiàn)有的需求的時(shí)候,我們此時(shí)就可以考慮創(chuàng)建一個(gè)全新的View來(lái)實(shí)現(xiàn)我們所需要的功能。創(chuàng)建一個(gè)全新View實(shí)現(xiàn)自定義控件,無(wú)非分成這么幾步:
Ⅰ、在OnMeasure()方法中,測(cè)量自定義控件的大小,使自定義控件能夠自適應(yīng)布局各種各樣的需求。
Ⅱ、在OnDraw()方法中,利用哼哈二將(Canvas與Paint)來(lái)繪制要顯示的內(nèi)容。
?、蟆⒃贠nLayout()方法中來(lái)確定控件顯示位置。
?、?、在OnTouchEvent()方法處理控件的觸摸事件。
相應(yīng)的思維導(dǎo)圖如下:
多說(shuō)無(wú)益,我們通過(guò)幾個(gè)小案例,來(lái)講解到底如何實(shí)現(xiàn)自定義控件。
一、一個(gè)帶有比例進(jìn)度的環(huán)形控件
首先看一下這個(gè)控件的示意圖:
通過(guò)這個(gè)簡(jiǎn)單的示意圖,我們對(duì)于項(xiàng)目所完成的比例,就一目了然了。通過(guò)這個(gè)簡(jiǎn)單的示意圖,我們可以很快速的把這個(gè)圖形分成三個(gè)部分。Ⅰ、外層的環(huán),Ⅱ、里面的園,三、相應(yīng)文字。有了這個(gè)思路以后,我們只需要在onDraw()方法中一個(gè)個(gè)進(jìn)行繪制罷了。我這里為了簡(jiǎn)單起見,把這個(gè)控件的寬度設(shè)置為屏幕的寬度。
首先,還是老樣子,為自定義控件設(shè)置一些自定義屬性,便于調(diào)用者對(duì)其進(jìn)行擴(kuò)展,自定義屬性的設(shè)置代碼為:
<declare-styleable name="circleView"> <attr name="textSize" format="dimension" /> <attr name="text" format="string" /> <attr name="circleColor" format="color" /> <attr name="arcColor" format="color" /> <attr name="textColor" format="color" /> <attr name="startAngle" format="integer" /> <attr name="sweepAngle" format="integer" /> </declare-styleable>
?、?、textSize——對(duì)應(yīng)中間文本文字的大小
Ⅱ、text——對(duì)應(yīng)中間文本
?、?、circleColor——對(duì)應(yīng)內(nèi)圓的顏色
Ⅳ、arcColor——對(duì)應(yīng)外環(huán)的顏色
?、?、textColor——對(duì)應(yīng)文本的顏色
Ⅵ、startAngle——對(duì)應(yīng)外環(huán)的起始角度
?、鳌weepAngle——對(duì)應(yīng)外環(huán)掃描角度
緊接著,就是在自定義控件的初始化方法中來(lái)獲取這些自定義屬性:
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.circleView); if (ta != null) { circleColor = ta.getColor(R.styleable.circleView_circleColor, 0); arcColor = ta.getColor(R.styleable.circleView_arcColor, 0); textColor = ta.getColor(R.styleable.circleView_textColor, 0); textSize = ta.getDimension(R.styleable.circleView_textSize, 50); text = ta.getString(R.styleable.circleView_text); startAngle = ta.getInt(R.styleable.circleView_startAngle, 0); sweepAngle = ta.getInt(R.styleable.circleView_sweepAngle, 90); ta.recycle(); }
這里在多說(shuō)一嘴子,為了釋放更多的資源,一定要將TypedArray這個(gè)對(duì)象進(jìn)行資源的釋放。
接下來(lái),在OnMeasure()方法中,初始化要繪制畫筆樣式,獲取屏幕的寬度,計(jì)算中間位置的坐標(biāo),以及指定外接矩形的寬高代碼如下:
private void init() { int length = Math.min(width, height); mCircleXY = length / 2; mRadius = length * 0.5f / 2; mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mCirclePaint.setColor(circleColor); mRectF = new RectF(length * 0.1f, length * 0.1f, length * 0.9f, length * 0.9f); mArcPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mArcPaint.setColor(arcColor); mArcPaint.setStyle(Paint.Style.STROKE); mArcPaint.setStrokeWidth((width * 0.1f)); mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mTextPaint.setTextSize(textSize); mTextPaint.setColor(textColor); mTextPaint.setTextAlign(Align.CENTER); }
將我們?cè)O(shè)置的自定義屬性,設(shè)置給不同筆刷。
做了這么多準(zhǔn)備以后,我們所需的就是在OnDraw方法中繪制內(nèi)圓、外環(huán)與文字。代碼如下:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); drawSth(canvas); } private void drawSth(Canvas canvas) { canvas.drawCircle(mCircleXY, mCircleXY, mRadius, mCirclePaint); canvas.drawArc(mRectF, startAngle, sweepAngle, false, mArcPaint); canvas.drawText(text, 0, text.length(), mCircleXY, mCircleXY + textSize / 4, mTextPaint); }
需要指出的是,畫環(huán)形需要在一個(gè)指定矩形區(qū)域畫取,并且要指定起始角度,掃描角度,這些變量都是自定義屬性?!?/p>
這個(gè)自定義控件的最終的運(yùn)行效果為:
二、動(dòng)態(tài)條形圖
條形圖,應(yīng)該在圖表展示系統(tǒng)中再普通不過(guò)的一種圖標(biāo)了。靜態(tài)示意圖就像這樣:
通過(guò)這個(gè)簡(jiǎn)單的示意圖,我們所需要做的是,繪制一個(gè)個(gè)的矩形,然后將每一個(gè)矩形x坐標(biāo)平移一定的單位,我們還看到這么一個(gè)現(xiàn)象:每個(gè)條形圖的起始點(diǎn)不一致,而終止點(diǎn)是一樣的。起始坐標(biāo)用個(gè)Random(隨機(jī)函數(shù))剛剛好,實(shí)現(xiàn)靜態(tài)條形圖就是這樣的思路:
首先,在OnMeasure()方法中計(jì)算出每個(gè)矩形寬與高,這里為了方便起見,每個(gè)矩形默認(rèn)的高為屏幕的高,每個(gè)矩形的寬這里定義為屏幕的寬度乘以80%除以矩形的個(gè)數(shù)。然后根據(jù)寬與高來(lái)初始化筆刷(Paint)。為什么要根據(jù)寬與高來(lái)初始化筆刷了,這里我為了使自定義View更加的逼真,我這里使用LinearGradient(線性渲染器)進(jìn)行了渲染,這個(gè)對(duì)象需要使用矩形寬與高。需要指出來(lái)的是這個(gè)自定義控件是動(dòng)態(tài)的,我只需要onDraw方法不斷發(fā)生重繪,這里為了防止控件刷新太快,我這里每隔300毫秒刷新視圖。這個(gè)控件的完整源代碼如下:
public class VolumneView extends View { private Paint mPaint; private int mCount; private int mWidth; private int mRectHeight; private int mRectWidth; private LinearGradient mLinearGradient; private double mRandom; private float mcurrentHeight; public static final int OFFSET = 5; public VolumneView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context, attrs); } private void initView(Context context, AttributeSet attrs) { mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setColor(Color.GREEN); mPaint.setStyle(Paint.Style.FILL); TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.volumneView); if (ta != null) { mCount = ta.getInt(R.styleable.volumneView_count, 6); ta.recycle(); } } public VolumneView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public VolumneView(Context context) { this(context, null); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth = getMeasuredWidth(); mRectHeight = getMeasuredHeight(); mRectWidth = (int) (mWidth * 0.8 / mCount); mLinearGradient = new LinearGradient(0, 0, mRectWidth, mRectHeight, Color.GREEN, Color.YELLOW, TileMode.CLAMP); mPaint.setShader(mLinearGradient); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); for (int i = 0; i < mCount; i++) { mRandom = Math.random(); mcurrentHeight = (float) (mRectHeight * mRandom); float width = (float) (mWidth * 0.4 / 2 + OFFSET); canvas.drawRect(width + i * mRectWidth, mcurrentHeight, width + (i + 1) * mRectWidth, mRectHeight, mPaint); } postInvalidateDelayed(300); }
最終,運(yùn)行效果如下:
后記,通過(guò)這兩個(gè)簡(jiǎn)單控件,相信大家對(duì)于自定義控件基本步驟有說(shuō)了解,當(dāng)然,要真正做好自定義控件的話,我們還需要按這個(gè)步驟一步步的來(lái),加油!
- Android控件系列之ImageView使用方法
- Android控件系列之TextView使用介紹
- android圖像繪制(四)自定義一個(gè)SurfaceView控件
- Android開發(fā)技巧之在a標(biāo)簽或TextView控件中單擊鏈接彈出Activity(自定義動(dòng)作)
- Android控件之EditView常用屬性及應(yīng)用方法
- Android控件ListView用法(讀取聯(lián)系人示例代碼)
- android ListView和ProgressBar(進(jìn)度條控件)的使用方法
- 自己實(shí)現(xiàn)的android樹控件treeview
- android中webview控件和javascript交互實(shí)例
- Android ExpandableListView展開列表控件使用實(shí)例
相關(guān)文章
Android 自定義 HorizontalScrollView 打造多圖片OOM 的橫向滑動(dòng)效果(實(shí)例代碼)
這篇文章主要介紹了Android 自定義 HorizontalScrollView 打造多圖片OOM 的橫向滑動(dòng)效果(實(shí)例代碼),需要的朋友可以參考下2017-10-10Android編程ViewPager回彈效果實(shí)例分析
這篇文章主要介紹了Android編程ViewPager回彈效果,以實(shí)例形式較為詳細(xì)的分析了ViewPager回彈效果的相關(guān)使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10Android?Flutter實(shí)現(xiàn)搜索的三種方式詳解
這篇文章主要為大家詳細(xì)介紹了Android?Flutter實(shí)現(xiàn)搜索的三種方式,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的可以了解一下2022-08-08Flutter使用Overlay與ColorFiltered新手引導(dǎo)實(shí)現(xiàn)示例
這篇文章主要介紹了Flutter使用Overlay與ColorFiltered新手引導(dǎo)實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10android實(shí)現(xiàn)簡(jiǎn)單拍照功能
這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)簡(jiǎn)單拍照功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06Android編程使用GestureDetector實(shí)現(xiàn)簡(jiǎn)單手勢(shì)監(jiān)聽與處理的方法
這篇文章主要介紹了Android編程使用GestureDetector實(shí)現(xiàn)簡(jiǎn)單手勢(shì)監(jiān)聽與處理的方法,簡(jiǎn)單講述了Android手勢(shì)監(jiān)聽的原理并結(jié)合實(shí)例形式分析了GestureDetector實(shí)現(xiàn)手勢(shì)監(jiān)聽與處理的相關(guān)操作技巧,需要的朋友可以參考下2017-09-09Android ProgressBar直線進(jìn)度條的實(shí)例代碼
本文通過(guò)實(shí)例代碼給大家介紹了android progressbar直線進(jìn)度條的實(shí)現(xiàn)方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧2017-06-06Android使用內(nèi)置WebView打開TextView超鏈接的實(shí)現(xiàn)方法
這篇文章主要介紹了Android使用內(nèi)置WebView打開TextView超鏈接的實(shí)現(xiàn)方法,文中給出了詳細(xì)的示例代碼,對(duì)各位Android開發(fā)者們具有一定的參考價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-03-03