Google지도의 하단 시트 3 단계 동작을 모방하는 방법은 무엇입니까?


110

배경

저는 Google지도에서 찾은 결과에 대한 하단 시트를 표시하는 방식과 유사한 UI를 만들도록 지정되었습니다.

세 가지 단계가 있습니다.

  1. 하단 내용. 상단 영역은 여전히 ​​터치 가능하며 하단에서 아무것도 스크롤하지 않습니다.
  2. 전체 화면 콘텐츠, 상단 영역에는 큰 헤더가 있습니다.
  3. 전체 화면 콘텐츠, 상단 영역에는 도구 모음 만 있습니다.

Google지도에서 제가 말하는 내용은 다음과 같습니다.

여기에 이미지 설명 입력

문제

사실, 하단 시트는 아직 디자인 라이브러리의 일부가 아닙니다 (요청되었지만 여기 ).

뿐만 아니라 UI가 매우 복잡해 보이며 여러 단계에서 도구 모음을 처리해야합니다.

내가 시도한 것

하단 시트 ( 여기 )에 대한 좋은 (충분한) 라이브러리를 찾았고 조각 샘플에 콘텐츠를 추가하여 머티리얼 디자인 샘플 (예 : 여기 ) 에 표시된 것과 거의 동일한 뷰 를 갖도록하여 CollapsingToolbarLayout을 처리합니다. 단계 2 + 3.

제가 만들고있는 앱에서 스크롤을하면서 아이콘도 움직여야하는데 나머지는 성공하면 쉬울 것 같아요. 코드는 다음과 같습니다.

fragment_my.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    android:id="@+id/main_content"
    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="@dimen/detail_backdrop_height"

        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"

            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginEnd="64dp"
            app:expandedTitleMarginStart="48dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">

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

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
        </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_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/fab_margin"
        android:clickable="true"
        android:src="@android:drawable/ic_menu_send"
        app:layout_anchor="@id/appbar"
        app:layout_anchorGravity="bottom|right|end"/>

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

MyFragment.java

public class MyFragment extends BottomSheetFragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        final View view = inflater.inflate(R.layout.fragment_my, container, false);
        view.setMinimumHeight(getResources().getDisplayMetrics().heightPixels);
        CollapsingToolbarLayout collapsingToolbar = (CollapsingToolbarLayout) view.findViewById(R.id.collapsing_toolbar);
        collapsingToolbar.setTitle("AAA");
        final Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar);
        final AppCompatActivity activity = (AppCompatActivity) getActivity();
        activity.setSupportActionBar(toolbar);
        activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        //toolbar.setNavigationIcon(R.drawable.abc_ic_ab_back_mtrl_am_alpha);
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                NavUtils.navigateUpFromSameTask(getActivity());
            }
        });
        final ImageView imageView = (ImageView) view.findViewById(R.id.backdrop);

        Glide.with(this).load(R.drawable.cheese_1).centerCrop().into(imageView);
        return view;
    }
}

BottomSheetFragmentActivity.java

public final class BottomSheetFragmentActivity extends AppCompatActivity {

    protected BottomSheetLayout bottomSheetLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bottom_sheet_fragment);
        bottomSheetLayout = (BottomSheetLayout) findViewById(R.id.bottomsheet);
        findViewById(R.id.bottomsheet_fragment_button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new MyFragment().show(getSupportFragmentManager(), R.id.bottomsheet);
            }
        });
        bottomSheetLayout.setShouldDimContentView(false);
        bottomSheetLayout.setPeekOnDismiss(true);
        bottomSheetLayout.setPeekSheetTranslation(200);
        bottomSheetLayout.setInterceptContentTouch(false);
        bottomSheetLayout.setDefaultViewTransformer(new BaseViewTransformer() {
            @Override
            public void transformView(final float translation, final float maxTranslation, final float peekedTranslation, final BottomSheetLayout parent, final View view) {
                Log.d("AppLog", "translation:" + translation + " maxTranslation:" + maxTranslation + " peekedTranslation:" + peekedTranslation);
            }
        });
    }
}

거의 잘 작동합니다. 유일한 문제는 # 3에서 # 2 로의 전환입니다.

여기에 이미지 설명 입력

질문

코드에 어떤 문제가 있습니까? 필요한 동작을 수행하기 위해 무엇을 할 수 있습니까?


나에게 활동 전환처럼 보입니다. 2 개의 활동을 만들고 그 사이에 재료 전환을 적용 해 보셨습니까? 그리고 CoordinatorLayout두 번째 화면에서 사용합니까?
SD

@SD 두 가지 활동이 아니라고 확신합니다. 화면을 계속 터치하여 스크롤하고 단계를 전환 할 수 있기 때문입니다. 다음 / 이전 활동으로 이동하는 것을 멈추지 않습니다. 새 활동을 열 때 스크롤 메커니즘에 대해 동일한 터치 이벤트를 지속하는 것이 가능하지 않다고 생각합니다. 프래그먼트를 사용하는 것이 가능한지 확실하지 않지만 이것은 아마도 활동보다 가능할 것입니다.
안드로이드 개발자

그런 다음 모든 뷰가 동일한 레이아웃에 있고 각각 특정 동작이 설정되어 있다고 생각합니다. 그리고 모든 동작은 모든 것을 조정하는 루트 레이아웃의 수직 스크롤 차단에서 트리거됩니다.
SD

@SD 잘 작동하는 방법을 알고 있습니까? 내가 찾은 것보다 낫습니까?
안드로이드 개발자

1
도서관 을 한 번 보셔야한다고 생각합니다 .
Savelii Zagurskii

답변:


18

참고 : 하단의 수정 사항을 읽으십시오.


좋아, 나는 그것을 할 수있는 방법을 찾았지만 하단 시트가 appBarLayout의 상태 (확장 여부)를 알 수 있도록 여러 클래스의 코드를 변경해야하고 스크롤 업을 무시해야합니다. 확장되지 않음 :

BottomSheetLayout.java

추가 된 필드 :

private AppBarLayout mAppBarLayout;
private OnOffsetChangedListener mOnOffsetChangedListener;
private int mAppBarLayoutOffset;

init ()-다음을 추가했습니다.

    mOnOffsetChangedListener = new OnOffsetChangedListener() {
        @Override
        public void onOffsetChanged(final AppBarLayout appBarLayout, final int verticalOffset) {
            mAppBarLayoutOffset = verticalOffset;
        }
    };

appBarLayout 설정 기능 추가 :

public void setAppBarLayout(final AppBarLayout appBarLayout) {
    if (mAppBarLayout == appBarLayout)
        return;
    if (mAppBarLayout != null)
        mAppBarLayout.removeOnOffsetChangedListener(mOnOffsetChangedListener);
    mAppBarLayout = appBarLayout;
    mAppBarLayout.addOnOffsetChangedListener(mOnOffsetChangedListener);
}

onDetachedFromWindow ()-다음을 추가했습니다.

    if (mAppBarLayout != null)
        mAppBarLayout.removeOnOffsetChangedListener(mOnOffsetChangedListener);

onTouchEvent ()-다음을 추가했습니다.

      ...
      if (bottomSheetOwnsTouch) {
        if (state == State.EXPANDED && scrollingDown && mAppBarLayout != null && mAppBarLayoutOffset != 0) {
            event.offsetLocation(0, sheetTranslation - getHeight());
            getSheetView().dispatchTouchEvent(event);
            return true;
        }
      ...

이것이 주요 변화였습니다. 이제 무엇이 그들을 설정하는지 :

MyFragment.java

onCreateView ()-다음을 추가했습니다.

    mBottomSheetLayout.setAppBarLayout((AppBarLayout) view.findViewById(R.id.appbar));

이 기능도 추가했습니다.

 public void setBottomSheetLayout(final BottomSheetLayout bottomSheetLayout) {
    mBottomSheetLayout = bottomSheetLayout;
}

이제 액티비티가 appBarLayout에 대해 프래그먼트에 알리는 방법입니다.

            final MyFragment myFragment = new MyFragment();
            myFragment.setBottomSheetLayout(bottomSheetLayout);
            myFragment.show(getSupportFragmentManager(), R.id.bottomsheet);

이제 GitHub에서 프로젝트를 사용할 수 있습니다.

https://github.com/AndroidDeveloperLB/ThreePhasesBottomSheet

버그가 없길 바랍니다.


슬프게도 솔루션에는 버그가 있으므로이 답변을 올바른 답변으로 표시하지 않겠습니다.

  1. Android 6 이상에서만 잘 작동합니다. 다른 것들은 그것을 보여줄 때마다 아주 작은 시간 동안 확장 된 하단 시트를 보여주는 이상한 행동을합니다.
  2. 방향 변경은 스크롤 상태를 전혀 저장하지 않으므로 비활성화했습니다.
  3. 하단 시트의 콘텐츠가 아직 접혀있는 동안 (하단) 스크롤 할 수있는 드문 문제
  4. 이전에 키보드가 표시된 경우 엿 보려고 할 때 하단 시트가 전체 화면이 될 수 있습니다.

누구든지 도와 줄 수 있으면 도와주세요.


문제 # 1의 경우 하단 시트가 아직 엿 보지 않은 경우 가시성을 INVISIBLE로 설정하여 수정 사항을 추가하려고 시도했지만, 특히 키보드가 표시되는 경우 항상 작동하지는 않습니다.


문제 # 1의 경우 CoordinatorLayout을 사용하려는 뷰 (FrameLayout 사용)로 감싸고 ( "fragment_my.xml"에서) 전체 크기 뷰를 배치하여 문제를 해결하는 방법을 찾았습니다. 다음과 같이 ( "View"를 입력합니다.)

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!--This full sized view, together with the FrameLayout above, are used to handle some weird UI issues on pre-Android-6 -->
    <View
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <...CollapsingToolbarLayout 
    ...

CoordinatorLayout이 뷰가되었을 때 bottomSheet를 혼동했을 것입니다. 프로젝트를 업데이트했지만 더 좋은 솔루션을 가질 수있는 방법이 있다면 그것에 대해 알고 싶습니다.


최근 몇 달 동안 Google은 자체 bottomSheet 클래스를 게시했지만 많은 문제가 있다는 것을 알게 되었기 때문에 사용해 볼 수도 없습니다.


하지만이 이미지는 어떻습니까? cloud.githubusercontent.com/assets/5357526/11641271/… 하단 시트 와 함께 이런 종류의 이미지 슬라이드를 구현하고 싶습니다
Hardy

@HBdroid 나는 그것이 가능하다고 생각합니다. "onOffsetChanged"함수의 경우 mBottomSheetBackgroundImageView의 번역도 변경 하시겠습니까? 제 케이스의 요구 사항은 3 단계를 먼저 처리하는 것이 었습니다. 이제 무엇을 어떻게 전환해야하는지에 대한 질문입니다. 이것은 매우 맞춤화되어 있으며 귀하의 필요에 따라 다릅니다. 또한 많은 성가신 수학이 필요합니다. 빠른 실행을 위해 즉시 실행 기능을 사용하는 것이 좋습니다.
안드로이드 개발자

내가 나를 솔루션 제발 도움을 찾을 수 없습니다입니다
하디

@HBdroid 죄송합니다. 이 app : layout_collapseMode = "parallax"를 제거해보세요. 또한 transformView에서 번역을 시도하십시오.
안드로이드 개발자

2
@Hardy 원하는 솔루션을 만들었습니까? 그렇다면 오픈 소스이며 공유 할 수 있습니까?
N 제이

15

큰 업데이트

같은 주제에 대해 4 ~ 5 개의 질문이 있었기 때문에 요구 사항이 다르고 모든 질문에 답하려고했지만 정중하지 않은 관리자가 삭제 / 닫아서 각각에 대한 티켓을 만들고 다음으로 변경했습니다. "복사 붙여 넣기"를 피 하십시오. Google지도와 같은 전체 동작을 얻는 방법에 대한 모든 설명을 찾을 수 있는 전체 답변 에 대한 링크를 제공합니다 .


질문에 답하기

Google지도의 하단 시트 3 단계 동작을 모방하는 방법은 무엇입니까?

지원 라이브러리 23.x.x +를 사용하면 기본값을 수정하여 BottomSheetBehavior다음 단계에 따라 통계를 하나 더 추가 할 수 있습니다 .

  1. Java 클래스를 만들고 다음에서 확장합니다. CoordinatorLayout.Behavior<V>
  2. 기본 BottomSheetBehavior파일에서 새 파일로 붙여 넣기 코드를 복사 합니다.
  3. clampViewPositionVertical다음 코드로 메서드 를 수정합니다 .

    @Override
    public int clampViewPositionVertical(View child, int top, int dy) {
        return constrain(top, mMinOffset, mHideable ? mParentHeight : mMaxOffset);
    }
    int constrain(int amount, int low, int high) {
        return amount < low ? low : (amount > high ? high : amount);
    }
  4. 새 상태 추가 :

    public static final int STATE_ANCHOR_POINT = X;
  5. 다음 방법을 수정 onLayoutChild, onStopNestedScroll, BottomSheetBehavior<V> from(V view)setState(선택 사항)

수정 된 메서드와 예제 프로젝트에 대한 링크 를 추가하겠습니다 .

다음은 그 모습입니다.
CustomBottomSheetBehavior


나는 지금 github repo를 테스트했는데 멋져 보인다. 그러나 위쪽 파란색 영역은 때때로 부분적으로 보입니다. 또한 하단 시트를 드래그 할 때 이동해야하는 뷰를 처리 할 위치를 찾을 수 없습니다. 내가 만든 저장소 (여기 : github.com/AndroidDeveloperLB/ThreePhasesBottomSheet )에서 이미지가 사라지고 작은 이미지가 크기 변경을 포함하여 한 위치에서 다른 위치로 이동합니다. 그 처리를 추가 할 위치를 알고 싶습니다.
안드로이드 개발자

안녕하세요, 시차 이미지가있는 로컬 버전이 있지만 아직 제대로 작동하지 않습니다 (보고 싶다면 푸시 할 수 있습니다). 당신은 내부에보기를 추가 할 수 CoordinatorLayout있는을 activity_main.xml. 코디네이터 레이아웃에 대해 좋은 경험이 있으신 것 같군요. 그렇지 않으면 제가 찾은
MiguelHincapieC

툴바 동작을 어떻게 얻었는지 살펴보고 내 작업에서 사용할 것입니다. : D. 그런데 지원 라이브러리 23.2를 사용하는 경우에만 모방 할 수있는 약간의 동작이 있습니다. Google지도에서 이미지를 툴바 아래로 드래그하면 하단 시트가 이동하지만 23.4 또는 minSdkVersion 14+로 업그레이드하면 o_O '
MiguelHincapieC

@androiddeveloper 맞았어요! 이제는 이미지 시차 효과 및 도구 모음 애니메이션과 함께 작동합니다. 계속해서 슬라이드 할 때 도구 모음을 사용하는 색상 만 누락되었습니다. D
MiguelHincapieC

@MiguelHincapieC 안녕하세요, 주 도구 모음 만 표시하고 병합 된 appbar 레이아웃을 제거했지만 하단 시트에서 시간 상태 표시 줄이 표시되지 않고 상태 표시 줄 위치로 끝을 확장하고 기본 도구 모음 아래에 parallex 이미지를 고정하고 싶습니다. 어떻게 할 수 있는지 설명해 주
Vijay Rajput

0

이거 해봤 어? http://android-developers.blogspot.in/2016/02/android-support-library-232.html?m=1 여기에서는 하단 시트 레이아웃 동작을 지정할 수 있다고 말합니다.

최신 정보:

기본적으로 링크 상태-

BottomSheetBehavior를 CoordinatorLayout의 자식 뷰에 연결하면 (즉, app : layout_behavior = "android.support.design.widget.BottomSheetBehavior"추가) 5 개 상태간에 전환 할 수있는 적절한 터치 감지 기능을 자동으로 얻습니다.

STATE_COLLAPSED: this collapsed state is the default and shows just a portion of the layout along the bottom. The height can be controlled with the app:behavior_peekHeight attribute (defaults to 0)
STATE_DRAGGING: the intermediate state while the user is directly dragging the bottom sheet up or down
STATE_SETTLING: that brief time between when the View is released and settling into its final position
STATE_EXPANDED: the fully expanded state of the bottom sheet, where either the whole bottom sheet is visible (if its height is less than the containing CoordinatorLayout) or the entire CoordinatorLayout is filled
STATE_HIDDEN: disabled by default (and enabled with the app:behavior_hideable attribute), enabling this allows users to swipe down on the bottom sheet to completely hide the bottom sheet
Keep in mind that scrolling containers in your bottom sheet must support nested scrolling (for example, NestedScrollView, RecyclerView, or ListView/ScrollView on API 21+).

상태 변경에 대한 콜백을 수신하려면 BottomSheetCallback을 추가 할 수 있습니다.

// The View with the BottomSheetBehavior  
 View bottomSheet = coordinatorLayout.findViewById(R.id.bottom_sheet);  
 BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);  
 behavior.setBottomSheetCallback(new BottomSheetCallback() {  
    @Override  
    public void onStateChanged(@NonNull View bottomSheet, int newState) {  
      // React to state change  
    }  
      @Override  
      public void onSlide(@NonNull View bottomSheet, float slideOffset) {  
       // React to dragging events  
   }  
 });  

BottomSheetBehavior가 영구 하단 시트 케이스를 캡처하는 동안이 릴리스에서는 모달 하단 시트 사용 사례를 채우기 위해 BottomSheetDialog 및 BottomSheetDialogFragment도 제공합니다. AppCompatDialog 또는 AppCompatDialogFragment를 하단 시트에 해당하는 항목으로 바꾸면 대화 상자가 하단 시트로 스타일이 지정됩니다.


이 질문은 Google이 지원 라이브러리 클래스를 표시하기 전에 만들어졌습니다. 이를 사용하는 작업 솔루션이있는 경우 여기에 표시하십시오.
안드로이드 개발자

@androiddeveloper 질문 날짜를 읽지 않았 으므로이 답변을 제안했습니다. 그러나이 라이브러리를 사용하려면 사용할 수 있습니다. 이 코드에 대한 작업 솔루션에 관해서는 없습니다. 죄송합니다.
Vaibhav Sharma

0

또한 Google지도에서 찾은 결과에 대한 하단 시트를 표시하는 것과 유사한보기를 구현해야했습니다.

내 모습은 다음과 같습니다.

엿보기

맨 위로 스크롤 된보기 확장

아래로 스크롤 된보기 확장

처음에는 헤더와 스크롤 가능한 콘텐츠로 하단 시트를 정의했지만 layout_height는 wrap_content.

내가 사용하는 경우 그 문제는 도망 갔어요 LinearLayout대신 ConstraintLayout에 대한 CoordinatorLayout의 아이의 레이아웃 (및 어린이를위한).

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/buttonPeek"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Peek"
        app:layout_constraintEnd_toStartOf="@+id/buttonExpand"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/buttonExpand"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Expand"
        app:layout_constraintEnd_toStartOf="@+id/buttonClose"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/buttonPeek"
        app:layout_constraintTop_toTopOf="@+id/buttonPeek" />

    <Button
        android:id="@+id/buttonClose"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Close"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/buttonExpand"
        app:layout_constraintTop_toTopOf="@+id/buttonExpand" />

    <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:id="@+id/layout_coordinator"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <LinearLayout
            android:id="@+id/layout_coordinator_child"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:behavior_hideable="true"
            app:layout_behavior="@string/bottom_sheet_behavior">

            <LinearLayout
                android:id="@+id/layout_bottom_sheet_header"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="#FFFF0000"
                android:orientation="vertical" >

                <TextView
                    android:id="@+id/headerTextView_a"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="a" />

                <TextView
                android:id="@+id/headerTextView_b"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="b" />

                <TextView
                android:id="@+id/headerTextView_c"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="c" />

                <TextView
                android:id="@+id/headerTextView_d"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="d" />

                <TextView
                android:id="@+id/headerTextView_e"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="e" />

                <TextView
                android:id="@+id/headerTextView_f"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="f" />

                <TextView
                android:id="@+id/headerTextView_g"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="g" />

                <TextView
                android:id="@+id/headerTextView_h"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="h" />

                <TextView
                android:id="@+id/headerTextView_i"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="i" />

                <TextView
                android:id="@+id/headerTextView_j"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="j" />

                <TextView
                android:id="@+id/headerTextView_k"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="k" />

            </LinearLayout>

            <androidx.core.widget.NestedScrollView
                android:id="@+id/layout_bottom_sheet_scrollable_view"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="#FF00FF00"
                android:fillViewport="true" >

                <LinearLayout
                    android:id="@+id/layout_bottom_sheet_scrollable_content"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">

                    <TextView
                        android:id="@+id/textView0"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="0" />

                    <TextView
                        android:id="@+id/textView1"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="1" />

                    <TextView
                        android:id="@+id/textView2"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="2" />

                    <TextView
                        android:id="@+id/textView3"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="3" />

                    <TextView
                        android:id="@+id/textView4"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="4" />

                    <TextView
                        android:id="@+id/textView5"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="5" />

                    <TextView
                        android:id="@+id/textView6"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="6" />

                    <TextView
                        android:id="@+id/textView7"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="7" />

                    <TextView
                        android:id="@+id/textView8"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="8" />

                    <TextView
                        android:id="@+id/textView9"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="9" />

                    <TextView
                        android:id="@+id/textView10"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="10" />

                    <TextView
                        android:id="@+id/textView11"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="11" />

                    <TextView
                        android:id="@+id/textView12"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="12" />

                    <TextView
                        android:id="@+id/textView13"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="13" />

                    <TextView
                        android:id="@+id/textView14"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="14" />

                    <TextView
                        android:id="@+id/textView15"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="15" />

                    <TextView
                        android:id="@+id/textView16"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="16" />

                    <TextView
                        android:id="@+id/textView17"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="17" />

                    <TextView
                        android:id="@+id/textView18"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="18" />

                    <TextView
                        android:id="@+id/textView19"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="19" />

                    <TextView
                        android:id="@+id/textView20"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="20" />

                    <TextView
                        android:id="@+id/textView21"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="21" />

                    <TextView
                        android:id="@+id/textView22"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="22" />

                    <TextView
                        android:id="@+id/textView23"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="23" />

                    <TextView
                        android:id="@+id/textView24"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="24" />

                    <TextView
                        android:id="@+id/textView25"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="25" />

                    <TextView
                        android:id="@+id/textView26"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="26" />

                    <TextView
                        android:id="@+id/textView27"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="27" />

                    <TextView
                        android:id="@+id/textView28"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="28" />

                    <TextView
                        android:id="@+id/textView29"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="29" />

                    <TextView
                        android:id="@+id/textView30"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="30" />

                    <TextView
                        android:id="@+id/textView31"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="31" />

                    <TextView
                        android:id="@+id/textView32"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="32" />

                    <TextView
                        android:id="@+id/textView33"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="33" />

                    <TextView
                        android:id="@+id/textView34"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="34" />

                    <TextView
                        android:id="@+id/textView35"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="35" />

                    <TextView
                        android:id="@+id/textView36"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="36" />

                    <TextView
                        android:id="@+id/textView37"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="37" />

                    <TextView
                        android:id="@+id/textView38"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="38" />

                    <TextView
                        android:id="@+id/textView39"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="39" />

                    <TextView
                        android:id="@+id/textView40"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="40" />

                    <TextView
                        android:id="@+id/textView41"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="41" />

                    <TextView
                        android:id="@+id/textView42"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="42" />

                    <TextView
                        android:id="@+id/textView43"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="43" />

                    <TextView
                        android:id="@+id/textView44"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="44" />

                    <TextView
                        android:id="@+id/textView45"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="45" />

                    <TextView
                        android:id="@+id/textView46"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="46" />

                    <TextView
                        android:id="@+id/textView47"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="47" />

                    <TextView
                        android:id="@+id/textView48"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="48" />

                    <TextView
                        android:id="@+id/textView49"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="49" />

                </LinearLayout>

            </androidx.core.widget.NestedScrollView>
        </LinearLayout>

    </androidx.coordinatorlayout.widget.CoordinatorLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity.java

package com.example.bottomsheetwithscrollablecontent;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import com.google.android.material.bottomsheet.BottomSheetBehavior;

import androidx.appcompat.app.AppCompatActivity;
import androidx.coordinatorlayout.widget.CoordinatorLayout;

public class MainActivity extends AppCompatActivity {
    private CoordinatorLayout layout_coordinator;
    private View layout_coordinator_child;
    private View layout_bottom_sheet_header;

    private BottomSheetBehavior behavior;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        layout_coordinator = findViewById(R.id.layout_coordinator);
        layout_coordinator_child = layout_coordinator.findViewById(R.id.layout_coordinator_child);
        layout_bottom_sheet_header = layout_coordinator.findViewById(R.id.layout_bottom_sheet_header);

        behavior = BottomSheetBehavior.from(layout_coordinator_child);

        Button buttonPeek = findViewById(R.id.buttonPeek);
        buttonPeek.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                behavior.setPeekHeight(layout_bottom_sheet_header.getHeight());
                behavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
            }
        });

        Button buttonExpand = findViewById(R.id.buttonExpand);
        buttonExpand.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
            }
        });

        Button buttonClose = findViewById(R.id.buttonClose);
        buttonClose.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                behavior.setState(BottomSheetBehavior.STATE_HIDDEN);
            }
        });
    }
}

app / build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.example.bottomsheetwithscrollablecontent"
        minSdkVersion 24
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.0.0-beta01'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.2'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.1.0-alpha4'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0-beta01'
    implementation "com.google.android.material:material:1.1.0-alpha04"
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.