Android-CoordinatorLayout에서 사용하면 바닥 글이 화면 외 스크롤됩니다.
나는 AppBarLayout
이을 스크롤 할 때 화면 외 다른 그 스크롤 RecyclerView
. 아래 RecyclerView
가 RelativeLayout
바닥 글입니다.
바닥 글은 위로 스크롤 한 후에 만 표시됩니다.
layout_scrollFlags="scroll|enterAlways"
하지만 스크롤 플래그가 없습니다. 뭔가 잘못하고 있습니까? 항상 보이길 원해
스크롤하기 전에
스크롤 후
최신 정보
이것에 대한 Google 문제 를 열었습니다 - 'WorkingAsIntended'로 표시되었습니다. 조각 내부의 바닥 글에 대한 작업 솔루션을 원하기 때문에 여전히 도움이되지 않습니다.
업데이트 2
당신은 활동을 찾을 수 있고, 단편은 여기 XMLS -
34 activity.xml
번째 줄 app:layout_behavior="@string/appbar_scrolling_view_behavior"
이 주석 처리 텍스트 끝 이 처음부터 표시됩니다. 텍스트 위로 스크롤 한 후에 만 표시됩니다.
나는 OpenGL을 ES의 솔루션 (학습의 단순화 된 버전을 사용 https://stackoverflow.com/a/33396965/778951 노아의 솔루션 (에 향상-)를 https://stackoverflow.com/a/31140112/1317564을 사용) ). 각 탭의 ViewPager 콘텐츠에 바닥 글 단추가있는 TabLayout 위의 간단한 빠른 반환 도구 모음에서 잘 작동합니다.
화면 하단에 정렬 할 View / ViewGroup에서 FixScrollingFooterBehavior를 layout_behavior로 설정하기 만하면됩니다.
형세 :
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:minHeight="?android:attr/actionBarSize"
app:title="Foo"
app:layout_scrollFlags="scroll|enterAlways|snap"
/>
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.spreeza.shop.ui.widgets.FixScrollingFooterBehavior"
/>
</android.support.design.widget.CoordinatorLayout>
행동 :
public class FixScrollingFooterBehavior extends AppBarLayout.ScrollingViewBehavior {
private AppBarLayout appBarLayout;
public FixScrollingFooterBehavior() {
super();
}
public FixScrollingFooterBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
if (appBarLayout == null) {
appBarLayout = (AppBarLayout) dependency;
}
final boolean result = super.onDependentViewChanged(parent, child, dependency);
final int bottomPadding = calculateBottomPadding(appBarLayout);
final boolean paddingChanged = bottomPadding != child.getPaddingBottom();
if (paddingChanged) {
child.setPadding(
child.getPaddingLeft(),
child.getPaddingTop(),
child.getPaddingRight(),
bottomPadding);
child.requestLayout();
}
return paddingChanged || result;
}
// Calculate the padding needed to keep the bottom of the view pager's content at the same location on the screen.
private int calculateBottomPadding(AppBarLayout dependency) {
final int totalScrollRange = dependency.getTotalScrollRange();
return totalScrollRange + dependency.getTop();
}
}
최신 정보
아래 솔루션은 5.1에서 작동하지 않습니다. 5에서 작동 사용 계산 에 getTop 대신 getTranslationY 를 사용 합니다.
layout.getTop()-->(int)layout.getTranslationY()
appbar.getTop()+toolbar.getHeight()-->(int)(appbar.getTranslationY()+toolbar.getHeight())
지원 라이브러리가 새로운 포함 된 업데이트 2-22.2.1-5.1과 이전 버전간에 차이가 없으므로이 답변 에서 getTop 만 사용하고 이전 업데이트를 무시해야 합니다 .
원본 솔루션 여러 방향을 본 후 솔루션은 실제로 합니다. 조각 에 paddingBottom 을 추가 하고 페이지가 스크롤 될 때 조정합니다.
도구 모음 y 위치 의 변경 사항을 덮기 위해 패딩이 필요합니다 . 도구 모음이 사라지고 다시 전체 페이지를 위아래로 이동합니다 .
이 활동AppBarLayout.ScrollingViewBehavior
의 조각 요소의 동작으로 확장 하고 설정 하여 달성 할 수 있습니다 .
여기에 코드의 기본은 - 당신이로 교체 할 수 있습니다 - 단지 도구 모음 그것은 활동을 위해 작동 appbar.getTop() + toolbar.getHeight()
하고 난 웬지 -이 더 잘 작동합니다 appbar가 포함 탭을 .
activity.xml
<android.support.design.widget.CoordinatorLayout
android:id="@+id/main"
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">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="3dp"
app:elevation="3dp">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways"
/>
</android.support.design.widget.AppBarLayout>
<fragment
android:id="@+id/fragment"
android:name="com.example.noa.footer2.MainActivityFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.example.noa.footer2.MyBehavior"
tools:layout="@layout/fragment"/>
</android.support.design.widget.CoordinatorLayout>
fragment.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="48dp"
android:background="@android:color/holo_green_dark"
tools:context=".MainActivityFragment">
<android.support.v7.widget.RecyclerView
android:id="@+id/list"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@null"/>
<View
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_alignParentBottom="true"
android:background="@android:color/holo_red_light"/>
</RelativeLayout>
MainActivityFragment # onActivityCreated
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
CoordinatorLayout.LayoutParams lp = (LayoutParams) getView().getLayoutParams();
MyBehavior behavior = (MyBehavior) lp.getBehavior();
behavior.setLayout(getView());
}
MyBehavior
public class MyBehavior extends AppBarLayout.ScrollingViewBehavior {
private View layout;
public MyBehavior() {
}
public MyBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
boolean result = super.onDependentViewChanged(parent, child, dependency);
if (layout != null) {
layout.setPadding(layout.getPaddingLeft(), layout.getPaddingTop(), layout
.getPaddingRight(), layout.getTop());
}
return result;
}
public void setLayout(View layout) {
this.layout = layout;
}
}
나는 Noa의 솔루션 ( https://stackoverflow.com/a/31140112/1317564 )으로 시작 손가락 드래그에 효과가 있었지만 플링에 문제가 생겼습니다. 방법 호출을 추적하고 다른 아이디어를 시도하는 데 시간을 투자 한 후 다음과 같은 해결 방법이 있습니다.
// Workaround for https://code.google.com/p/android/issues/detail?id=177195
// Based off of solution originally found here: https://stackoverflow.com/a/31140112/1317564
@SuppressWarnings("unused")
public class CustomScrollingViewBehavior extends AppBarLayout.ScrollingViewBehavior {
private AppBarLayout appBarLayout;
private boolean onAnimationRunnablePosted = false;
@SuppressWarnings("unused")
public CustomScrollingViewBehavior() {
}
@SuppressWarnings("unused")
public CustomScrollingViewBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
if (appBarLayout != null) {
// We need to check from when a scroll is started, as we may not have had the chance to update the layout at
// the start of a scroll or fling event.
startAnimationRunnable(child, appBarLayout);
}
return super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
}
@Override
public boolean onMeasureChild(CoordinatorLayout parent, final View child, int parentWidthMeasureSpec, int widthUsed,
int parentHeightMeasureSpec, int heightUsed) {
if (appBarLayout != null) {
final int bottomPadding = calculateBottomPadding(appBarLayout);
if (bottomPadding != child.getPaddingBottom()) {
// We need to update the padding in onMeasureChild as otherwise we won't have the correct padding in
// place when the view is flung, and the changes done in onDependentViewChanged will only take effect on
// the next animation frame, which means it will be out of sync with the new scroll offset. This is only
// needed when the view is flung -- when dragged with a finger, things work fine with just
// implementing onDependentViewChanged().
child.setPadding(child.getPaddingLeft(), child.getPaddingTop(), child.getPaddingRight(), bottomPadding);
}
}
return super.onMeasureChild(parent, child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, final View child, final View dependency) {
if (appBarLayout == null)
appBarLayout = (AppBarLayout) dependency;
final boolean result = super.onDependentViewChanged(parent, child, dependency);
final int bottomPadding = calculateBottomPadding(appBarLayout);
final boolean paddingChanged = bottomPadding != child.getPaddingBottom();
if (paddingChanged) {
// If we've changed the padding, then update the child and make sure a layout is requested.
child.setPadding(child.getPaddingLeft(),
child.getPaddingTop(),
child.getPaddingRight(),
bottomPadding);
child.requestLayout();
}
// Even if we didn't change the padding, if onDependentViewChanged was called then that means that the app bar
// layout was changed or was flung. In that case, we want to check for these changes over the next few animation
// frames so that we can ensure that we capture all the changes and update the view pager padding to match.
startAnimationRunnable(child, dependency);
return paddingChanged || result;
}
// Calculate the padding needed to keep the bottom of the view pager's content at the same location on the screen.
private int calculateBottomPadding(AppBarLayout dependency) {
final int totalScrollRange = dependency.getTotalScrollRange();
return totalScrollRange + dependency.getTop();
}
private void startAnimationRunnable(final View child, final View dependency) {
if (onAnimationRunnablePosted)
return;
final int onPostChildTop = child.getTop();
final int onPostDependencyTop = dependency.getTop();
onAnimationRunnablePosted = true;
// Start looking for changes at the beginning of each animation frame. If there are any changes, we have to
// ensure that layout is run again so that we can update the padding to take the changes into account.
child.postOnAnimation(new Runnable() {
private static final int MAX_COUNT_OF_FRAMES_WITH_NO_CHANGES = 5;
private int previousChildTop = onPostChildTop;
private int previousDependencyTop = onPostDependencyTop;
private int countOfFramesWithNoChanges;
@Override
public void run() {
// Make sure we request a layout at the beginning of each animation frame, until we notice a few
// frames where nothing changed.
final int currentChildTop = child.getTop();
final int currentDependencyTop = dependency.getTop();
boolean hasChanged = false;
if (currentChildTop != previousChildTop) {
previousChildTop = currentChildTop;
hasChanged = true;
countOfFramesWithNoChanges = 0;
}
if (currentDependencyTop != previousDependencyTop) {
previousDependencyTop = currentDependencyTop;
hasChanged = true;
countOfFramesWithNoChanges = 0;
}
if (!hasChanged) {
countOfFramesWithNoChanges++;
}
if (countOfFramesWithNoChanges <= MAX_COUNT_OF_FRAMES_WITH_NO_CHANGES) {
// We can still look for changes on subsequent frames.
child.requestLayout();
child.postOnAnimation(this);
} else {
// We've encountered enough frames with no changes. Do a final layout request, and don't repost.
child.requestLayout();
onAnimationRunnablePosted = false;
}
}
});
}
}
나는 모든 애니메이션 프레임에서 레이아웃을 다시 확인하는 것을 좋아하지 않는 프로그래밍 방식으로 앱 바 레이아웃을 확장 / 축소하는 경우 몇 가지 문제를 해결이 솔루션은 완벽하지 지금은 더 나은 솔루션을 찾지 않습니다. . 성능은 새 장치에서 양호하고 이전 장치에서 허용됩니다. 다른 사람이 권한 내 답변을 출처로 삼아 다시 게시하십시오.
package pl.mkaras.utils;
import android.content.Context;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CoordinatorLayout;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.Toolbar;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import java.util.List;
public class ScrollViewBehaviorFix extends AppBarLayout.ScrollingViewBehavior {
public ScrollViewBehaviorFix() {
super();
}
public ScrollViewBehaviorFix(Context context, AttributeSet attrs) {
super(context, attrs);
}
public boolean onMeasureChild(CoordinatorLayout parent, View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec,
int heightUsed) {
if (child.getLayoutParams().height == -1) {
List<View> dependencies = parent.getDependencies(child);
if (dependencies.isEmpty()) {
return false;
}
final AppBarLayout appBar = findFirstAppBarLayout(dependencies);
if (appBar != null && ViewCompat.isLaidOut(appBar)) {
int availableHeight = View.MeasureSpec.getSize(parentHeightMeasureSpec);
if (availableHeight == 0) {
availableHeight = parent.getHeight();
}
final int height = availableHeight - appBar.getMeasuredHeight();
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST);
parent.onMeasureChild(child, parentWidthMeasureSpec, widthUsed, heightMeasureSpec, heightUsed);
int childContentHeight = getContentHeight(child);
if (childContentHeight <= height) {
updateToolbar(parent, appBar, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed, false);
heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
parent.onMeasureChild(child, parentWidthMeasureSpec, widthUsed, heightMeasureSpec, heightUsed);
return true;
} else {
updateToolbar(parent, appBar, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed, true);
return super.onMeasureChild(parent, child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
}
}
}
return false;
}
private static int getContentHeight(View view) {
if (view instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) view;
int contentHeight = 0;
for (int index = 0; index < viewGroup.getChildCount(); ++index) {
View child = viewGroup.getChildAt(index);
contentHeight += child.getMeasuredHeight();
}
return contentHeight;
} else {
return view.getMeasuredHeight();
}
}
private static AppBarLayout findFirstAppBarLayout(List<View> views) {
int i = 0;
for (int z = views.size(); i < z; ++i) {
View view = views.get(i);
if (view instanceof AppBarLayout) {
return (AppBarLayout) view;
}
}
throw new IllegalArgumentException("Missing AppBarLayout in CoordinatorLayout dependencies");
}
private void updateToolbar(CoordinatorLayout parent, AppBarLayout appBar, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec,
int heightUsed, boolean toggle) {
toggleToolbarScroll(appBar, toggle);
appBar.forceLayout();
parent.onMeasureChild(appBar, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
}
private void toggleToolbarScroll(AppBarLayout appBar, boolean toggle) {
for (int index = 0; index < appBar.getChildCount(); ++index) {
View child = appBar.getChildAt(index);
if (child instanceof Toolbar) {
Toolbar toolbar = (Toolbar) child;
AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) toolbar.getLayoutParams();
int scrollFlags = params.getScrollFlags();
if (toggle) {
scrollFlags |= AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL;
} else {
scrollFlags &= ~AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL;
}
params.setScrollFlags(scrollFlags);
}
}
}
}
동작은 기본적이으로 의존적 뷰 ( , )의 스크롤 콘텐츠 가 뷰 높이보다 작을 때에 서 스크롤 플래그 SCROLL
를 제거합니다 . 스크롤이 필요하지 않을 때. 또한 일반적으로 수행하는 명령문 뷰를 재정의합니다 . 바닥 글을 추가 할 때 잘 작동합니다. 버튼, 스크롤링보기 또는 각 페이지에서 콘텐츠 길이가 다를 수 있습니다.AppBarLayout
RecyclerView
NestedScrollView
AppBarLayout.ScrollingViewBehavior
ViewPager
고정 머리글과 바닥 글을 만드는 것이 문제를 해결하는 것이 생각합니다. 나는 비용을 지출하는 비용이 50 명의 담당자가 없습니다. 여기서 어떻게하는지 알아낼 수 있습니다.
저는 android:layout_gravity="end|bottom"
XML의 레이아웃에 제가 맨 아래에 원하는대로 추가 확인한 작업 을 수행했습니다.CoordinatorLayout
그런 다음 코드에서 설정하십시오.
mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
@Override
public void onGlobalLayout() {
if (mFooterView != null) {
final int height = mFooterView.getHeight();
mRecyclerView.setPadding(0, 0, 0, height);
mRecyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
}
});
참고 : 바닥 글 View / ViewGroup이 제대로 작동 작동하는지 z 축 (XML의 RecyclerView 아래에 설치 됨)에서 더 배치 야합니다.
다음과 같이 선형 레이아웃으로 요소를 둘러 쌉니다.
<android.support.design.widget.CoordinatorLayout >
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout>
<android.support.v7.widget.Toolbar />
</android.support.design.widget.AppBarLayout>
<include layout="@layout/content_main" />
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
Android CoordinatorLayout 하단 레이아웃 동작 예제
activity_bottom.xml
<android.support.design.widget.CoordinatorLayout 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">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimaryDark"
app:layout_scrollFlags="scroll|enterAlways"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#C0C0C0"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<com.example.android.coordinatedeffort.widget.FooterBarLayout
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_gravity="bottom">
<TextView
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#007432"
android:gravity="center"
android:text="Footer View"
android:textColor="@android:color/white"
android:textSize="25sp" />
</com.example.android.coordinatedeffort.widget.FooterBarLayout>
</android.support.design.widget.CoordinatorLayout>
문제에 대한 라이브러리가 있습니다. 당신에게 도움이되기에 도움이 여기는 도서관입니다
그리고 언급 한 또 다른 문제가 바닥 글을 수정했습니다. 는 상대적인 레이아웃 아래이므로 android:layout_alignParentBottom="true"
바닥 글 의 기능 현관 을 사용하십시오 .
내가 문제를 해결했으면 좋겠어
'ProgramingTip' 카테고리의 다른 글
JSON 스키마에 선언 된 속성 만 허용 (0) | 2020.12.25 |
---|---|
프래그먼트를 사용하여 공유 요소 전환을 시작하는 방법은 무엇입니까? (0) | 2020.12.25 |
Android에서 ClipData의 "label"매개 변수는 정확히 무엇입니까? (0) | 2020.12.25 |
실행되지 않은 코드가 주석 처리되면 Java 프로그램이 느리게 실행됩니다. (0) | 2020.12.25 |
리터럴을 만드는 방법 : 클래스 (0) | 2020.12.25 |