2017-05-10 3 views
1

Je crée une activité de défilement dans mon application Android. L'activité a un CollapsingToolbarLayout avec effet de parallaxe. Lorsque je fais défiler la mise en page en dessous de la barre d'outils de l'application, elle monte en douceur et la barre d'applications est réduite au titre. ImageView et TextView iront jusqu'au titre. Et quand je fais défiler la mise en page, ils vont tous revenir au début.CollapsingToolbarLayout Scrolling Bug -Parfois, il restera bloqué lors du défilement

Le bug est ici:

quand je l'activité en cours d'exécution sur certains appareils, parfois, quand je fais défiler vers le haut, la mise en page sera stucked là-haut et vers le bas pendant quelques secondes puis, revenez vers le haut. Et quand je cours l'activité sur d'autres appareils, tout ira bien, rien de mal ne s'est passé.

La démo de ce bug: https://share.weiyun.com/1d797a4a92580e1595eacb226f9a92a3

Voici la mise en page:

<?xml version="1.0" encoding="utf-8"?> 
<android.support.design.widget.CoordinatorLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    tools:context="nczz.cn.helloworld.ScrollingActivity" 
    > 
    <android.support.design.widget.AppBarLayout 
     android:id="@+id/app_bar" 
     android:layout_width="match_parent" 
     android:layout_height="@dimen/app_bar_height" 
     android:background="#FA7199" 
     app:layout_scrollFlags="scroll|enterAlways" 
     android:theme="@style/AppTheme.AppBarOverlay"> 

     <nczz.cn.widget.CollapsingImageTextLayout 
      android:id="@+id/imageTextLayout" 
      android:layout_width="match_parent" 
      android:layout_height="match_parent" 
      app:layout_scrollFlags="scroll|exitUntilCollapsed" 
      app:title_id="@+id/test_title" 
      app:text_id="@+id/test_text" 
      app:img_scale="0.6" 
      app:text_scale="0.6" 
      app:text_margin_left="110dp" 
      app:img_id="@+id/test_img" 
      app:img_margin_left="55dp" 
      > 
      <LinearLayout 
       android:id="@+id/test_title" 
       android:layout_width="match_parent" 
       android:layout_height="80dp" 
       android:background="#FA7199" 
       android:gravity="center_vertical" 
       android:orientation="horizontal" 
       > 
       <ImageView 
        android:id="@+id/return_btn" 
        android:layout_width="15dp" 
        android:layout_height="15dp" 
        android:layout_marginLeft="20dp" 
        android:layout_centerVertical="true" 
        android:src="@drawable/left" /> 
      </LinearLayout> 

      <ImageView 
       android:id="@+id/test_img" 
       android:layout_width="80dp" 
       android:layout_height="80dp" 
       android:scaleType="fitXY" 
       android:src="@mipmap/ic_launcher" 
       android:layout_centerInParent="true" 
       android:layout_marginBottom="30dp" 
       /> 

      <TextView 
       android:id="@+id/test_text" 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:layout_below="@+id/test_img" 
       android:text="MoveText" 
       android:textSize="20sp" 
       android:textColor="@android:color/white" 
       android:layout_marginTop="-20dp" 
       android:layout_marginLeft="50dp" 
       android:layout_centerInParent="true" 
       /> 

     </nczz.cn.widget.CollapsingImageTextLayout> 

    </android.support.design.widget.AppBarLayout> 
    <include 
     android:id="@+id/includelayout" 
     layout="@layout/content_scrolling"/> 

</android.support.design.widget.CoordinatorLayout> 

Voici le CollapsingImageTextLayout:

package nczz.cn.widget; 

import android.content.Context; 
import android.content.res.TypedArray; 
import android.support.annotation.NonNull; 
import android.support.design.widget.AppBarLayout; 
import android.util.AttributeSet; 
import android.util.Log; 
import android.view.View; 
import android.view.ViewGroup; 
import android.view.ViewParent; 
import android.widget.RelativeLayout; 

import nczz.cn.helloworld.R; 


/** 
* Created by yahui.hu on 2017/4/21. 
*/ 

public class CollapsingImageTextLayout extends RelativeLayout { 

    private AppBarLayout.OnOffsetChangedListener mOffsetChangedListener; 

    private int mTitleId, mTextId, mImageId; 
    private int mTitleMarginLeft, mTitleMarginTop, mImgMarginLeft, mImgMarginTop; 
    private float mTextScale, mImgScale; 
    private View mTitle, mImg, mText; 
    private boolean isGetView = true; 
    private int mTitleHeight = 0; 


    public CollapsingImageTextLayout(Context context) { 
     this(context, null); 
    } 

    public CollapsingImageTextLayout(Context context, AttributeSet attrs) { 
     this(context, attrs, 0); 
    } 

    public CollapsingImageTextLayout(Context context, AttributeSet attrs, int defStyleAttr) { 
     super(context, attrs, defStyleAttr); 
     TypedArray a = context.obtainStyledAttributes(attrs, 
       R.styleable.CollapsingImageLayout, defStyleAttr, 0); 
     mTitleId = a.getResourceId(R.styleable.CollapsingImageLayout_title_id, 0); 
     mTextId = a.getResourceId(R.styleable.CollapsingImageLayout_text_id, 0); 
     mImageId = a.getResourceId(R.styleable.CollapsingImageLayout_img_id, 0); 
     mTextScale = a.getFloat(R.styleable.CollapsingImageLayout_text_scale, 0.4f); 
     mImgScale = a.getFloat(R.styleable.CollapsingImageLayout_img_scale, 0.4f); 
     mTitleMarginLeft = a.getDimensionPixelSize(R.styleable.CollapsingImageLayout_text_margin_left, 0); 
     mTitleMarginTop = a.getDimensionPixelSize(R.styleable.CollapsingImageLayout_text_margin_top, 0); 
     mImgMarginLeft = a.getDimensionPixelSize(R.styleable.CollapsingImageLayout_img_margin_left, 0); 
     mImgMarginTop = a.getDimensionPixelSize(R.styleable.CollapsingImageLayout_img_margin_top, 0); 
     a.recycle(); 

    } 

    @Override 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
     getView(); 
     super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
    } 

    private void getView() { 
     if (!isGetView) { 
      return; 
     } 
     if (mTitleId != 0) { 
      mTitle = findViewById(mTitleId); 
     } 

     if (mTextId != 0) { 
      mText = findViewById(mTextId); 
     } 

     if (mImageId != 0) { 
      mImg = findViewById(mImageId); 
     } 
     isGetView = false; 
    } 

    @Override 
    protected void onLayout(boolean changed, int l, int t, int r, int b) { 
     super.onLayout(changed, l, t, r, b); 

     if (mTitle != null) { 
      getViewOffsetHelper(mTitle).onViewLayout(0, 0); 
      setMinimumHeight(getHeightWithMargins(mTitle)); 
      mTitleHeight = mTitle.getHeight(); 
      this.bringChildToFront(mTitle); 
     } 

     if (mImg != null) { 
      getViewOffsetHelper(mImg).onViewLayout(mImgMarginLeft, mImgMarginTop); 
      this.bringChildToFront(mImg); 
     } 

     if (mText != null) { 
      getViewOffsetHelper(mText).onViewLayout(mTitleMarginLeft, mTitleMarginTop); 
      this.bringChildToFront(mText); 
     } 
    } 

    static ViewHelper getViewOffsetHelper(View view) { 
     ViewHelper offsetHelper = (ViewHelper) view.getTag(R.id.view_helper); 
     if (offsetHelper == null) { 
      offsetHelper = new ViewHelper(view); 
      view.setTag(R.id.view_helper, offsetHelper); 
     } 
     return offsetHelper; 
    } 


    private static int getHeightWithMargins(@NonNull final View view) { 
     final ViewGroup.LayoutParams lp = view.getLayoutParams(); 
     if (lp instanceof MarginLayoutParams) { 
      final MarginLayoutParams mlp = (MarginLayoutParams) lp; 
      return view.getHeight() + mlp.topMargin + mlp.bottomMargin; 
     } 
     return view.getHeight(); 
    } 

    @Override 
    protected void onAttachedToWindow() { 
     super.onAttachedToWindow(); 
     ViewParent viewParent = getParent(); 
     if (viewParent instanceof AppBarLayout) { 
      if (mOffsetChangedListener == null) mOffsetChangedListener = new OffsetListenerImp(); 
      ((AppBarLayout) viewParent).addOnOffsetChangedListener(mOffsetChangedListener); 
     } 
    } 

    @Override 
    protected void onDetachedFromWindow() { 
     ViewParent viewParent = getParent(); 
     if (viewParent instanceof AppBarLayout) { 
      ((AppBarLayout) viewParent).removeOnOffsetChangedListener(mOffsetChangedListener); 
     } 
     super.onDetachedFromWindow(); 
    } 


    final int getMaxOffsetForPinChild(View child) { 
     final ViewHelper offsetHelper = getViewOffsetHelper(child); 
     final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 
     return getHeight() 
       - offsetHelper.getLayoutTop() 
       - child.getHeight() 
       - lp.bottomMargin; 
    } 

    static int constrain(int amount, int low, int high) { 
     return amount < low ? low : (amount > high ? high : amount); 
    } 

    static int constrain(int amount, int low) { 
     return amount < low ? low : amount; 
    } 

    private void setTopAndBottomOffset(View child, int verticalOffset) { 
     ViewHelper viewHelper = (ViewHelper) child.getTag(R.id.view_helper); 
     viewHelper.setTopAndBottomOffset(
       constrain(-verticalOffset, 0, getMaxOffsetForPinChild(child))); 
     Log.e("setTopAndBottomOffset",""+-verticalOffset); 
    } 

    private void setTopAndBottomOffset(View child, int verticalOffset, float scale) { 
     ViewHelper viewHelper = (ViewHelper) child.getTag(R.id.view_helper); 
     viewHelper.setTopAndBottomOffset(
       constrain(-verticalOffset - getMaxOffset(viewHelper, scale), 
         0)); 
     //Log.e("setTopAndBottomOffset",""+-verticalOffset); 
    } 

    private void setLeftAndRightOffset(View child, int verticalOffset, float scale) { 
     ViewHelper viewHelper = (ViewHelper) child.getTag(R.id.view_helper); 
     int maxOffsetDistance = getMaxOffset(viewHelper, scale); 
     int maxLeft = viewHelper.getLayoutLeft() 
       + (viewHelper.getViewWidth() - viewHelper.getScaleViewWidth(scale)) 
       - viewHelper.getMarginTitleLeft(); 
     int realOffset = (int) (maxLeft * 1.0f/(maxOffsetDistance * 1.0f) * verticalOffset); 
     realOffset = constrain(realOffset, -maxLeft, maxLeft); 
     viewHelper.setLeftAndRightOffset(realOffset); 
     // Log.e("setLeftAndRightOffset",""+realOffset); 
    } 

    private void setViewScale(View child, int verticalOffset, float scale) { 
     ViewHelper viewHelper = (ViewHelper) child.getTag(R.id.view_helper); 
     int maxOffsetDistance = getMaxOffset(viewHelper, scale); 
     float realScale = -verticalOffset - maxOffsetDistance > 0 ? scale : verticalOffset == 0 ? 1f : 0f; 
     if (realScale == 0) { 
      realScale = (maxOffsetDistance + verticalOffset * (1 - scale))/(maxOffsetDistance * 1f); 
     } 
     viewHelper.setViewOffsetScale(realScale); 
    } 

    private int getMaxOffset(ViewHelper viewHelper, float scale) { 
     int scaleViewHeight = (int) (scale * viewHelper.getViewHeight()); 
     int offsetTitleDistance = scaleViewHeight >= mTitleHeight ? 0 : (mTitleHeight - scaleViewHeight)/2; 
     int marginTop = viewHelper.getMarginTitleTop() >= offsetTitleDistance ? offsetTitleDistance : viewHelper.getMarginTitleTop(); 
     return viewHelper.getLayoutBottom() - viewHelper.getScaleViewHeight(scale) - offsetTitleDistance - marginTop; 
    } 

    private class OffsetListenerImp implements AppBarLayout.OnOffsetChangedListener { 
     @Override 
     public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { 
      if (mTitle != null) { 
       setTopAndBottomOffset(mTitle, verticalOffset); 
      } 
      if (mText != null) { 
       setTopAndBottomOffset(mText, verticalOffset, mTextScale); 
       setLeftAndRightOffset(mText, verticalOffset, mTextScale); 
       setViewScale(mText, verticalOffset, mTextScale); 
      } 
      if (mImg != null) { 
       setTopAndBottomOffset(mImg, verticalOffset, mImgScale); 
       setLeftAndRightOffset(mImg, verticalOffset, mImgScale); 
       setViewScale(mImg, verticalOffset, mImgScale); 
      } 
     } 
    } 

    public void setImgTitleMarginTop(int top) { 
     if (mImg != null) { 
      getViewOffsetHelper(mImg).setMarginTitleTop(top); 
     } 
    } 

    public void setImgTitleMarginLeft(int left) { 
     if (mImg != null) { 
      getViewOffsetHelper(mImg).setMarginTitleLeft(left); 
     } 
    } 

    public void setTextTitleMarginTop(int top) { 
     if (mText != null) { 
      getViewOffsetHelper(mText).setMarginTitleTop(top); 
     } 
    } 

    public void setImgTextMarginLeft(int left) { 
     if (mText != null) { 
      getViewOffsetHelper(mText).setMarginTitleLeft(left); 
     } 
    } 
} 

Voici le content_scolling.xml:

<?xml version="1.0" encoding="utf-8"?> 
<android.support.v4.widget.NestedScrollView 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:background="#cccccc" 
    android:layout_height="match_parent" 
    app:layout_behavior="@string/appbar_scrolling_view_behavior" 
    tools:context="nczz.cn.helloworld.ScrollingActivity" 
    tools:showIn="@layout/activity_scrolling"> 
    <TextView 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:text="@string/large_text" /> 

</android.support.v4.widget.NestedScrollView> 

Voici la java:

package nczz.cn.helloworld; 

import android.app.Activity; 
import android.content.Intent; 
import android.view.View; 
import android.view.ViewGroup; 
import android.view.Window; 
import android.view.WindowManager; 
import android.widget.LinearLayout; 

public class ScrollingActivity extends Activity { 
    LinearLayout titleTxt; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     this.requestWindowFeature(Window.FEATURE_NO_TITLE); 
     setContentView(R.layout.activity_scrolling); 
     initViews(); 
     setTitleBarHeight(); 
    } 

    private void initViews(){ 
     titleTxt= (LinearLayout) findViewById(R.id.test_title); 
    } 


    private void setTitleBarHeight(){ 
     WindowManager manager=getWindowManager(); 
     int height=manager.getDefaultDisplay().getHeight(); 
     ViewGroup.LayoutParams params=titleTxt.getLayoutParams(); 
     params.height=height/12; 
     titleTxt.setLayoutParams(params); 
    } 
} 

Répondre

0

je ne suis pas sûr mais u pouvez utiliser le code suivant selon vue de l'intérieur scrollview imbriqué

viewlayoutInsidescrollview.setNestedScrollingEnabled(false); 

en classe java

+0

merci, mais il n'a pas homme de travail – lee