RecycleView оставляет пустое пространство внизу из-за панели инструментов
Обновить:
- Фактическая проблема с CoordinatorLayout, а не с RecycleView.
- Вместо использования RecycleView я попробовал TextView внутри ScrollView, и это та же проблема.
- Что-то не выравнивается, если у вас есть Панель инструментов в качестве ActionBar и используется компоновка Координатора с другой Панелью инструментов в качестве Липкого заголовка с прокручиваемым элементом внизу
Оригинал:
Я нахожусь в процессе разработки представления, которое нуждалось в реализации заголовка Sticky с представлением recycle внизу. Я использовал поддержку макета Координатора, как описано здесь.
Что работает:
- Sticky View в списке прокрутки.
- Панель инструментов с использованием layout_collapseMode = pin & CollapsingToolbarLayout с использованием layout_scrollFlags = scroll|exitUntilCollapsed|snap свойство.
- Повторное представление с поведением app:layout_behavior="@string/appbar_scrolling_view_behavior"
В чем проблема:
- Переверните вид, оставляя поле снизу, он имеет тот же размер, что и панель инструментов, которую я использую для закрепления вида.
- Последний элемент в режиме повторного просмотра не отображается, требуется дополнительныйbottom_margin в качестве размера липкой панели инструментов.
Наблюдение:
- Если я заполняю утилизацию мгновенно, то это работает. Но если уведомить об этом с некоторой задержкой, то это вызывает проблему.
- Обновить. В другом испытании и запуске ** вместо использования Recycle я поместил TextView в NestedScrollView.(PFA) (здесь не обновляется макет)
- Здесь я добавил текст из XML и после задержки 2 секунды просто добавить еще текст, и это тот же результат.
- Это макет, который снова принимает нижнее поле. Так что ничего особенного, связанного с представлением Recycle, кажется, что есть некоторая проблема с CoordinatorLayout.
Я пробовал с несколькими решениями, доступными здесь, здесь, но ни одно из них не работает.
PFA, токовый выход.
Обновите PFA, поэкспериментируйте с просмотром текста с задержкой.
Вот файл макета.
<androidx.coordinatorlayout.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">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/summaryAppBar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/main.collapsing"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="256dp"
android:background="@drawable/fable_1"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.3" />
<!-- This is sticky header-->
<androidx.appcompat.widget.Toolbar
android:id="@+id/summaryToolBar"
android:layout_width="match_parent"
android:layout_height="72dp"
android:layout_gravity="center"
android:background="@android:color/white"
android:padding="@dimen/common_layout_margin"
android:visibility="visible"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
android:text="Name" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:textSize="24sp"
android:text="Offer"/>
</FrameLayout>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<!-- Bottom margin if I do't use then it does not display last item. Wired but true in this case-->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:visibility="visible"
android:layout_marginBottom="72dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:listItem="@layout/item_dessert" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
3 ответа
Я считаю, что CoordinatorLayout
(может быть AppBarLayout
или же CollapsingToolbarLayout
- не уверен, какой компонент) записывает неправильную высоту CollapsingToolbarLayout
из-за липкой панели инструментов. Поведение отличается, если элементы добавляются до или после первоначального макета.
Попробуйте следующее:
- Удалить
android:layout_marginBottom="72dp"
из XML дляRecyclerView
, - добавлять
android:minHeight="72dp"
в XML дляCollapsingToolbarLayout
Так как ваша липкая панель инструментов установлена на 72dp
это нормально использовать minHeight
установлен в 72dp
,
Если у вас есть проблемы с этим, напишите сюда.
Вот краткая демонстрация вашего макета с использованием NestedScrollView
и изменения, упомянутые выше.
Обновление: я работал с этим RecyclerView
который отображает ту же проблему. Демонстрационный проект, показывающий проблему и исправление, находится на GitHub.
Вот код:
MainActivity.java
public class MainActivity extends AppCompatActivity {
// Set to true to break the layout; false for it to work.
// The setting of this flag should only matter for the
// layout activity_not_working.
private boolean mBreakIt = true;
// private int mLayoutToUse = R.layout.activity_not_working;
private int mLayoutToUse = R.layout.activity_working;
private LinearLayout mLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(mLayoutToUse);
mLayout = findViewById(R.id.linearLayout);
if (mBreakIt) {
mLayout.post(new Runnable() {
@Override
public void run() {
addViews();
}
});
} else {
addViews();
}
}
private void addViews() {
for (int i = 0; i < 50; i++) {
TextView tv = new TextView(MainActivity.this);
tv.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
tv.setText("TextView #" + (i + 1));
mLayout.addView(tv);
}
}
}
activity_working.xml
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/summaryAppBar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/main.collapsing"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="72dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="256dp"
android:background="@drawable/beach"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.3" />
<!-- This is sticky header-->
<androidx.appcompat.widget.Toolbar
android:id="@+id/summaryToolBar"
android:layout_width="match_parent"
android:layout_height="72dp"
android:layout_gravity="center"
android:background="@android:color/white"
android:padding="@dimen/common_layout_margin"
android:visibility="visible"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Name"
android:textSize="24sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="Offer"
android:textSize="24sp" />
</FrameLayout>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<!-- Bottom margin if I do't use then it does not display last child item. Wired but true in this case-->
<!-- Removed following: -->
<!--android:layout_marginBottom="72dp"-->
<androidx.core.widget.NestedScrollView
android:id="@+id/nestedScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/holo_blue_light"
android:visibility="visible"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
app:layout_insetEdge="bottom"
tools:listItem="@layout/item_dessert">
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="A TextView" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="A TextView" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="A TextView" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="A TextView" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
activity_not_working.xml
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/summaryAppBar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/main.collapsing"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="256dp"
android:background="@drawable/beach"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.3" />
<!-- This is sticky header-->
<androidx.appcompat.widget.Toolbar
android:id="@+id/summaryToolBar"
android:layout_width="match_parent"
android:layout_height="72dp"
android:layout_gravity="center"
android:background="@android:color/white"
android:padding="@dimen/common_layout_margin"
android:visibility="visible"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Name"
android:textSize="24sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="Offer"
android:textSize="24sp" />
</FrameLayout>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<!-- Bottom margin if I do't use then it does not display last child item. Wired but true in this case-->
<!-- Removed following: -->
<!--android:layout_marginBottom="72dp"-->
<androidx.core.widget.NestedScrollView
android:id="@+id/nestedScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="72dp"
android:background="@android:color/holo_blue_light"
android:visibility="visible"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
app:layout_insetEdge="bottom"
tools:listItem="@layout/item_dessert">
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="A TextView" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="A TextView" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="A TextView" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="A TextView" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Можете ли вы попробовать файл макета ниже. Я проверил это, и он отлично работает. Вы также можете удалить marginButtom из окна реселлера.
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.coordinatorlayout.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">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/summaryAppBar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/main.collapsing"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="256dp"
android:background="@drawable/fable_1"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.3" />
<!-- This is sticky header-->
<androidx.appcompat.widget.Toolbar
android:id="@+id/summaryToolBar"
android:layout_width="match_parent"
android:layout_height="72dp"
android:layout_gravity="center"
android:background="@android:color/white"
android:padding="@dimen/common_layout_margin"
android:visibility="visible"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
android:text="Name" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:textSize="24sp"
android:text="Offer"/>
</FrameLayout>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:visibility="visible"
android:layout_marginBottom="72dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:listItem="@layout/item_dessert" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</RelativeLayout>
Просто удалите эту строку из RecyclerView
:
android:layout_marginBottom="72dp"
и этот атрибут может быть мало полезен, потому что это значение по умолчанию:
android:visibility="visible"
Я не вижу там никакой липкой панели инструментов... и если она должна быть, не устанавливайте высоту так:
android:layout_height="match_parent"
но сделайте так, чтобы он заполнил доступное пространство (чтобы не потребовалось никакого нижнего поля):
android:layout_height="0dp"
android:layout_weight="1.00"
это всегда делает RecyclerView
подходит, в случае если есть нижняя панель инструментов, независимо от того, должна ли эта панель инструментов быть закрепленной, потому что это то, что требует нерешительного "исправления" макета. BottomNavigationView в конечном итоге может быть полезен там, в зависимости от того, что эта воображаемая липкая панель инструментов, которая не показана на GIF
может быть хорошо для. даже нашел источник скрипта: https://github.com/saulmm/CoordinatorBehaviorExample, который должен был быть приписан, как того требует лицензия.
Я предполагаю, что могут возникнуть проблемы при добавлении новых данных и уведомлении адаптера.
Вы должны измениться с notifyDataSetChanged()
в notifyItemInserted(index)
,
Больше документации по notifyItemInserted(index)
здесь
Надеюсь, поможет.
Эй, вы установили marginBottom
атрибут там. Удалить это. Вот где ошибка. Код для RecyclerView
должно быть:
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:listItem="@layout/item_dessert" />