最近在項目碰到一個比較頭疼的項目,設(shè)計師需要給ui圖中的一些按鈕之類的東西添加陰影街图。乍一看設(shè)計圖阻荒,這沒啥嘛,咱們Android中不是有這個屬性嘛漩怎,于是擼起袖子開搞:
<TextView
android:id="@+id/btn_test_performance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:elevation="5dp"
android:text="@string/hello"
android:background="@drawable/shape_round_white"
android:padding="20dp"
android:layout_marginTop="10dp"
android:layout_gravity="center"/>
代碼敲完跑起來看一下效果圖勋颖,恩,效果還可以勋锤。于是把所有需要陰影的控件全部加上android:elevation屬性饭玲,美滋滋,有api就是好叁执。事情發(fā)展得很順利茄厘,直到我們設(shè)計師找到我,“你是Android設(shè)計師吧谈宛,你這個顏色有點不對啊次哈,我們標記的顏色比較淡,你這個顏色有點深”吆录。窑滞。。瞬間凌亂,wtf,這個顏色是系統(tǒng)自帶的啊哀卫,我怎么控制巨坊。于是上網(wǎng)google一下,怎樣修改elevation的顏色屬性此改。一頓搜索后趾撵,無果。禍不單行共啃,我們測試工程師也找了過來占调,“你這個頁面不對啊,我們設(shè)計圖上這里有陰影勋磕,你這里啥也沒有”妈候。?挂滓?苦银?什么鬼,不可能啊赶站,我這里都有的幔虏,你這個包有問題吧。于是把測試的測試機拿過來自己裝上一個一跑贝椿。想括。。尼瑪烙博,什么鬼瑟蜈,真沒有≡埽回頭再看一遍自己的代碼發(fā)現(xiàn)在android:elevation上有一個黃色的警告铺根,之前沒注意,鼠標放上去一看乔宿,
位迂。。原來是版本適配問題详瑞,看來是api是不能用了掂林,只能通過一些其他的手段去實現(xiàn)了。經(jīng)過漫長的思考人生后坝橡,想出下面幾個思路:
- 自定義shape.xml drawable文件去給控件設(shè)置背景泻帮,使用Gradient漸變色屬性實現(xiàn)陰影樣式。
- 找ui設(shè)計師驳庭,讓他們切一個帶陰影的圖給我們(找ui能解決的都不是事~)
- 自己代碼實現(xiàn)一個帶背景的自定義view
經(jīng)過不停地自我推翻以及方案被否定后還是留下了第三個方案刑顺,主要原因如下:
- 第一個方案的漸變色不支持四周向中間的漸變氯窍,只能支持線性或者環(huán)裝形式漸變饲常,這兩種都不滿足需要蹲堂,因為陰影本身是一個四周一層很淡的顏色包圍,在一個矩形框的層面上顏色大概一致贝淤,所以這個思路無法實現(xiàn)這個需求柒竞,拋棄。
- 第二個方案詢問了一下我們ui播聪。朽基。他們給出的結(jié)果是如果使用切圖的話那標注的話很難標,身為一個優(yōu)秀的設(shè)計師大多對像素點都和敏感离陶,界面上的像素點有一點不協(xié)調(diào)那都是無法容忍的稼虎。。
- 那么就只剩下第三個方案了
經(jīng)過資料查詢招刨,發(fā)現(xiàn)有兩個方式用來寫陰影很合適霎俩。在我們Android中自定義view的時候有以下兩個方法,我們可能用的都不是很多:
-
paint.setShadowLayer(float radius, float dx, float dy, int shadowColor);
這個方法可以達到這樣一個效果沉眶,在使用canvas畫圖時給視圖順帶上一層陰影效果打却。
簡單介紹一下這幾個參數(shù):
radius: 陰影半徑,主要可以控制陰影的模糊效果以及陰影擴散出去的大小谎倔。
dx:陰影在X軸方向上的偏移量
dy: 陰影在Y軸方向上的偏移量
shadowColor: 陰影顏色柳击。
終于找到了設(shè)置顏色的,通過設(shè)置shadowColor來控制視圖的陰影顏色片习。
我們試一下使用paint.setShadowLayer(10, 0, 0, Color.RED)的效果:
圖3
這個是在4.1的設(shè)備上的效果圖捌肴,上面的hello world使用elevation,可以看到絲毫沒有效果藕咏。下面是使用自定義view的方式畫出來的一個圖状知,可以看到效果是很nice的,這個也實現(xiàn)了顏色的可調(diào)整性侈离,完美解決试幽。
這里也順帶說下第二種思路,這邊我試了一下效果沒這邊好卦碾,有可能是我沒調(diào)整好铺坞,個人覺得應(yīng)該也是能實現(xiàn)這種效果的, paint還有一個方法是paint.setMaskFilter();這里通過設(shè)置BlurMaskFilter()應(yīng)該也能達到這種效果洲胖。
對于第一種方案济榨,經(jīng)過思考決定封裝成一個Viewgroup比較合適,將需要設(shè)置陰影的視圖放到Viewgroup里面绿映。其中涉及到幾個屬性擒滑,陰影的寬度腐晾,view到Viewgroup的距離,如果視圖和父布局一樣大的話丐一,那陰影就不好顯示藻糖,如果要能夠顯示出來就必須設(shè)置clipChildren=false。還有就是視圖自帶的圓角库车,大部分背景都是有圓角的巨柒,比如上圖中的圓角,需要達到高度還原陰影的效果就是的陰影的圓角和背景保持一致柠衍。
這里把這幾個屬性抽成自定義屬性:
<declare-styleable name="ShadowContainer">
<attr name="containerShadowColor" format="color"/>
<attr name="containerShadowRadius" format="dimension"/>
<attr name="containerDeltaLength" format="dimension"/>
<attr name="containerCornerRadius" format="dimension"/>
<attr name="deltaX" format="dimension"/>
<attr name="deltaY" format="dimension"/>
</declare-styleable>
- containerShadowColor:設(shè)置陰影顏色
- containerShadowRadius:設(shè)置陰影的擴展距離
- containerDeltaLength:設(shè)置子View到ShadowContainer的距離
- containerCornerRadius:設(shè)置子View背景的圓角大小
- deltaX: 設(shè)置陰影向下移動距離
-
deltaY: 設(shè)置陰影在Y軸移動距離
圖4
這里使用畫圖的方式解釋一下這幾個參數(shù):
圖中的紅色區(qū)域是需要設(shè)置陰影的View洋满,外部黑色邊框包裹的區(qū)域是ShadowContainer,中間的白色部分是陰影展示的區(qū)域珍坊,這塊的大小根據(jù)設(shè)置的containerDeltaLength控制牺勾。這里打個比方,如果目標view需要距離左邊20dp的話阵漏,而中間的containerdeltaLength為10dp驻民,則只需要將ShadowContainer的marginLeft設(shè)置為10dp就可以了,這樣可以完美控制子view的位置袱饭。
此外川无,containerShadowRadius影響的是陰影在空白區(qū)域的占比情況,如果containerShadowRadius小一點的話陰影倒是不大, 但是如果太大的話那么空白區(qū)域可能裝不下陰影面積虑乖。這里需要看情況調(diào)整懦趋。
使用方式:
<example.chenj.com.apptest.ShadowContainer
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:layout_gravity="center"
app:containerCornerRadius="5dp"
app:containerDeltaLength="5dp"
app:containerShadowColor="#f00"
app:containerShadowRadius="5dp">
<View
android:layout_width="80dp"
android:layout_height="80dp"
android:background="@drawable/shape_round_white"/>
</example.chenj.com.apptest.ShadowContainer>
效果圖: