2013-02-18 121 views
11

我想擴展LinearLayout,以便在繪製佈局時在其下面添加陰影。我玩過覆蓋onDraw的方法,但我有點失落。任何幫助,甚至圖書館的建議,將不勝感激!擴展Android View類以添加陰影

下面是我試圖實現的投影視圖示例。我不相信我可以在這裏使用九個補丁,因爲我需要視圖的內容在白框內。這意味着我需要知道邊界與PNG結束之間的距離。但是我相信不同的屏幕密度意味着這個距離將永遠是相同的PX但不是相同的DP。

所以很清楚,我需要一種擴展View類的方法,以便在添加到佈局時在其下繪製陰影。請不要XML或9Patch解決方案。

enter image description here

感謝

傑克

+0

我想你可以繪製一個黑色矩形具有視圖的大小,然後在它上面畫出你的看法,但翻譯一點點的向下和向右(或者向下和向左,不管你想要什麼)。 – 2013-02-18 07:10:10

+0

請你詳細說明一下如何做到這一點? – JackMahoney 2013-02-19 04:07:58

+0

'這是一個例子。我無法使用9貼片「 爲什麼不能?這是最好和最簡單的方法。 – JanithaR 2013-02-20 04:34:27

回答

14

我同意你的問題的意見:方案陰影效果的影響是一個不錯的選擇,你可以實現一個簡單的9patch(或一組人)相同的效果就像說here

順便說一句,我太好奇了,下班後我就結束了黑客解決方案。

給出的代碼是一個測試,並應旨在作爲一個簡單證明了概念(所以請不要downvote)。有些所示的操作是相當昂貴,並可能在表演嚴重影響(有很多例子身邊,看herehere得到一個想法)。它應該是最後的手段解決方案只適用於一次顯示的組件。

public class BalloonView extends TextView { 

    protected NinePatchDrawable bg; 
    protected Paint paint; 
    protected Rect padding = new Rect(); 
    protected Bitmap bmp; 

    public BalloonView(Context context) { 
    super(context); 
init(); 
    } 

    public BalloonView(Context context, AttributeSet attrs) { 
    super(context, attrs); 
init(); 
    } 

    public BalloonView(Context context, AttributeSet attrs, int defStyle) { 
    super(context, attrs, defStyle); 
    init(); 
    } 

    @SuppressLint("NewApi") 
    protected void init() { 
    // decode the 9patch drawable 
    bg = (NinePatchDrawable) getResources().getDrawable(R.drawable.balloon); 

    // get paddings from the 9patch and apply them to the View 
    bg.getPadding(padding); 
    setPadding(padding.left, padding.top, padding.right, padding.bottom); 

    // prepare the Paint to use below 
    paint = new Paint(); 
    paint.setAntiAlias(true); 
    paint.setColor(Color.rgb(255,255,255)); 
    paint.setStyle(Style.FILL); 

    // this check is needed in order to get this code 
    // working if target SDK>=11 
    if(Build.VERSION.SDK_INT >= 11) 
     setLayerType(View.LAYER_TYPE_SOFTWARE, paint); 

    // set the shadowLayer 
    paint.setShadowLayer(
     padding.left * .2f, // radius 
     0f, // blurX 
     padding.left * .1f, // blurY 
     Color.argb(128, 0, 0, 0) // shadow color 
    ); 
    } 

    @Override 
    protected void onDraw(Canvas canvas) { 
    int w = getMeasuredWidth(); 
    int h = getMeasuredHeight(); 

    // set 9patch bounds according to view measurement 
    // NOTE: if not set, the drawable will not be drawn 
    bg.setBounds(0, 0, w, h); 

    // this code looks expensive: let's do once 
    if(bmp == null) { 

     // it seems like shadowLayer doesn't take into account 
     // alpha channel in ARGB_8888 sources... 
     bmp = Bitmap.createBitmap(w, h, Config.ARGB_8888); 

     // draw the given 9patch on the brand new bitmap 
     Canvas tmp = new Canvas(bmp); 
     bg.draw(tmp); 

     // extract only the alpha channel 
     bmp = bmp.extractAlpha(); 
    } 

    // this "alpha mask" has the same shape of the starting 9patch, 
    // but filled in white and **with the dropshadow**!!!! 
    canvas.drawBitmap(bmp, 0, 0, paint); 

    // let's paint the 9patch over... 
    bg.draw(canvas); 

    super.onDraw(canvas); 
    } 
} 

首先,爲了得到綱領性陰影,你必須處理Paint.setShadowLayer(...)喜歡說here。基本上你應該定義一個陰影層對於Paint對象用於繪製您的自定義視圖的Canvas。不幸的是,你不能使用Paint對象來繪製一個NinePatchDrawable,所以你需要將它轉換成一個Bitmap(1st hack)。此外,看起來陰影圖層無法在ARGB_8888圖像中正常工作,所以爲了獲得適當的陰影,我發現的唯一方法是繪製給定的NinePatchDrawable(第2個黑客)的alpha蒙版,它位於其下方。

這裏有一對夫婦sshots的(在Android [email protected][email protected]測試) enter image description here enter image description here

編輯:只是要徹底,我連着在測試中使用的9patch (放置在res/drawable/mdpienter image description here

+0

感謝您的回答我會嘗試一下。但我不同意9Patch。 9Patch的非伸縮區域對於每個屏幕密度都不會縮放,因此它們在高密度屏幕上會顯得更小 - 因此,陰影區域會更小,我不知道在哪裏放置容器的兒童填充物 – JackMahoney 2013-02-21 00:58:50

+2

@JackMahoney對不起但你錯了。只要看看上面的截圖:有2個不同的**真實設備**:320x480 | mdpi,720x1280 | xhdpi。在這兩種情況下使用相同的9patch。您可以在每個sshot中以像素爲單位來測量氣球的圓角,並且您會注意到在xhdpi上的寬度比在mdpi上寬2倍。還有填充物(在9patch中定義)相應地放大。 – 2013-02-21 10:33:32

+0

@ a.bertucci你能爲我添加一個示例項目嗎? – linker 2013-08-27 17:45:10

3

嘗試這種技術。

container_dropshadow.xml

`

<!-- Drop Shadow Stack --> 
<item> 
    <shape> 
     <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" /> 
     <solid android:color="#00CCCCCC" /> 
    </shape> 
</item> 
<item> 
    <shape> 
     <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" /> 
     <solid android:color="#10CCCCCC" /> 
    </shape> 
</item> 
<item> 
    <shape> 
     <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" /> 
     <solid android:color="#20CCCCCC" /> 
    </shape> 
</item> 
<item> 
    <shape> 
     <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" /> 
     <solid android:color="#30CCCCCC" /> 
    </shape> 
</item> 
<item> 
    <shape> 
     <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" /> 
     <solid android:color="#50CCCCCC" /> 
    </shape> 
</item> 

<!-- Background --> 
<item> 
<shape> 
     <solid android:color="@color/white" /> 
    <corners android:radius="3dp" /> 
</shape> 
</item> 

然後,你可以把它應用到一個XML佈局像

的LinearLayout的android背景:背景=「@ drawable/container_dropshadow「

`

+0

嗯,這看起來有點煩躁。你能解釋一下這背後的想法嗎?看起來你剛剛堆疊了一系列相互重疊的盒子。這不會創建漸變。 – JackMahoney 2013-02-19 04:07:38

+1

我覺得問題是你的一面,邁克爾還提出了一個邏輯。但你告訴了請詳細說明。我也提出了一個建議方式。但你告訴同樣的事情請解釋。首先你在谷歌搜索。很多東西在那裏。如果你找不到確切的解決方案,那麼來堆棧溢出,然後提出你的問題。我們無法發送完整的代碼片段來完成您的工作。感謝您的理解。所有最好的:) – AndroidEnthusiastic 2013-02-19 06:16:05

+0

答案是錯誤的。每個項目的填充是相同的,所以它創建一個純色而不是一個漸變 – JackMahoney 2013-02-20 09:19:25

3

這是丟棄陰影的任何東西,或者佈局,按鈕等 background.xml的最簡單的方法

<?xml version="1.0" encoding="utf-8"?> 
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> 
     <item > 
      <shape 
       android:shape="rectangle"> 
      <solid android:color="@android:color/darker_gray" /> 
      <corners android:radius="5dp"/> 
      </shape> 
     </item> 
     <item android:right="1dp" android:left="1dp" android:bottom="2dp"> 
      <shape 
       android:shape="rectangle"> 
      <solid android:color="@android:color/white"/> 
      <corners android:radius="5dp"/> 
      </shape> 
     </item> 
    </layer-list> 
在main.xml中

<LineaLayout 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
android:background="@drawable/background" 
/> 
+0

喜歡這個解決方案!對(參考http://www.google.com/design/spec/style/color.html#color-color-palette)和< item android:bottom =「2dp」>我可以模仿谷歌播放的按鈕。 – Milanor 2014-11-21 09:47:29

+0

這也不創建一個漸變,只有一個純色。 – 2016-04-22 15:27:49