網(wǎng)上搜索到的做法
- 加一個(gè)背景,android:background="@android:drawable/dialog_holo_light_frame 這個(gè)安卓自帶的圖片,設(shè)置為背景,就帶有陰影效果。
- 通過使用5.0以上的方法,
View.setElevation()方法,可以繪制陰影效果。 - 通過添加padding,在view的邊框上通過canvas繪制陰影。
為何還要自己做的原因
針對(duì)以上的所有方式,都不能很好的解決,原因有下:
- 方案一,不能動(dòng)態(tài)的改變背景顏色,而且如果view本身需要設(shè)置一個(gè)背景,此時(shí)有兩個(gè)背景就會(huì)沖突,所以并不是通用的解決方案。
- 方案二,現(xiàn)有的api不能支持所有的安卓版本繪制陰影,而且不能修改陰影顏色。
- 方案三,改變view的大小,對(duì)布局有所影響。
解決方案
方案1.0
最開始,想到了系統(tǒng)Paint自帶的方法。
//陰影只能在View.LAYER_TYPE_SOFTWARE 環(huán) 境 下 工 作
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
paint.setShadowLayer(10, 10, 5, Color.BLACK);
通過這種方式,的確可以畫出來陰影效果,但是此時(shí)并不能將陰影畫在view的外面,其實(shí)還是畫在了view的上面,也就是間接改變了view的大小。而且還必須設(shè)置View.LAYER_TYPE_SOFTWARE。
//首先獲取已經(jīng)被裁減過的畫布大小
clipBounds = canvas.getClipBounds();
//改變畫布大小 也可以使用insert方法。
clipBounds.set(left, top, right, bottom);
//將畫布的大小進(jìn)行替換,達(dá)到增大畫布的效果。Region.Op.REPLACE 是關(guān)鍵
canvas.clipRect(clipBounds, Region.Op.REPLACE);
或者:
設(shè)置不裁減孩子大小
viewgroup.setClipChildren(false);
設(shè)置可以在padding上畫圖
viewgroup.setClipPadding(false);
通過上面兩種方式,就可以將view所在的區(qū)域變大。但是第二種方式是將所有的view根節(jié)點(diǎn)設(shè)置為不裁剪,就是全局畫布大小,而且要設(shè)置所有view容器,所以方法不具有通用性,不使用。
方案二指定了想要擴(kuò)大的view大小。接著使用上面陰影的設(shè)置方法,發(fā)現(xiàn)沒有任何的效果。后來不斷測(cè)試,發(fā)現(xiàn)了this.setLayerType(View.LAYER_TYPE_SOFTWARE, null); 和 改變畫布大小的這段代碼沖突,如果設(shè)置了View.LAYER_TYPE_SOFTWARE就不能改變畫布的大小。
由此,只能另選方法了。
方案2.0
必須要將畫布大小進(jìn)行放大,所以更改畫布大小的代碼必不可少。所以丟棄了 setShadowLayer 的方法。自己來繪制陰影效果。
由于陰影可能會(huì)出現(xiàn)在一個(gè)view的上下左右四個(gè)角,為了減少判斷,就直接在view外面繪制一個(gè)圈,分解為9個(gè)矩形。這是因?yàn)殛幱暗乃膫€(gè)角需要圓滑一些,所以不是正常的矩形,所以共計(jì)上下左右+四個(gè)角+中心共9個(gè)矩形。這樣做的好處就是簡(jiǎn)化了一部分邏輯,但是增加了繪制成本。誰有更好的繪制思路,可以給我留言。
首先在繪制前,設(shè)置陰影的大小,偏移量,生成對(duì)應(yīng)的Gradient對(duì)象,上下左右用LinearGradient,四個(gè)角用RadialGradient。再根據(jù)view的大小來找到每個(gè)矩形的頂點(diǎn)坐標(biāo),生成對(duì)應(yīng)的Rect。用來繪制圖像。
在onDraw中,通過循環(huán)渲染9個(gè)矩形。繪制完成后,把和原view重疊的部分直接剪切掉,就形成了一個(gè)帶有陰影效果的view。裁減方式如下:
Path rectPath = new Path();
Path viewPath = new Path();
viewPath.addRect(0, 0, viewWidth, viewHeight, Path.Direction.CW);
rectPath.addRect(left, top, right, bottom, Path.Direction.CW);
rectPath.op(rectPath, viewPath, Path.Op.DIFFERENCE);
canvas.drawPath(rectPath, mPaint);
通過這種方式,就可以直接裁減掉重疊的部分,關(guān)于Path的使用請(qǐng)google。
通過如上的方式,就可以繪制一個(gè)陰影了。
結(jié)語(yǔ)
目前還不夠完善,希望大家多提寶貴意見。有問題,評(píng)論留言。郵箱:lybvinci@foxmail.com 。