#android #android-coordinatorlayout #bottom-sheet #android-jetpack
#Android #android-coordinatorlayout #нижний лист #android-jetpack
Вопрос:
У меня есть нижний лист с дочерним NestedScrollView. Я хочу прокрутить весь NestedScrollView до самого низа, не сдвигая нижний лист вверх.
Если пользователь хочет, чтобы нижний лист поднимался полностью, он не должен использовать привязку никаким другим способом.
Теперь, когда я использую start прокрутку вниз, после прокрутки всего содержимого я хочу, чтобы нижний лист скрывался при следующем действии прокрутки.
Поскольку поведение нижней таблицы по умолчанию не допускает этого, я создал свое собственное пользовательское поведение и переопределил onNestedScroll () и onNestedPreScroll().
Есть две проблемы, с которыми я сталкиваюсь:
1: Nestedscrollview частично прокручивается и останавливается, потому что по отношению к нижнему листу он видит, что больше нет содержимого для прокрутки. Я должен сдвинуть лист вверх, чтобы увидеть остальное содержимое. Означает, что я не могу увидеть последний элемент внутри NestedScrollView, не разворачивая лист.
2: Как я могу определить, прокручивается ли NestedScrollChild вверх или вниз. Потому что я хочу, чтобы нижний лист перехватывал события, как только scrollview закончит прокручивать свое содержимое. Я попробовал onNestedPreScroll, но, похоже, это не обязательно срабатывает каждый раз, когда прокручивается дочерний элемент. Является ли подключение прослушивателя к scrollview единственным решением?
Ссылка, чтобы увидеть проблему в GIFhttps://photos.app.goo.gl/RPmDFEtR9TbGHrau6
Ниже приведен мой класс макета и поведения.
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.appbar.AppBarLayout
android:id="@ id/appBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.ActionBar">
<androidx.appcompat.widget.Toolbar
android:id="@ id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
/>
</com.google.android.material.appbar.AppBarLayout>
—>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@ id/bs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bottom_sheet_background_shaded"
android:elevation="10dp"
app:behavior_hideable="false"
app:behavior_peekHeight="35dp"
app:behavior_fitToContents="false"
app:layout_behavior="com.pyus13.bottomsheetsample.MyBottomSheetBehaviour">
<ImageView
android:id="@ id/anchor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="1dp"
android:src="@drawable/bottom_sheet_anchor_holder"
app:layout_constraintBottom_toTopOf="@ id/main_container"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<androidx.core.widget.NestedScrollView
android:id="@ id/main_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:clipToPadding="false"
android:elevation="5dp"
android:gravity="center"
android:paddingTop="20dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/anchor">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@ id/change_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Title 1"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Title 2"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Page 3"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Page 4"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Page 5"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Change Title"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Change Title"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Change Title"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Change Title"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Change Title"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Change Title"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Change Title"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Change Title"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Change Title"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Change Title"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Change Title"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Change Title"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Change Title"/>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
Мой класс поведения:
class MyBottomSheetBehaviour<V : View> @JvmOverloads constructor(
context: Context? = null, attrs: AttributeSet? = null) : BottomSheetBehavior<V>(context, attrs) {
private var isScrollingDown = false
override fun onInterceptTouchEvent(parent: CoordinatorLayout, child: V, event: MotionEvent): Boolean {
if (state == STATE_COLLAPSED || state == STATE_HALF_EXPANDED) {
return false
}
return super.onInterceptTouchEvent(parent, child, event)
}
override fun onStartNestedScroll(coordinatorLayout: CoordinatorLayout, child: V, directTargetChild: View, target: View, axes: Int, type: Int): Boolean {
Log.d("Scroll", "OnNestedScroll EVent $child $target $axes $type")
if (state == STATE_COLLAPSED || state == STATE_HALF_EXPANDED) {
if (target.canScrollVertically(1) || target.canScrollVertically(-1)) {
return false
}
}
return super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, axes, type)
}
override fun onNestedPreScroll(coordinatorLayout: CoordinatorLayout, child: V, target: View, dx: Int, dy: Int, consumed: IntArray, type: Int) {
isScrollingDown = dy > 0
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type)
}
}
Я хочу, чтобы подобное поведение, если кто-то может помочь, действительно было бы оценено.
Комментарии:
1. Вы нашли решение для этого?
2. У меня точно такая же проблема. Что вы сделали, чтобы это исправить?
3. Вы нашли решение для этого?
Ответ №1:
У меня была почти такая же проблема, хотя макет был немного другим, и поведение заключалось в том, чтобы вообще не перехватывать вложенную прокрутку. Поскольку ответа по-прежнему нет, я думаю, стоит поделиться своим опытом здесь.
Итак, мой макет был следующим:
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
...
<LinearLayout
android:id="@ id/bottomSheetLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:backgroundTint="@color/colorPrimary"
android:orientation="vertical"
app:layout_behavior=".view.FullNestedScrollBottomSheetBehavior"
app:behavior_hideable="false"
app:behavior_peekHeight="@dimen/bottom_sheet_min_height"
>
<androidx.appcompat.widget.AppCompatImageView
android:id="@ id/anchorImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="-4dp"
android:layout_gravity="center"
android:paddingTop="4dp"
android:src="@drawable/ic_baseline"
android:tint="@android:color/white"
/>
<com.google.android.material.tabs.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@ id/tabLayout"
app:tabTextColor="#b2ffffff"
app:tabIconTint="@color/selector_status_tab"
app:tabRippleColor="#42ffffff"
app:tabSelectedTextColor="@android:color/white"
app:tabIndicatorColor="@android:color/white"
>
...
</com.google.android.material.tabs.TabLayout>
<androidx.viewpager.widget.ViewPager
android:id="@ id/viewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
/>
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
И в итоге я пришел к следующему подходу:
- Запретить
BottomSheet
принимать вложенную прокрутку:
class FullNestedScrollBottomSheetBehavior<V: View>(
context: Context,
attrs: AttributeSet?
): BottomSheetBehavior<V>(context, attrs) {
override fun onStartNestedScroll(...) = false
}
- Динамически изменять высоту родительского элемента вложенного элемента прокрутки (в моем случае это a,
ViewPager
который содержитNestedScrollView
иRecyclerView
) в соответствии с реальной высотойBottomSheet
видимой части:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
bottomSheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {}
override fun onSlide(bottomSheet: View, slideOffset: Float) {
val height = view.height - bottomSheet.top - anchorImage.height 4.dp - tabLayout.height
val params = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, height)
viewPager.layoutParams = params
}
})
}
- Поскольку
onSlide()
не будет вызван, пока вы не перетащите свойBottomSheet
, приведенная выше логика должна быть продублирована на что-то вродеonViewCreated()
:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
view.post {
val h = view.height - bottomSheetLayout.top - anchorImage.height 4.dp - tabLayout.height
val p = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, h)
viewPager.layoutParams = p
}
// here goes the code from the second point
}
Я думаю, что предоставленное решение может быть хорошим советом для реализации точного поведения, требуемого в вопросе.