2013-07-23 37 views
6

所以,我有一個很奇怪的設置,並且出現了一些奇怪的可視化錯誤。基本上,我在相對佈局中有兩個視圖:第一個只是一個ImageView背景圖像;二是相同的背景圖片,但模糊,給人一種背後毛玻璃效果:Invalidate()實際上並沒有重繪兒童

<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" /> 

... 

模糊的背景只應HalvedLinearLayout_視圖,滾動起來的背後,所以我需要模糊的背景面膜本身上面HalvedLinearLayout_所以非模糊的背景顯示通過:

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

現在的問題是,一切正常,因爲它應該,除了巨大的明顯的事實,當你滾動了滾動,則blurredBackground竟平OVER HalvedLinearLayout_,刪除其中的按鈕。 (但只有一半,有時候,有時候它會沒問題,有時候按鈕的一半會被拉過,另一半會被保留......各種奇怪的毛刺)。

我開始調試了,我注意到一些有趣的東西:在rootView上調用invalidate()實際上並不會使所有的子節點失效。我推翻所有的無效和借鑑功能與一些記錄的東西:

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

,現在當我看日誌,該rootView.invalidate()是當我滾動射擊,但孩子從來沒有重繪:

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 

如何強制孩子在正確的順序中重畫?現在我猜他們會按順序亂畫,這就是爲什麼模糊的背景畫在其他東西上。

這裏的毛刺的截圖:

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

+0

您是否試過requestLayout()?這應該刷新子視圖。 – Cata

+0

當滾動事件被觸發時,您可以爲blurBackground設置可見性(View.INVISIBLE)。 – droideckar

+0

@Cata:我剛剛嘗試requestLayout()。它仍然做同樣的事情。 – phreakhead

回答

1

好吧,我想通了,如何擺脫毛刺,至少:所有我需要做的就是變化「Region.Op.REPLACE」與「Region.Op.INTERSECT」,現在它的工作原理!

Invalidate()仍然不會重繪孩子,但我想我會讓它滑過它的工作。

+1

'invalidate'不會重繪任何東西。它只是將區域標記爲無效,這會導致Android在繪圖管道中開始重繪。 –

2

我遇到了同樣的問題invalidate(),由於在SO上沒有很好的答案,我想我會發布我的解決方案。

這是一個循環遍歷ViewGroup的所有子視圖的遞歸函數。如果孩子是ViewGroup,它會遞歸併搜索孩子。否則,它會對孩子打電話invalidate()(這是終止的情況)。

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

參數layout應該能夠成爲使之成爲一個相當普遍的解決方案ViewGroup型(LinearLayoutRelativeLayout等)的任何東西。

這是爲我的目的工作,但我沒有把它進行徹底的測試。如果有任何錯誤,請評論並告訴我。