2012-01-27 15 views
5

Próbuję zbudować LayerDrawable w formacie xml, gdzie górne warstwy będą od czasu do czasu całkowicie zasłaniały niższe warstwy. Aby zmniejszyć dolne warstwy, używam InsetDrawable do owijania kolejnej operacji przeciągania, aby był mniejszy niż pełny rozmiar widoku. Jednakże niespodziewanie stwierdzam, że każda warstwa umieszczona na wierzchu warstwy zawierającej wkładkę ma również nałożoną na nią wkładkę. Nie mogę znaleźć dokumentacji wspierającej to zachowanie i jestem zdezorientowany, dlaczego tak się stało.Nieoczekiwane zachowanie LayerDrawable podczas rysowania warstw zawierających InsetDrawable's

W poniższym przykładzie wykonuję LayerDrawable z 3 warstwami. Dolna i górna warstwa zawiera rysunki w kształcie owalnym, które mają zająć cały widok. Środkowa warstwa to prostokąt do narysowania wewnątrz InsetDrawable. Kod jest poniżej:

<?xml version="1.0" encoding="utf-8"?> 
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" > 

    <item> 
     <shape android:shape="oval" > 
      <solid android:color="#00ff00" /> 
     </shape> 
    </item> 
    <item> 
     <inset 
      android:insetBottom="4dp" 
      android:insetLeft="4dp" 
      android:insetRight="4dp" 
      android:insetTop="4dp" > 
      <shape android:shape="rectangle" > 
       <solid android:color="#ff0000" /> 
      </shape> 
     </inset> 
    </item> 
    <item> 
     <shape android:shape="oval" > 
      <solid android:color="#0000ff" /> 
     </shape> 
    </item> 

</layer-list> 

Wywołanie setBackgroundDrawable(getResources().getDrawable(drawableId)); moim zdaniem daje zielony owal, który wypełnia cały widok, jak oczekiwano, z czerwonym prostokątem wstawka 4DP zgodnie z oczekiwaniami, ale niebieski owal na górnej warstwy jest również wstawka 4DP i narysowany całkowicie w granicach czerwonego prostokąta.

Oczekuję, że niebieski owal całkowicie zasłoni zielony owal i większość czerwonego prostokąta, ale zamiast tego jest wstawiony wewnątrz czerwonego prostokąta. Czy jest jakikolwiek sposób, aby niebieskie kółko wypełniło widok, a jednocześnie trzymało go na wierzchu?

Odpowiedz

10

Nie widzę również, gdzie jest udokumentowana, ale dopełnienie w kodzie LayerDrawable kumuluje się. Oznacza to, że wypełnienie jednej warstwy wpływa na granice wszystkich wyższych warstw. To z the source for LayerDrawable:

@Override 
protected void onBoundsChange(Rect bounds) { 
    final ChildDrawable[] array = mLayerState.mChildren; 
    final int N = mLayerState.mNum; 
    int padL=0, padT=0, padR=0, padB=0; 
    for (int i=0; i<N; i++) { 
     final ChildDrawable r = array[i]; 
     r.mDrawable.setBounds(bounds.left + r.mInsetL + padL, 
           bounds.top + r.mInsetT + padT, 
           bounds.right - r.mInsetR - padR, 
           bounds.bottom - r.mInsetB - padB); 
     padL += mPaddingL[i]; 
     padR += mPaddingR[i]; 
     padT += mPaddingT[i]; 
     padB += mPaddingB[i]; 
    } 
} 

(. LayerDrawable.getPadding(Rect) podąża tą samą logiką) Ponieważ InsetDrawable wykorzystuje swoje wypustki wypychania (jak documented), to wyjaśnia zachowanie jesteś widząc.

Myślę, że to kiepska decyzja dotycząca projektu, ale jakoś się z tym uporałeś, obawiam się. Nie sądzę, żeby można go było przesłonić.

+0

Zgadzam się. Wydaje się sprzeczne z intuicją, że wciągany pojemnik w taki sposób może wpływać na przeciąganie pojemnika. Dziękuję za Twoją odpowiedź. – happydude

+0

Wygląda na to, że właściwość 'paddingMode' została dodana w celu rozwiązania tego problemu. Ale jak możemy zachować zgodność na starszych platformach? – 500865

+0

Jeszcze gorzej w selektorze, gdzie wydaje się wpływać nawet na różne stany! – JohnyTex

2

Odpowiedź Teda jest najlepszą odpowiedzią, ale podzielę się tym rozwiązaniem, które mi pomogło. W szczególności miałem problemy z paddingiem z TextView, więc zrobiłem niestandardowy TextView zamiast tego, który ignoruje podkładanie tła.

public class HackTextView extends TextView { 

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

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

    public HackTextView(Context context) { 
     super(context); 
    } 

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 
    @Override 
    public void setBackground(Drawable background) { 
     super.setBackground(hackDrawable(background)); 
    } 

    @Override 
    public void setBackgroundDrawable(Drawable background) { 
     super.setBackgroundDrawable(hackDrawable(background)); 
    } 

    private Drawable hackDrawable(Drawable background){ 
     return new LayerDrawable(new Drawable[]{background}){ 
      @Override 
      public boolean getPadding(Rect padding) { 
       padding.set(0, 0, 0, 0); 
       return false; 
      } 
     }; 
    } 

} 
+0

To jest dokładnie to, czego potrzebowałem. Chciałem niestandardowe tło, które nie pasowało do rozmiaru treści i nie wpłynęło na rozmiar treści, ponieważ mam obrazy z marginesami ujemnymi nad tłem. Dzięki! – shane

Powiązane problemy