2013-07-23 4 views
6

Mam więc dość dziwną konfigurację i dostaję z tego jakieś dziwne wizualne błędy. Zasadniczo mam dwa widoki we względnym układzie: pierwszy to tylko obraz tła ImageView; drugi to ten sam obraz tła, ale niewyraźne dać taki efekt za-matowego szkła:Invalidate() tak naprawdę nie przerysowuje dzieci

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:id="@+id/profile_holder" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" > 

    <!-- background --> 
    <ImageView 
     android:id="@+id/backgroundImage" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:layout_alignParentLeft="true" 
     android:layout_alignParentTop="true" 
     android:layout_marginLeft="0dp" 
     android:layout_marginTop="0dp" 
     android:scaleType="centerCrop" 
     android:src="@drawable/default_logo" /> 

    <!-- blurry background --> 
    <com.custom.MaskedBlurredBackgroundView_ 
     android:id="@+id/blurred_background" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:layout_alignParentLeft="true" 
     android:layout_alignParentTop="true" 
     android:layout_marginLeft="0dp" 
     android:layout_marginTop="0dp" /> 

<ScrollView 
    android:id="@+id/scrolly" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:fillViewport="true" 
    android:layout_alignParentLeft="true" 
    android:layout_alignParentTop="true" > 

      <com.custom.HalvedLinearLayout_ 
       android:paddingTop="100dp" 
       android:id="@+id/profileHolder" 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content" 
       android:orientation="vertical" 
       > 

       <Button 
        android:id="@+id/profileButtonTracks" 
        style="@style/ProfileButtons" 
        android:drawableLeft="@drawable/ic_profile_menu_music" 
        android:text="@string/profile_button_tracks" /> 

... 

niewyraźne tło powinno być tylko z tyłu widoku HalvedLinearLayout_, który przewija się, więc muszę niewyraźne tło do maskować się powyżej HalvedLinearLayout_ więc non-rozmyte tło pokazuje poprzez:

scrolly = ((ScrollView) rootView.findViewById(R.id.scrolly)); 
scrolly.setOnScrollListener(new ScrollView.OnScrollListener() { 

    private boolean hasScrolled = false; 

    @Override 
    public void onScrollChanged(int l, int t, int oldl, int oldt) { 

     if (!hasScrolled) { 
      hasScrolled = true; 
      Logger.action(Logger.Action.BioView, band); 
     } 

     positionMask(); 
    } 
}); 

... 

protected void positionMask() { 
    if (blurredBackground == null) return; 

    Logger.d(TAG, "positionMask() " + rootView.getId()); 

    //blurredBackground.setMaskBottom(blurredBackground.getHeight() - profileHolder.getPaddingTop() - scrollY); 
    blurredBackground.setMaskBottom(profileHolder.getTop() + profileHolder.getPaddingTop() - scrolly.getScrollY()); 
    //blurredBackground.invalidate(); 
    //profileHolder.invalidate(); 
    rootView.postInvalidate(); 
} 

teraz problemem jest to, że wszystko działa jak należy, z wyjątkiem ogromnego rażący fakt, że podczas przewijania Scrollview The blurredBackground faktycznie rysuje OVER the HalvedLinearLayout_, zatrzaskując guziki w nim. (ale tylko w połowie, czasami Czasami będzie dobrze, czasami połowa przycisku zostanie narysowana, a druga połowa zachowana ... wszelkiego rodzaju dziwne usterki.)

Rozpocząłem debugowanie i zauważyłem coś ciekawego: wywoływanie invalidate() na rootView faktycznie nie unieważnia() wszystkich dzieci. I wszystko overrode invalidate i wyciągnąć z niektórych funkcji rejestrowania rzeczy:

public class MaskedBlurredBackgroundView extends BlurredBackgroundView { 
    /*** 
    * Sets the mask to cover everything above the given Y coordinate 
    * @param t Y Coordinate in pixels 
    */ 
    public void setMaskBottom(int y) { 
     maskBottom = y; 
    } 

    private void clipCanvas(Canvas canvas) { 
     Logger.d(TAG, "dispatchDraw clipping: " + maskBottom + ", " + getWidth() + "," + getHeight()); 
     canvas.clipRect(0, maskBottom, getWidth(), getHeight(), Region.Op.REPLACE); 
    } 

    @Override 
    protected void dispatchDraw(Canvas canvas) { 
     canvas.save(); 
     clipCanvas(canvas); 
     super.dispatchDraw(canvas); 

     canvas.restore(); 
    } 
    @Override 
    protected boolean drawChild(Canvas canvas, View child, long drawingTime) { 
     Logger.d(TAG, "drawChild: " + child + getWidth() + "," + getHeight()); 

     return super.drawChild(canvas, child, drawingTime); 
    } 

    @Override 
    public void invalidate() { 
     Logger.d(TAG, "invalidate: " + getWidth() + "," + getHeight()); 
     super.invalidate(); 
    } 

A teraz, gdy patrzę w dzienniku The rootView.invalidate() jest wypalanie kiedy przewijać, ale dzieci nie przerysować:

07-23 12:36:49.328: D/BandDetailFrag(12982): positionMask() 2131165298 
07-23 12:36:49.348: D/BandDetailFrag(12982): positionMask() 2131165298 
07-23 12:36:49.348: D/BandDetailFrag(12982): positionMask() 2131165298 
07-23 12:36:49.368: D/BandDetailFrag(12982): positionMask() 2131165298 
07-23 12:36:49.368: D/BandDetailFrag(12982): positionMask() 2131165298 
07-23 12:36:49.378: D/BandDetailFrag(12982): positionMask() 2131165298 
07-23 12:36:49.398: D/BandDetailFrag(12982): positionMask() 2131165298 
07-23 12:36:49.418: D/BandDetailFrag(12982): positionMask() 2131165298 
07-23 12:36:49.448: D/BandDetailFrag(12982): positionMask() 2131165298 
07-23 12:36:49.478: D/BandDetailFrag(12982): positionMask() 2131165298 

Jak zmusić dzieci do przerysowania, W POPRAWNYM ZAMÓWIENIU? W tej chwili domyślam się, że rysują się nie w porządku i dlatego rozmyte tło rysuje się na wszystko inne.

Oto zrzut ekranu usterki:

screenshot of glitch: see the blurred background masked correctly, but drawing OVER the HalvedLinearLayout_

+0

Czy próbowałeś requestLayout()? To powinno również odświeżyć widoki podrzędne .. – Cata

+0

możesz ustawićVIDibility (View.INVISIBLE) dla blurBackground po uruchomieniu zdarzenia scroll. – droideckar

+0

@Cata: Właśnie próbowałem requestLayout(). Nadal robi to samo. – phreakhead

Odpowiedz

1

Ok, zorientowali się, jak pozbyć się glitching, co najmniej: wszystko, co musiałem zrobić, to zmiana „Region.Op.REPLACE” z "Region.Op.INTERSECT", a teraz działa!

Invalidate() nadal nie przerysowuje dzieci, ale myślę, że pozwolę temu slajdowi teraz, kiedy to działa.

+1

'unieważnić' nie przerysowuje niczego. To po prostu oznacza region jako nieważny, co powoduje, że system Android zaczyna przerysowywać w ramach procesu rysowania. –

2

Wpadłem na ten sam problem z invalidate(), a ponieważ nie ma dobrej odpowiedzi w innym miejscu na SO, pomyślałem, że mogę opublikować moje rozwiązanie.

To jest funkcja rekursywna, która przejdzie przez wszystkie widoki podrzędne ViewGroup. Jeśli dziecko jest ViewGroup, będzie ono rekurencyjne i będzie wyszukiwać dziecko. W przeciwnym razie zadzwoni pod numer invalidate() na dziecko (jest to przypadek zakończenia).

public void invalidateRecursive(ViewGroup layout) { 
    int count = layout.getChildCount(); 
    View child; 
    for (int i = 0; i < count; i++) { 
     child = layout.getChildAt(i); 
     if(child instanceof ViewGroup) 
      invalidateRecursive((ViewGroup) child); 
     else 
      child.invalidate(); 
    } 
} 

Parametr layout powinien móc być coś typu ViewGroup (LinearLayout, RelativeLayout, itd.) Czyni to dość ogólne rozwiązanie.

To działa dla moich celów, ale nie poddałem go dokładnym testom. Jeśli pojawią się jakieś błędy, prosimy o komentarz i daj mi znać.