我有一个“详细信息”片段,其中包含很多textview,relativelayouts等。这些都包装在NestedScrollView中:

<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?android:attr/windowBackground"
    android:orientation="vertical"
    android:paddingBottom="10dp">

    <android.support.v4.widget.NestedScrollView
        android:id="@+id/movie_details_scroll"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        // Here are the textviews, relativelayouts etc...
    </android.support.v4.widget.NestedScrollView>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/edit_movies_fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:src="@drawable/ic_edit_white_24dp"
    />
</android.support.design.widget.CoordinatorLayout>


现在,我想在屏幕底部(而不是nestedscrollview的底部)添加一个FAB,当我滚动nestedscrollview时也向下滚动。但是使用我的代码,FAB始终位于nestedscrollview的底部。因此,当我一直向下滚动时,FAB出现。我希望FAB始终在右下角可见...

编辑

我忘了提一下,我使用的是淡化操作栏(https://github.com/ManuelPeinado/FadingActionBar),但进行了一些编辑。

相关代码:

m_FadingActionBarHelper.createView(getContext()); // this will create the view with header content etc.


createView:

public final View createView(LayoutInflater inflater) {
  //
  // Prepare everything

  mInflater = inflater;
  if (mContentView == null) {
    mContentView = inflater.inflate(mContentLayoutResId, null); // this will load my view which i already posted.
  }
  if (mHeaderView == null) {
    mHeaderView = inflater.inflate(mHeaderLayoutResId, null, false);
  }

  // See if we are in a ListView, WebView or ScrollView scenario

  ListView listView = (ListView) mContentView.findViewById(android.R.id.list);
  View root;
  if (listView != null) {
    root = createListView(listView);
  } else if (mContentView instanceof CDMObservableWebViewWithHeader){
    root = createWebView();
  } else {
    root = createScrollView(); // this will be called in my example
  }

  if (mHeaderOverlayView == null && mHeaderOverlayLayoutResId != 0) {
    mHeaderOverlayView = inflater.inflate(mHeaderOverlayLayoutResId, mMarginView, false);
  }
  if (mHeaderOverlayView != null) {
    mMarginView.addView(mHeaderOverlayView);
  }

  // Use measured height here as an estimate of the header height, later on after the layout is complete
  // we'll use the actual height
  int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY);
  int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY);
  mHeaderView.measure(widthMeasureSpec, heightMeasureSpec);
  updateHeaderHeight(mHeaderView.getMeasuredHeight());

  root.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
      int headerHeight = mHeaderContainer.getHeight();
      if ((!mFirstGlobalLayoutPerformed || (headerHeight != mLastHeaderHeight)) && headerHeight != 0) {
        updateHeaderHeight(headerHeight);
        mFirstGlobalLayoutPerformed = true;
      }
    }
  });
  return root;
}


createScrollView:

private View createScrollView() {
  ViewGroup scrollViewContainer = (ViewGroup) mInflater.inflate(R.layout.fab__scrollview_container, null);

  CDMObservableScrollView scrollView = (CDMObservableScrollView) scrollViewContainer.findViewById(R.id.fab__scroll_view);
  scrollView.setOnScrollChangedCallback(mOnScrollChangedListener);

  ViewGroup contentContainer = (ViewGroup) scrollViewContainer.findViewById(R.id.fab__container);
  LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
          LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
  mContentView.setLayoutParams(layoutParams);
  contentContainer.addView(mContentView);
  mHeaderContainer = (FrameLayout) scrollViewContainer.findViewById(R.id.fab__header_container);
  initializeGradient(mHeaderContainer);
  mHeaderContainer.addView(mHeaderView, 0);
  mMarginView = (FrameLayout) contentContainer.findViewById(R.id.fab__content_top_margin);

  return scrollViewContainer;
}


将要加载的xml:

<denis.de.meperdia.fadingactionbar.CDMRootLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <include layout="@layout/fab__header_container"/>

    <denis.de.meperdia.fadingactionbar.CDMObservableScrollView
        android:id="@+id/fab__scroll_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:id="@+id/fab__container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <FrameLayout
                android:id="@+id/fab__content_top_margin"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@android:color/transparent"/>
        </LinearLayout>
    </denis.de.meperdia.fadingactionbar.CDMObservableScrollView>

</denis.de.meperdia.fadingactionbar.CDMRootLayout>


类CDMRootLayout:

public class CDMRootLayout extends CoordinatorLayout {

  private View mHeaderContainer;
  private View mListViewBackground;
  private boolean mInitialized = false;

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

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

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

  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    //at first find headerViewContainer and listViewBackground
    if(mHeaderContainer == null)
      mHeaderContainer = findViewById(R.id.fab__header_container);
    if(mListViewBackground == null)
      mListViewBackground = findViewById(R.id.fab__listview_background);

    //if there's no headerViewContainer then fallback to standard FrameLayout
    if(mHeaderContainer == null) {
      super.onLayout(changed, left, top, right, bottom);
      return;
    }

    if(!mInitialized) {
      super.onLayout(changed, left, top, right, bottom);
      //if mListViewBackground not exists or mListViewBackground exists
      //and its top is at headercontainer height then view is initialized
      if(mListViewBackground == null || mListViewBackground.getTop() == mHeaderContainer.getHeight())
        mInitialized = true;
      return;
    }

    //get last header and listViewBackground position
    int headerTopPrevious = mHeaderContainer.getTop();
    int listViewBackgroundTopPrevious = mListViewBackground != null ? mListViewBackground.getTop() : 0;

    //relayout
    super.onLayout(changed, left, top, right, bottom);

    //revert header top position
    int headerTopCurrent = mHeaderContainer.getTop();
    if(headerTopCurrent != headerTopPrevious) {
      mHeaderContainer.offsetTopAndBottom(headerTopPrevious - headerTopCurrent);
    }
    //revert listViewBackground top position
    int listViewBackgroundTopCurrent = mListViewBackground != null ? mListViewBackground.getTop() : 0;
    if(listViewBackgroundTopCurrent != listViewBackgroundTopPrevious) {
      mListViewBackground.offsetTopAndBottom(listViewBackgroundTopPrevious - listViewBackgroundTopCurrent);
    }
  }
}


和类CDMObservableScrollView:

public class CDMObservableScrollView extends ScrollView implements CDMObservableScrollable {
    // Edge-effects don't mix well with the translucent action bar in Android 2.X
    private boolean mDisableEdgeEffects = true;

    private CDMOnScrollChangedCallback mOnScrollChangedListener;

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

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

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

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
      super.onScrollChanged(l, t, oldl, oldt);
      if (mOnScrollChangedListener != null) {
        mOnScrollChangedListener.onScroll(l, t);
      }
    }

    @Override
    protected float getTopFadingEdgeStrength() {
      // http://stackoverflow.com/a/6894270/244576
      if (mDisableEdgeEffects && Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
        return 0.0f;
      }
      return super.getTopFadingEdgeStrength();
    }

    @Override
    protected float getBottomFadingEdgeStrength() {
      // http://stackoverflow.com/a/6894270/244576
      if (mDisableEdgeEffects && Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
        return 0.0f;
      }
      return super.getBottomFadingEdgeStrength();
    }

    @Override
    public void setOnScrollChangedCallback(CDMOnScrollChangedCallback callback) {
      mOnScrollChangedListener = callback;
    }
}


编辑2

我现在可以界定问题:

如果我这些行,FAB可以按我的意愿工作:

    <denis.de.meperdia.fadingactionbar.CDMObservableScrollView
        android:id="@+id/fab__scroll_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">


但是后来我的衰落动作条的同步化被破坏了...

很抱歉有这么多代码,但是如果没有这些代码,理解起来真的很复杂。

最佳答案

导入app名称空间,用NestedScrollView包围RelativeLayout,然后将RelativeLayout设置为anchor作为FAB

<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"     //Import app namespace
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?android:attr/windowBackground"
    android:orientation="vertical"
    android:paddingBottom="10dp">

    <RelativeLayout
        android:id="@+id/mainview"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v4.widget.NestedScrollView
            android:id="@+id/movie_details_scroll"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            // Here are the textviews, relativelayouts etc...
        </android.support.v4.widget.NestedScrollView>

    </RelativeLayout>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/edit_movies_fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/fab_margin"
        android:src="@drawable/ic_edit_white_24dp"
        app:layout_anchor="@id/mainview"           //attributes of app namespace
        app:layout_anchorGravity="bottom|end"
    />
</android.support.design.widget.CoordinatorLayout>

07-28 03:15
查看更多