จะเลียนแบบพฤติกรรม 3 เฟสด้านล่างของ Google Maps ได้อย่างไร


110

พื้นหลัง

ฉันได้รับมอบหมายให้สร้าง UI ที่ทำงานคล้ายกับที่ Google Maps แสดงแผ่นงานด้านล่างสำหรับผลลัพธ์ที่พบ

มีสามขั้นตอนที่แตกต่างกัน:

  1. เนื้อหาด้านล่าง พื้นที่ด้านบนยังคงสัมผัสได้และจะไม่เลื่อนอะไรเลยที่ด้านล่าง
  2. เนื้อหาเต็มหน้าจอในขณะที่พื้นที่ด้านบนมีส่วนหัวขนาดใหญ่
  3. เนื้อหาเต็มหน้าจอในขณะที่พื้นที่ด้านบนมีเพียงแถบเครื่องมือ

นี่คือสิ่งที่ฉันกำลังพูดถึงบน Google Maps:

ใส่คำอธิบายภาพที่นี่

ปัญหา

สิ่งนี้คือแผ่นงานด้านล่างยังไม่ได้เป็นส่วนหนึ่งของไลบรารีการออกแบบ (แม้ว่าจะมีการร้องขอที่นี่ )

ไม่เพียงแค่นั้น แต่ 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บนหน้าจอที่ 2?
SD

@SD ฉันแน่ใจมากว่ามันไม่ใช่ 2 กิจกรรมเพราะคุณสามารถแตะหน้าจอเพื่อเลื่อนและสลับไปมาระหว่างเฟสได้ ไม่ได้หยุดให้คุณไปที่กิจกรรมถัดไป / ก่อนหน้า เมื่อเปิดกิจกรรมใหม่ฉันคิดว่าเป็นไปไม่ได้ที่จะยังคงมีกิจกรรมการสัมผัสแบบเดิมสำหรับกลไกการเลื่อน ฉันไม่แน่ใจด้วยซ้ำว่าเป็นไปได้ไหมโดยใช้ชิ้นส่วน แต่อาจเป็นไปได้มากกว่ากิจกรรม
นักพัฒนา android

จากนั้นฉันคิดว่ามุมมองทั้งหมดอยู่ในเลย์เอาต์เดียวกันโดยแต่ละมุมมองมีพฤติกรรมเฉพาะที่กำหนดไว้ และพฤติกรรมทั้งหมดจะถูกทริกเกอร์จากการสกัดกั้นการเลื่อนแนวตั้งบนเค้าโครงรูทซึ่งประสานทุกอย่าง
SD

@SD รู้วิธีทำให้ใช้งานได้ดี? ดีกว่าที่เคยเจอไหม?
นักพัฒนา Android

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 ฉันได้ลองเพิ่มการแก้ไขโดยตั้งค่าการมองเห็นเป็นมองไม่เห็นเมื่อยังไม่ได้มองแผ่นงานด้านล่าง แต่ก็ไม่ได้ผลเสมอไปโดยเฉพาะอย่างยิ่งหากมีการแสดงแป้นพิมพ์


สำหรับปัญหา # 1 ฉันได้พบวิธีแก้ไขแล้วโดยเพียงแค่ตัด (ใน "fragment_my.xml") CoordinatorLayout ด้วยมุมมองใด ๆ ที่คุณต้องการใช้ (ฉันใช้ FrameLayout) และยังใส่มุมมองขนาดเต็มไว้ใน (ฉันแค่ใส่ "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 
    ...

อาจจะสับสนใน bottomSheet เมื่อฉันมี CoordinatorLayout เป็นมุมมองของมัน ฉันได้อัปเดตโครงการแล้ว แต่หากมีวิธีแก้ไขปัญหาที่ดีกว่านี้ฉันอยากทราบเกี่ยวกับเรื่องนี้


ในช่วงไม่กี่เดือนที่ผ่านมา Google ได้เผยแพร่คลาส bottomSheet ของตัวเอง แต่เนื่องจากฉันพบว่ามันมีปัญหามากมายฉันจึงไม่สามารถลองใช้งานได้


แต่ภาพนี้ล่ะ? cloud.githubusercontent.com/assets/5357526/11641271/…ฉันต้องการใช้สไลด์รูปภาพประเภทนี้พร้อมกับด้านล่างขึ้นไป
Hardy

@HBdroid ฉันคิดว่ามันเป็นไปได้ สำหรับฟังก์ชัน "onOffsetChanged" เปลี่ยนการแปลของ mBottomSheetBackgroundImageView ด้วยหรือไม่ ข้อกำหนดในกรณีของฉันคือก่อนอื่นให้จัดการ 3 ขั้นตอน ตอนนี้เป็นคำถามว่าจะเปลี่ยนอะไรอย่างไรและปรับแต่งได้มากและขึ้นอยู่กับความต้องการของคุณ นอกจากนี้ยังต้องใช้คณิตศาสตร์จำนวนมากที่น่ารำคาญ ฉันขอแนะนำให้ใช้คุณลักษณะการเรียกใช้ทันทีเพื่อให้สามารถลองใช้งานได้อย่างรวดเร็ว
นักพัฒนา Android

ฉันไม่พบวิธีแก้ไขโปรดช่วยฉันด้วย
Hardy

@HBdroid ขออภัยฉันไม่ทราบ ลองลบแอปนี้: layout_collapseMode = "parallax" ลองทำการแปลใน transformView
นักพัฒนา Android

2
@ คุณยากที่จะสร้างโซลูชันที่คุณต้องการหรือไม่? ถ้าใช่มันเป็นโอเพ่นซอร์สและแชร์ได้หรือไม่
N Jay

15

อัปเดตครั้งใหญ่

เนื่องจากมีคำถาม 4 หรือ 5 ข้อเกี่ยวกับหัวข้อเดียวกัน แต่มีข้อกำหนดที่แตกต่างกันและฉันพยายามตอบคำถามทั้งหมด แต่ผู้ดูแลระบบที่ไม่สุภาพได้ลบ / ปิดคำถามเหล่านี้ทำให้ฉันสร้างตั๋วสำหรับแต่ละอันและเปลี่ยนเป็น หลีกเลี่ยงการ "คัดลอกวาง" ฉันจะให้ลิงก์ไปยังคำตอบที่สมบูรณ์ซึ่งคุณสามารถค้นหาคำอธิบายทั้งหมดเกี่ยวกับวิธีการทำงานอย่างสมบูรณ์เช่น Google Maps


ตอบคำถามของคุณ

จะเลียนแบบพฤติกรรม 3 เฟสด้านล่างของ Google Maps ได้อย่างไร

ด้วยไลบรารีสนับสนุน 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 แล้วและดูเหมือนจะดี แต่บางครั้งพื้นที่สีน้ำเงินด้านบนจะดูบางส่วน นอกจากนี้ฉันไม่พบตำแหน่งที่จะจัดการกับมุมมองที่ต้องย้ายเมื่อคุณลากแผ่นงานด้านล่าง ใน repo ที่ฉันทำ (ที่นี่: github.com/AndroidDeveloperLB/ThreePhasesBottomSheet ) ภาพจะจางลงและภาพขนาดเล็กจะเคลื่อนจากที่หนึ่งไปยังอีกที่หนึ่งรวมถึงการเปลี่ยนขนาดด้วย ฉันต้องการทราบว่าจะเพิ่มการจัดการเหล่านั้นได้ที่ไหน
นักพัฒนา Android

สวัสดีฉันมีเวอร์ชันท้องถิ่นที่มีอิมเมจพารัลแลกซ์ แต่ยังใช้งานได้ไม่ดี (ฉันสามารถผลักดันได้ถ้าคุณต้องการดู) คุณสามารถเพิ่มมุมมองใด ๆ ภายในในCoordinatorLayout activity_main.xmlฉันเดาว่าคุณมีประสบการณ์ที่ดีกับเค้าโครงผู้ประสานงานมิฉะนั้นลองดูที่ลิงค์
MiguelHincapieC

ฉันจะดูว่าคุณมีพฤติกรรมแถบเครื่องมืออย่างไรและจะใช้กับฉัน: D อย่างไรก็ตามมีพฤติกรรมเล็กน้อยที่ฉันสามารถเลียนแบบได้ก็ต่อเมื่อฉันใช้ไลบรารีสนับสนุน 23.2: ใน Google Maps หากคุณลากรูปภาพที่อยู่ด้านล่างแถบเครื่องมือมันจะย้ายด้านล่าง แต่ถ้าคุณอัปเกรดเป็น 23.4 หรือ minSdkVersion 14+ คุณจะ สูญเสียพฤติกรรมนี้ o_O '
MiguelHincapieC

@androiddeveloper ฉันเข้าใจแล้ว! ตอนนี้มันทำงานร่วมกับเอฟเฟกต์พารัลแลกซ์รูปภาพและแอนิเมชั่นแถบเครื่องมือ ... ฉันพลาดแค่สีที่ใช้แถบเครื่องมือเมื่อคุณเลื่อนขึ้นไปเรื่อย ๆ : D
MiguelHincapieC

@MiguelHincapieC สวัสดีฉันต้องการแสดงเฉพาะแถบเครื่องมือหลักและฉันลบเลย์เอาต์ของแอพบาร์ที่ผสานออก แต่ในแผ่นงานด้านล่างขยายแถบสถานะเวลาไม่แสดงและรูปภาพพารัลเล็กซ์จะสิ้นสุดที่ตำแหน่งแถบสถานะและฉันต้องการให้ภาพ parallex เหนียวด้านล่างแถบเครื่องมือหลัก คุณช่วยอธิบายได้ไหมว่าฉันทำได้
Vijay Rajput

0

ลองทำดูไหม http://android-developers.blogspot.in/2016/02/android-support-library-232.html?m=1 ในที่นี้จะบอกว่าเราสามารถระบุลักษณะการทำงานของเค้าโครงแผ่นงานด้านล่างได้

อัพเดท:

โดยทั่วไปสถานะการเชื่อมโยง -

ด้วยการแนบ BottomSheetBehavior กับมุมมองลูกของ CoordinatorLayout (เช่นการเพิ่มแอป: layout_behavior = "android.support.design.widget.BottomSheetBehavior") คุณจะได้รับการตรวจจับการสัมผัสที่เหมาะสมโดยอัตโนมัติเพื่อเปลี่ยนระหว่างห้าสถานะ:

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 จะแสดงคลาสไลบรารีการสนับสนุน หากคุณมีวิธีการใช้งานโปรดแสดงที่นี่
นักพัฒนา Android

@androiddeveloper ฉันไม่ได้อ่านวันที่ของคำถามดังนั้นฉันจึงแนะนำคำตอบนี้ แต่ถ้าคุณต้องการใช้ไลบรารีนี้คุณสามารถใช้สิ่งนั้นได้ เท่าที่วิธีแก้ปัญหาการทำงานสำหรับรหัสนี้ฉันไม่มี ขออภัย.
Vaibhav Sharma

0

ฉันต้องใช้มุมมองที่คล้ายกับการที่ Google Maps แสดงแผ่นงานด้านล่างสำหรับผลลัพธ์ที่พบ

นี่คือลักษณะของฉัน:

แอบดู

ขยายมุมมองเลื่อนไปด้านบน

ขยายมุมมองเลื่อนไปด้านล่าง

ในตอนแรกฉันกำหนดแผ่นงานด้านล่างด้วยส่วนหัวและเนื้อหาที่เลื่อนได้ แต่ 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.