[Material Design] 教你做一个Material风格、动画的button(MaterialButton)
原創(chuàng)作品,轉(zhuǎn)載請(qǐng)注明出處:http://blog.csdn.net/qiujuer/article/details/39831451
前段時(shí)間Android L 公布了,相信看過(guò)公布會(huì)了解過(guò)的朋友都為當(dāng)中的 “Material Design” 感到由衷的驚艷吧!至少我是的。
在驚艷之余感到由衷的遺憾,由于其必須在 ”Android L“ 上才干使用。MD。郁悶啊。之后便自己想弄一個(gè)點(diǎn)擊動(dòng)畫(huà)試試,此念頭一發(fā)不可收拾;干脆一不做二不休,就重寫(xiě)了一個(gè) ”MaterialButton“ 控件出來(lái)。
在這里不討論什么是 :“Material Design” 。
在這里將給大家分享一下我自己弄的 “Material Design” 風(fēng)格的 ”MaterialButton“ button動(dòng)畫(huà)實(shí)現(xiàn)。
預(yù)熱一下:
上面的兩張動(dòng)畫(huà)相信大家都看過(guò)吧?是不是挺不錯(cuò)的?反正我是認(rèn)為手機(jī)上有這種動(dòng)畫(huà)是非常爽的,比較手機(jī)是用來(lái)添加體驗(yàn)的。可是這些動(dòng)畫(huà)僅僅能在Android L 才干體驗(yàn)到,對(duì)于如今國(guó)內(nèi)的 Android 廠商的情況來(lái)看,預(yù)計(jì)谷歌出新的版本號(hào)的時(shí)候我們就能用上這個(gè) L 版本號(hào)了。
以下給大伙看看我做的 “MaterialButton” button:
效果還不錯(cuò)吧?好了開(kāi)始開(kāi)工了。
介紹一下我的工具:“Android Studio” 當(dāng)然大家用其它也行。
第一步:新建項(xiàng)目(這個(gè)隨意。自己搗鼓吧)
第二步:新建自己定義控件:在java目錄上右擊選擇自己定義控件:
取個(gè)名字:“MaterialButton”
如今來(lái)看看多了一個(gè)類(lèi)(MaterialButton),一個(gè)布局文件 “sample_material_button”,一個(gè)屬性文件 “attrs_material_button”
到這里第二步完畢了。多了3個(gè)文件。
第三步:改動(dòng) “MaterialButton” 類(lèi):
分為幾步走:刪除演示樣例代碼。又一次繼承自 “Button” 類(lèi),復(fù)寫(xiě) “onTouchEvent()” 方法。完畢后的代碼:
public class MaterialButton extends Button {public MaterialButton(Context context) {super(context);init(null, 0);}public MaterialButton(Context context, AttributeSet attrs) {super(context, attrs);init(attrs, 0);}public MaterialButton(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);init(attrs, defStyle);}private void init(AttributeSet attrs, int defStyle) {// Load attributesfinal TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MaterialButton, defStyle, 0);a.recycle();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);}@Overridepublic boolean onTouchEvent(MotionEvent event) {return super.onTouchEvent(event);}} 是不是感覺(jué)干凈多了?到此第三步完畢了。第四步:就是做實(shí)際的動(dòng)畫(huà)了,在這里須要給大家說(shuō)說(shuō)三個(gè)須要注意的東西:
1.點(diǎn)擊事件響應(yīng),這個(gè)非常好理解,在?“onTouchEvent()” 方法中完畢,在該方法中我們須要完畢的是點(diǎn)擊后啟動(dòng)一個(gè)動(dòng)畫(huà)。同一時(shí)候須要獲取到當(dāng)時(shí)點(diǎn)擊的位置。
2.動(dòng)畫(huà),這里的動(dòng)畫(huà)不是放大動(dòng)畫(huà)而是屬性動(dòng)畫(huà),說(shuō)實(shí)話 這個(gè)要說(shuō)清楚還真不是一點(diǎn)點(diǎn)就能說(shuō)清楚的事情。簡(jiǎn)單說(shuō)就是在動(dòng)畫(huà)中能夠控制一個(gè)屬性的變化,而在這里來(lái)說(shuō)就是在 “MaterialButton” 類(lèi)中建立一個(gè)寬度和一個(gè)顏色的屬性,然后在動(dòng)畫(huà)中控制這兩個(gè)屬性的變化。
3.屬性的建立以及屬性的變化區(qū)域確定問(wèn)題。
首先建立兩個(gè)屬性:
private Paint backgroundPaint;private float radius;private Property<MaterialButton, Float> mRadiusProperty = new Property<MaterialButton, Float>(Float.class, "radius") {@Overridepublic Float get(MaterialButton object) {return object.radius;}@Overridepublic void set(MaterialButton object, Float value) {object.radius = value;//刷新Canvasinvalidate();}};private Property<MaterialButton, Integer> mBackgroundColorProperty = new Property<MaterialButton, Integer>(Integer.class, "bg_color") {@Overridepublic Integer get(MaterialButton object) {return object.backgroundPaint.getColor();}@Overridepublic void set(MaterialButton object, Integer value) {object.backgroundPaint.setColor(value);}};兩個(gè)屬性對(duì)照一下能夠發(fā)如今半徑的屬性 “set” 操作中調(diào)用了 “invalidate()” 方法,該方法的作用是告訴系統(tǒng)刷新當(dāng)前控件的 “Canvas”。也就是觸發(fā)一次:“onDraw(Canvas canvas)” 方法。
然后復(fù)寫(xiě) “onTouchEvent()” 方法例如以下:
@Overridepublic boolean onTouchEvent(MotionEvent event) {if (event.getAction() == MotionEvent.ACTION_DOWN) {//記錄坐標(biāo)paintX = event.getX();paintY = event.getY();//啟動(dòng)動(dòng)畫(huà)startAnimator();}return super.onTouchEvent(event);}在該方法中,首先確定是否是點(diǎn)擊下去的事件。然后記錄坐標(biāo),并啟動(dòng)動(dòng)畫(huà)。在啟動(dòng)動(dòng)畫(huà)方法 “startAnimator()” 方法中。我們這樣寫(xiě):
private void startAnimator() {//計(jì)算半徑變化區(qū)域int start, end;if (getHeight() < getWidth()) {start = getHeight();end = getWidth();} else {start = getWidth();end = getHeight();}float startRadius = (start / 2 > paintY ? start - paintY : paintY) * 1.15f;float endRadius = (end / 2 > paintX ? end - paintX : paintX) * 0.85f;//新建動(dòng)畫(huà)AnimatorSet set = new AnimatorSet();//加入變化屬性set.playTogether(//半徑變化ObjectAnimator.ofFloat(this, mRadiusProperty, startRadius, endRadius),//顏色變化 黑色到透明ObjectAnimator.ofObject(this, mBackgroundColorProperty, new ArgbEvaluator(), Color.BLACK, Color.TRANSPARENT));// 設(shè)置時(shí)間set.setDuration((long) (1200 / end * endRadius));//先快后慢set.setInterpolator(new DecelerateInterpolator());set.start();}在這一步我們須要知道有些button并非橫向的,所以長(zhǎng)不一定大于寬度。所以須要先推斷獲取到最長(zhǎng)與最短,然后進(jìn)行計(jì)算獲取到開(kāi)始的半徑與結(jié)束的半徑。這里有一個(gè)我的思路圖:
我們知道在 Android 中都是以左上腳為圓心。然后右邊為X正數(shù)。下邊為Y正數(shù)。
所以建立了如上坐標(biāo)系。
藍(lán)色矩形區(qū)域代表button。藍(lán)色點(diǎn)代表點(diǎn)擊的點(diǎn)。
灰色矩形代表點(diǎn)擊后的開(kāi)始區(qū)域,然后4邊開(kāi)始擴(kuò)散開(kāi)。以上就是一個(gè)簡(jiǎn)單的原理。當(dāng)然思路有些跳躍,假設(shè)不懂能夠在下邊評(píng)論我都會(huì)進(jìn)行回復(fù)的。
第五步:畫(huà)畫(huà)。對(duì)就是畫(huà)畫(huà)。這一步就是利用上面的半徑和畫(huà)筆顏色進(jìn)行實(shí)際的繪制。
這里須要了解的是:
1:畫(huà)畫(huà)是在:“onDraw(Canvas canvas)” 方法中完畢
2:在畫(huà)板(Canvas)上是分層級(jí)的。簡(jiǎn)單說(shuō)就是先畫(huà)背景然后畫(huà)房子,然后畫(huà)人。最后畫(huà)人的一些小細(xì)節(jié) 自底向上的流程
3:畫(huà)板每次畫(huà) 都是新的畫(huà)板。預(yù)示著你每次都須要從背景畫(huà)起然后才到人。在編程中就是每次?“onDraw(Canvas canvas)” 方法中的畫(huà)板(Canvas?)都是新的(New)。
說(shuō)了那么多事實(shí)上非常easy,由于復(fù)雜的都在上一步中完畢了。
?“onDraw(Canvas canvas)” 源代碼例如以下:
@Overrideprotected void onDraw(Canvas canvas) {canvas.save();canvas.drawCircle(paintX, paintY, radius, backgroundPaint);canvas.restore();super.onDraw(canvas);}在這里我們先保存了畫(huà)板的狀態(tài)。然后畫(huà)一個(gè)圓,然后恢復(fù)上一次的狀態(tài),然后調(diào)用父類(lèi)進(jìn)行后面的繪制工作。這里解釋一下:
1.為什么 “super.onDraw(canvas)” 須要放在最后調(diào)用?
由于畫(huà)板是分層級(jí)的,當(dāng)調(diào)用 “super.onDraw(canvas)” 的時(shí)候進(jìn)行的工作是繪制字體那些。假設(shè)放在前面調(diào)用那么造成的后果是我們的圓會(huì)覆蓋到字體上面。
所以我們須要先畫(huà)圓背景。
2.為什么僅僅有一次畫(huà)圓操作(canvas.drawCircle())?
由于在半徑屬性中調(diào)用了?“invalidate()” ,當(dāng)每次變化半徑值的時(shí)候?qū)⑦M(jìn)行一次 “onDraw(canvas)” 操作,也就畫(huà)一次圓,在一定時(shí)間內(nèi)高速反復(fù)畫(huà)半徑逐漸增大的圓的時(shí)候就形成了動(dòng)畫(huà)效果。
最后給出這次控件的代碼:
start - paintY : paintY) * 1.15f; float endRadius = (end / 2 > paintX ? end - paintX : paintX) * 0.85f; //新建動(dòng)畫(huà) AnimatorSet set = new AnimatorSet(); //加入變化屬性 set.playTogether( //半徑變化 ObjectAnimator.ofFloat(this, mRadiusProperty, startRadius, endRadius), //顏色變化 黑色到透明 ObjectAnimator.ofObject(this, mBackgroundColorProperty, new ArgbEvaluator(), Color.BLACK, Color.TRANSPARENT) ); // 設(shè)置時(shí)間 set.setDuration((long) (1200 / end * endRadius)); //先快后慢 set.setInterpolator(new DecelerateInterpolator()); set.start(); } private Property<MaterialButton, Float> mRadiusProperty = new Property<MaterialButton, Float>(Float.class, "radius") { @Override public Float get(MaterialButton object) { return object.radius; } @Override public void set(MaterialButton object, Float value) { object.radius = value; //刷新Canvas invalidate(); } }; private Property<MaterialButton, Integer> mBackgroundColorProperty = new Property<MaterialButton, Integer>(Integer.class, "bg_color") { @Override public Integer get(MaterialButton object) { return object.backgroundPaint.getColor(); } @Override public void set(MaterialButton object, Integer value) { object.backgroundPaint.setColor(value); } }; }
當(dāng)然興許的工作還有:不同的顏色的button,button屬性的問(wèn)題。
介于大家可能沒(méi)有 Android Studio 無(wú)法看到效果,特意把 Apk 上傳了,假設(shè)Eclipse不知道怎么導(dǎo)入的話 就加我QQ。我給你說(shuō)一下!
地址:APK
這些我都在個(gè)人的項(xiàng)目中完畢了。大家拿去試試:
Genius-Android
進(jìn)階:[Material Design] MaterialButton 效果進(jìn)階 動(dòng)畫(huà)自己主動(dòng)移動(dòng)進(jìn)行對(duì)齊效果
轉(zhuǎn)載于:https://www.cnblogs.com/jhcelue/p/6804052.html
總結(jié)
以上是生活随笔為你收集整理的[Material Design] 教你做一个Material风格、动画的button(MaterialButton)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 算法练习-随机数
- 下一篇: 让Lua支持Linq吧