我有一个“详细信息”片段,其中包含很多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>