2013-02-18 2 views
11

Ich möchte LinearLayout erweitern, sodass beim Zeichnen meines Layouts ein Schlagschatten darunter eingefügt wird. Ich habe herum gespielt, um die Methode zu überschreiben, aber ich bin ein bisschen verloren. Jede Hilfe mit dieser oder sogar Bibliothek Vorschläge würde sehr geschätzt werden!Erweitern der Android View-Klasse zum Hinzufügen eines Dropshadows

Hier ist ein Beispiel für die Schlagschattenansicht, die ich erreichen möchte. Ich glaube nicht, dass ich hier einen neunen Patch verwenden kann, weil ich brauche, dass der Inhalt der Ansicht innerhalb der weißen Box liegt. Dies würde bedeuten, dass ich die Entfernung zwischen der Grenze und dem Ende der PNG kennen müsste. Ich glaube jedoch, dass unterschiedliche Bildschirmdichten bedeuten, dass diese Entfernung immer dieselbe PX, aber nicht dieselbe DP sein wird.

Also, um klar zu sein, ich brauche eine Möglichkeit, die View-Klasse zu erweitern, so dass ein Schlagschatten darunter gezeichnet wird, wenn es zu einem Layout hinzugefügt wird. Keine XML- oder 9Patch-Lösungen bitte.

enter image description here

Dank

Jack

+0

Ich glaube, Sie ein schwarzes rect die Größe Ihrer Ansicht hat ziehen könnte, und dann auf es Ihrer Ansicht nach zeichnen aber ein wenig nach unten übersetzt und Recht (oder unten und links, was immer du willst). –

+0

Könnten Sie bitte erläutern, wie man das machen könnte? – JackMahoney

+0

'Hier ist ein Beispiel. Ich kann auch kein 9-Patch verwenden. Warum nicht? Es ist der beste und einfachste Ansatz. – JanithaR

Antwort

14

Ich stimme mit den Kommentaren zu Ihrer Frage: programmatischer Schatten-Effekt eine schlechte Wahl ist, und man konnte den gleichen Effekt mit einem einfachen 9patch (oder einem Satz von ihnen) wie angegeben here erreichen.

BTW Ich war zu neugierig, und ich endete mit einer Lösung nach der Arbeit zu hacken.

Der vorgestellte Code ist ein Test und sollte als einfacher Proof-of-Concept (also bitte nicht nach unten) gedacht sein. Einige der gezeigten Operationen sind ziemlich teuer, und können ernsthaft Auswirkungen auf die Leistungen (Es gibt viele Beispiele herum, schauen here, here, um eine Idee zu bekommen). Es sollte eine letzte Lösung nur für eine Komponente sein, die einmal gezeigt wird.

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); 
    } 
} 

Zunächst einmal, um Sie programmatische Schlagschatten zu bekommen haben mit Paint.setShadowLayer(...) wie angegeben here beschäftigen. Grundsätzlich sollten Sie eine Schattenschicht für das Objekt Paint definieren, das zum Zeichnen auf die Canvas Ihrer benutzerdefinierten Ansicht verwendet wird. Leider können Sie kein Paint Objekt verwenden, um ein NinePatchDrawable zu zeichnen, also müssen Sie es in eine Bitmap konvertieren (1. Hack).Außerdem scheint es so, als könnten Schatten-Layer mit ARGB_8888-Bildern nicht richtig funktionieren. Daher habe ich die einzige Möglichkeit, einen richtigen Schatten zu erhalten, darin gesehen, die Alpha-Maske des angegebenen NinePatchDrawable (2. Hack) direkt unter sich zu zeichnen.

Hier ein paar sshots (getestet auf Android [email protected] und [email protected]) enter image description here enter image description here

Edit: nur gründlich zu sein, angebracht ich die 9patch im Test verwendeten (platziert in res/drawable/mdpi) enter image description here

+0

Dank für dich antworte ich es probiere es aus. Aber ich stimme dem 9Patch nicht zu. Die nicht gestreckten Bereiche eines 9Patch werden nicht für jede Bildschirmdichte skaliert, so dass sie auf High-Density-Bildschirmen kleiner erscheinen - daher wird der Dropshadow-Bereich kleiner und ich weiß nicht, wo ich die Kinder des Containers mit Padding positionieren soll – JackMahoney

+2

@JackMahoney aber du liegst falsch. Schauen Sie sich die obigen Screenshots an: Es gibt 2 verschiedene ** reale Geräte **: 320x480 | mdpi, 720x1280 | xhdpi. In beiden Fällen wird das gleiche 9patch verwendet. Sie können die runde Ecke des Ballons in jedem Sshot in Pixeln messen und Sie werden feststellen, dass auf xhdpi 2x breit ist als auf mdpi. Auch Paddings (definiert im 9patch) skalieren entsprechend. –

+0

@ a.bertucci kannst du bitte ein Beispielprojekt für mich hinzufügen? – linker

3

diese Technik versuchen.

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> 

Dann Sie es in eine XML-Layout als Hintergrund wie

Linearlayout android anwenden können: background =" @ Zeichnungs/container_dropshadow "

`

+0

Hm das sieht ein bisschen zappelig aus. Kannst du erklären, was die Idee dahinter ist? Es sieht so aus, als hättest du gerade eine Reihe übereinander gepackt. Das wird keinen Gradienten erzeugen. – JackMahoney

+1

Ich denke, Problem ist deine Seite, Michael schlug auch eine Logik vor. Aber du hast gesagt, bitte erzähle es. Ich habe auch einen Vorschlag Weg gezeigt.Aber du hast dasselbe gesagt, bitte erkläre es. Zuerst haben Sie in Google suchen. Viel Zeug ist da. Wenn Sie keine genaue Lösung finden können, dann kommen Sie zum Stack-Überlauf und dann stellen Sie Ihre Frage. Wir können Ihnen keinen vollständigen Ausschnitt senden, um Ihre Arbeit zu erledigen. Danke für Ihr Verständnis. Alles Gute :) – AndroidEnthusiastic

+0

Die Antwort ist falsch. Die Auffüllung für jedes Einzelteil ist das selbe, also schafft es eine feste Farbe nicht eine Steigung – JackMahoney

3

Dies ist die einfachste Art und Weise Schatten zu jeder Sache fallen zu lassen entweder Layout Taste usw. 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> 

in Ihrem main.xml

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

liebte diese Lösung! mit einer kleinen Änderung an (siehe http://www.google.com/design/spec/style/color.html#color-color-palette) und < item android: bottom = "2dp"> Ich könnte Google Play Button nachahmen. – Milanor

+0

Dies erzeugt auch keinen Farbverlauf, nur eine Farbe. –

Verwandte Themen