programing

내부 CoordinatorLayout과 함께 BottomSheetBehavior 사용

kingscode 2021. 1. 16. 10:00
반응형

내부 CoordinatorLayout과 함께 BottomSheetBehavior 사용


코디네이터의 자식이 하단 시트 (화면 하단에서 드래그 할 수있는 뷰) 역할을 할 수 있는 디자인 지원 라이브러리가 v. 23.2도입되었습니다 BottomSheetBehavior.

내가하고 싶은 것은 하단 시트 뷰로 다음 뷰 (일반 코디네이터 + 축소 항목)를 갖는 것입니다.

<CoordinatorLayout
    app:layout_behavior=“@string/bottom_sheet_behavior”>

   <AppBarLayout>
        <CollapsingToolbarLayout>
           <ImageView />
        </CollapsingToolbarLayout>
    </AppBarLayout>

    <NestedScrollView>
        <LinearLayout>
            < Content ... />
        </LinearLayout>
    </NestedScrollView>

</CoordinatorLayout>

안타깝게도 하단 시트보기는 중첩 스크롤을 구현해야합니다. 그렇지 않으면 스크롤 이벤트를받지 못합니다. 기본 활동으로 시도한 다음이보기를 하단 시트로로드하면 스크롤 이벤트가 종이의 "시트"에서만 작동하며 계속 읽는 경우 알 수 있듯이 이상한 동작이 있음을 알 수 있습니다.

나는 이것이 서브 클래 싱 CoordinatorLayout또는 서브 클래 싱에 의해 더 잘 처리 될 수 있다고 확신한다 BottomSheetBehavior. 힌트가 있습니까?

몇 가지 생각

  • requestDisallowInterceptTouchEvent() 일부 조건에서 부모의 이벤트를 훔치기 위해 사용되어야합니다.

    • AppBarLayout오프셋> 0
    • AppBarLayout오프셋이 == 0 일 때, 우리는 위로 스크롤하고 있습니다 (잠시 동안 생각해 보면 알 수 있습니다)
  • 첫 번째 조건 OnOffsetChanged은를 내부 앱 바에 설정하여 얻을 수 있습니다 .

  • 두 번째는 몇 가지 이벤트 처리가 필요합니다. 예를 들면 다음과 같습니다.

    switch (MotionEventCompat.getActionMasked(event)) {
        case MotionEvent.ACTION_DOWN:
            startY = event.getY();
            lastY = startY;
            userIsScrollingUp = false;
            break;
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            userIsScrollingUp = false;
            break;
        case MotionEvent.ACTION_MOVE:
            lastY = event.getY();
            float yDeltaTotal = startY - lastY;
            if (yDeltaTotal > touchSlop) { // Moving the finger up.
                userIsScrollingUp = true;
            }
            break;
    }
    

이슈

말할 필요도없이 지금은이 일을 할 수 없습니다. 조건이 충족되면 이벤트를 잡을 수없고 다른 경우에는 잡을 수 없습니다. 아래 이미지에서 표준 CoordinatorLayout에서 어떤 일이 발생하는지 확인할 수 있습니다.

  • 앱바에서 아래로 스크롤하면 시트가 닫히지 만 중첩 된 콘텐츠에서 아래로 스크롤하면 닫힙니다. 중첩 된 스크롤 이벤트가 Coordinator 동작으로 전파되지 않는 것 같습니다.

  • 내부 앱 바에도 문제가 있습니다. 중첩 된 스크롤 콘텐츠가 축소 될 때 앱 바를 따르지 않습니다.

여기에 이미지 설명 입력

이러한 문제를 보여주는 github에 샘플 프로젝트를 설정했습니다 .

명확하게 말하면 원하는 동작은 다음과 같습니다.

  • 시트 내 앱바 / 스크롤보기의 올바른 동작;

  • 시트가 확장되면 아래로 스크롤하면 축소 될 수 있지만 내부 앱 바도 완전히 확장 된 경우에만 가능합니다 . 지금은 앱바 상태와 상관없이 앱 바를 드래그하는 경우에만 축소됩니다.

  • 시트가 축소되면 스크롤 업 제스처로 확장됩니다 (내부 앱 바에는 영향을주지 않음).

연락처 앱의 예 (아마도 BottomSheetBehavior를 사용하지 않지만 이것이 내가 원하는 것입니다) :

여기에 이미지 설명 입력


마침내 구현을 릴리스했습니다. Github에서 또는 jcenter에서 직접 찾으십시오 .

compile 'com.otaliastudios:bottomsheetcoordinatorlayout:1.0.0’

해야 할 일은 BottomSheetCoordinatorLayout하단 시트의 루트 뷰로 사용하는 것입니다 . 자동으로 작동하는 동작을 부풀 리므로 걱정하지 마십시오.

나는 이것을 오랫동안 사용해 왔으며 스크롤 문제가 없어야하며 ABL에서 드래그를 지원합니다.


방금 위의 질문을 한 방식을 따랐고 더 많은 설명이 필요한 솔루션을 찾았습니다. 샘플 코드를 따르고 xml에 추가 부분을 통합하여 BottomSheeet 동작처럼 동작하도록 만드십시오.

<CoordinatorLayout>
   <AppBarLayout>
        <Toolbar
            app:layout_collapseMode="pin">
        </Toolbar>
    </AppBarLayout>
    <NestedScrollView
         app:layout_behavior=“@string/bottom_sheet_behavior” >
        <include layout="@layout/items" />
    </NestedScrollView>

    <!-- Bottom Sheet -->

     <BottomSheetCoordinatorLayout>
        <AppBarLayout
            <CollapsingToolbarLayout">
             <ImageView />
                <Toolbar />
            </CollapsingToolbarLayout>
        </AppBarLayout>
        <NestedScrollView">
            <include layout="@layout/items" />
        </NestedScrollView>
    </BottomSheetCoordinatorLayout>
</CoordinatorLayout>

참고 : 나를 위해 일한 솔루션은 이미 귀하의 질문의 마지막 댓글에서 설명했습니다.

더 나은 explantion : https://github.com/laenger/BottomSheetCoordinatorLayout


첫 번째 자녀가 있으면 nestedscroll다른 문제가 발생합니다. 이 솔루션은 내 문제가 해결되었습니다.

<CoordinatorLayout
    app:layout_behavior=“@string/bottom_sheet_behavior”>

   <AppBarLayout>
        <CollapsingToolbarLayout>
           <ImageView />
        </CollapsingToolbarLayout>
    </AppBarLayout>
</LinearLayout>
    <NestedScrollView>
        <LinearLayout>
            < Content ... />
        </LinearLayout>
    </NestedScrollView>
</LinearLayout>
</CoordinatorLayout>

NestedScrollView와 함께 사용하지 마십시오 LinearLayout. 내 앱에서도 문제가 발생했습니다. LinearLayout대신 사용 하십시오.

다음을 시도하십시오.

<CoordinatorLayout
app:layout_behavior=“@string/bottom_sheet_behavior”>

<AppBarLayout>
    <CollapsingToolbarLayout>
       <ImageView />
    </CollapsingToolbarLayout>
</AppBarLayout>

<LinearLayout>
     <!--don't forget to addd this line-->
     app:layout_behavior="@string/appbar_scrolling_view_behavior">

        < Content ... />
</LinearLayout>


나는이 문제와 관련하여 laenger의 초기 github 테스트 프로젝트를 따랐으며, 내 앱에서도이 동작이 필요했기 때문에 그의 문제에 대한 해결책을 공유하게되어 기쁩니다.

이것은 그의 문제에 대한 해결책입니다. ❌ 툴바가 때때로 너무 일찍 축소됩니다.

이를 방지하려면 사용자 정의를 만들어야합니다 . 스크롤 동작을 가져 AppBarLayout.Behavior오는 동안 드래그하는 동안 위로 스크롤 할 때이기 때문입니다 AppBarLayout.behavior. STATE_DRAGGING인지 감지하고 툴바를 너무 일찍 숨기거나 접는 것을 피하기 위해 돌아와야합니다.

public class CustomAppBarLayoutBehavior extends AppBarLayout.Behavior {

    private CoordinatorLayoutBottomSheetBehavior behavior;

    public CustomAppBarLayoutBehavior() {
    }

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

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes) {
        behavior = CoordinatorLayoutBottomSheetBehavior.from(parent);
        return super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes);
    }

    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int[] consumed) {
        if(behavior.getState() == CoordinatorLayoutBottomSheetBehavior.STATE_DRAGGING){
            return;
        }else {
            super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
        }
    }

    @Override
    public void setDragCallback(@Nullable DragCallback callback) {
        super.setDragCallback(callback);
    }
}

다른 문제를 해결하는 방법에 대한 좋은 시작이 될 수 있습니다.

❌ 툴바는 드래그로 축소 할 수 없습니다.

❌ 메인 코디네이터 레이아웃이 스크롤을 사용합니다.

나는 실제로 좋은 UI / 애니메이션 사람은 아니지만, 열심히 노력하면 때때로 코드를 이해하고 구현할 올바른 콜백 / 오버라이드 함수를 찾는 데 도움이됩니다.

이것을 appbarlayout에 대한 동작으로 설정하십시오.

<android.support.design.widget.AppBarLayout
    android:id="@+id/bottom_sheet_appbar"
    style="@style/BottomSheetAppBarStyle"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:layout_behavior="your.package.CustomAppBarLayoutBehavior">

앱바 레이아웃의 전체 화면 레이아웃은 다음과 같습니다.

<android.support.design.widget.AppBarLayout
    android:id="@+id/appbar"
    android:layout_width="match_parent"
    android:layout_height="@dimen/detail_backdrop_height"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    android:fitsSystemWindows="true">

    <android.support.design.widget.CollapsingToolbarLayout
        android:id="@+id/collapsing_toolbar"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_scrollFlags="scroll|exitUntilCollapsed"
        android:fitsSystemWindows="true"
        app:contentScrim="?attr/colorPrimary"
        app:expandedTitleMarginStart="48dp"
        app:expandedTitleMarginEnd="64dp">

        <ImageView
            android:id="@+id/backdrop"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            android:fitsSystemWindows="true"
            app:layout_collapseMode="parallax" />

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
            app:layout_collapseMode="pin" />

    </android.support.design.widget.CollapsingToolbarLayout>

</android.support.design.widget.AppBarLayout>

<android.support.v4.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingTop="24dp">

        <android.support.v7.widget.CardView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/card_margin">

            <LinearLayout
                style="@style/Widget.CardContent"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="Info"
                    android:textAppearance="@style/TextAppearance.AppCompat.Title" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="@string/cheese_ipsum" />

            </LinearLayout>

        </android.support.v7.widget.CardView>

        <android.support.v7.widget.CardView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="@dimen/card_margin"
            android:layout_marginLeft="@dimen/card_margin"
            android:layout_marginRight="@dimen/card_margin">

            <LinearLayout
                style="@style/Widget.CardContent"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="Friends"
                    android:textAppearance="@style/TextAppearance.AppCompat.Title" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="@string/cheese_ipsum" />

            </LinearLayout>

        </android.support.v7.widget.CardView>

        <android.support.v7.widget.CardView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="@dimen/card_margin"
            android:layout_marginLeft="@dimen/card_margin"
            android:layout_marginRight="@dimen/card_margin">

            <LinearLayout
                style="@style/Widget.CardContent"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="Related"
                    android:textAppearance="@style/TextAppearance.AppCompat.Title" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="@string/cheese_ipsum" />

            </LinearLayout>

        </android.support.v7.widget.CardView>

    </LinearLayout>

</android.support.v4.widget.NestedScrollView>

<android.support.design.widget.FloatingActionButton
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    app:layout_anchor="@id/appbar"
    app:layout_anchorGravity="bottom|right|end"
    android:src="@drawable/ic_discuss"
    android:layout_margin="@dimen/fab_margin"
    android:clickable="true"/>

그런 다음 클래스에서 AppBarLayout.OnOffsetChangedListener를 구현하고 화면의 오프셋을 설정해야합니다.

참조 URL : https://stackoverflow.com/questions/36229911/using-bottomsheetbehavior-with-a-inner-coordinatorlayout

반응형