简体   繁体   中英

How to have a view draggable until it becomes full height then make it scrollable?

so I am having a bit of a predicament. I have created an activity which functions like a bottom sheet. One feature that many of my users have asked for is the ability to make it so once the bottom sheet is fully extended, the sheet will then scroll so they can view the rest of the items. I tried putting my linear layout inside of a nestedscrollview but that just caused a crash. Please do not recommend me to use the support bottom sheet class as that does not have everything I need for it to work. Thank you in advance!

Here is the layout for the bottom sheet:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/totalScreen"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_alignTop="@+id/fab"
    android:layout_gravity="bottom|center"
    android:gravity="bottom|center_vertical"
    android:orientation="vertical">

    <TextView
        android:id="@+id/sheetTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#424242"
        android:padding="12dp"
        android:text="Dummy Title"
        android:textSize="18sp" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_alignTop="@+id/sheetTitle"
        android:layout_marginEnd="20dp"
        android:layout_marginTop="-28dp"
        android:visibility="invisible"
        app:fabSize="normal" />

    <LinearLayout
        android:id="@+id/sheetScreen"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/sheetTitle"
        android:background="#424242"
        android:gravity="bottom|center_vertical"
        android:orientation="vertical"
        android:paddingBottom="8dp">

    </LinearLayout>

</RelativeLayout>

Here is the ontouch listener which allows the bottom sheet behavior:

ID: 
protected LinearLayout main;
protected RelativeLayout full;

protected void setAdjustableTouchListener() {
        full.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getActionMasked()) {
                    case MotionEvent.ACTION_DOWN:
                        mDragStartY = event.getY();
                        mPointerOffset = event.getRawY() + main.getMeasuredHeight();
                        return true;
                    case MotionEvent.ACTION_UP:                        DisplayMetrics metrics = new DisplayMetrics();
                        getWindowManager().getDefaultDisplay().getMetrics(metrics);
                        int sheetHeight = (int) (metrics.heightPixels - event.getY());
                        if (mDragStartY < (event.getY() + TAP_DRIFT_TOLERANCE) && mDragStartY > (event.getY() - TAP_DRIFT_TOLERANCE)
                                && ((SystemClock.elapsedRealtime() - mDraggingStarted) < SINGLE_TAP_MAX_TIME)
                                && sheetHeight > (main.getMeasuredHeight() + findViewById(R.id.sheetTitle).getMeasuredHeight())) {
                            result = "Dismissed";
                            finish();
                        } else {
                            if (main.getMeasuredHeight() > (viewConversion + heightDifference)) {
                                ResizeAnimation a = new ResizeAnimation(main);
                                a.setDuration(500);
                                a.setParams(main.getMeasuredHeight(), extendedViewHeight);
                                main.startAnimation(a);
                                state = 2;
                            } else if (main.getMeasuredHeight() < (viewConversion + heightDifference)
                                    && main.getMeasuredHeight() > viewConversion) {
                                ResizeAnimation a = new ResizeAnimation(main);
                                a.setDuration(500);
                                a.setParams(main.getMeasuredHeight(), viewConversion);
                                main.startAnimation(a);
                                state = 1;
                            } else if (main.getMeasuredHeight() < viewConversion && main.getMeasuredHeight() > (viewConversion / 2)) {
                                ResizeAnimation a = new ResizeAnimation(main);
                                a.setDuration(500);
                                a.setParams(main.getMeasuredHeight(), viewConversion);
                                main.startAnimation(a);
                                state = 1;
                            } else if (main.getMeasuredHeight() < (viewConversion / 2)) {
                                result = "Dismissed";
                                finish();
                            }
                        }
                        return true;
                    case MotionEvent.ACTION_MOVE:
                        if (mPointerOffset - event.getRawY() < extendedViewHeight)
                            setPrimaryContentHeight((int) (mPointerOffset - event.getRawY()));
                        return true;
                    default:
                        return true;
                }
            }
        });
    }

Here is the method to actually set the new height of the sheet:

protected boolean setPrimaryContentHeight(int newHeight) {
    // the new primary content height should not be less than 0 to make the
    // handler always visible
    newHeight = Math.max(0, newHeight);
    // the new primary content height should not be more than the SplitView
    // height minus handler height to make the handler always visible
    RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) main.getLayoutParams();
    if (newHeight >= 0) {
        params.height = newHeight;
        // set the primary content parameter to do not stretch anymore and
        // use the height specified in the layout params
    }
    main.setLayoutParams(params);
    return true;
}

Here is the crash that occurs when using the NestedScrollView:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.nick.mowen.sceneplugin/com.nick.mowen.sceneplugin.ui.BottomSheetActivity}: android.view.InflateException: Binary XML file line #32: Binary XML file line #32: Error inflating class android.support.v4.widget.NestedScrollView
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2450)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2520)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1363)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5466)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: android.view.InflateException: Binary XML file line #32: Binary XML file line #32: Error inflating class android.support.v4.widget.NestedScrollView
at android.view.LayoutInflater.inflate(LayoutInflater.java:539)
at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
at android.view.LayoutInflater.inflate(LayoutInflater.java:374)
at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:267)
at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:129)
at com.nick.mowen.sceneplugin.ui.BottomSheetActivity.onCreate(BottomSheetActivity.java:37)
at android.app.Activity.performCreate(Activity.java:6251)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1108)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2403)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2520) 
at android.app.ActivityThread.-wrap11(ActivityThread.java) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1363) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:148) 
at android.app.ActivityThread.main(ActivityThread.java:5466) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 
Caused by: android.view.InflateException: Binary XML file line #32: Error inflating class android.support.v4.widget.NestedScrollView
at android.view.LayoutInflater.createView(LayoutInflater.java:645)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:764)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:835)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:798)
at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
at android.view.LayoutInflater.inflate(LayoutInflater.java:423) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:374) 
at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:267) 
at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:129) 
at com.nick.mowen.sceneplugin.ui.BottomSheetActivity.onCreate(BottomSheetActivity.java:37) 
at android.app.Activity.performCreate(Activity.java:6251) 
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1108) 
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2403) 
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2520) 
at android.app.ActivityThread.-wrap11(ActivityThread.java) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1363) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:148) 
at android.app.ActivityThread.main(ActivityThread.java:5466) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.newInstance(Native Method)
at android.view.LayoutInflater.createView(LayoutInflater.java:619)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:764) 
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704) 
at android.view.LayoutInflater.rInflate(LayoutInflater.java:835) 
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:798) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:515) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:423) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:374) 
at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:267) 
at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:129) 
at com.nick.mowen.sceneplugin.ui.BottomSheetActivity.onCreate(BottomSheetActivity.java:37) 
at android.app.Activity.performCreate(Activity.java:6251) 
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1108) 
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2403) 
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2520) 
at android.app.ActivityThread.-wrap11(ActivityThread.java) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1363) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:148) 
at android.app.ActivityThread.main(ActivityThread.java:5466) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v4.view.NestedScrollingChildHelper.setNestedScrollingEnabled(boolean)' on a null object reference
at android.support.v4.widget.NestedScrollView.setNestedScrollingEnabled(NestedScrollView.java:212)
at android.view.View.<init>(View.java:4256)
at android.view.ViewGroup.<init>(ViewGroup.java:573)
at android.widget.FrameLayout.<init>(FrameLayout.java:97)
at android.widget.FrameLayout.<init>(FrameLayout.java:92)
at android.support.v4.widget.NestedScrollView.<init>(NestedScrollView.java:189)
at android.support.v4.widget.NestedScrollView.<init>(NestedScrollView.java:185)
at java.lang.reflect.Constructor.newInstance(Native Method) 
at android.view.LayoutInflater.createView(LayoutInflater.java:619) 
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:764) 
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704) 
at android.view.LayoutInflater.rInflate(LayoutInflater.java:835) 
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:798) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:515) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:423) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:374) 
at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:267) 
at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:129) 
at com.nick.mowen.sceneplugin.ui.BottomSheetActivity.onCreate(BottomSheetActivity.java:37) 
at android.app.Activity.performCreate(Activity.java:6251) 
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1108) 
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2403) 
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2520) 
at android.app.ActivityThread.-wrap11(ActivityThread.java) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1363) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:148) 
at android.app.ActivityThread.main(ActivityThread.java:5466) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 

Ok, solved this, what I ended up doing was just adding a recyclerview in place of the linearlayout. Then I just made the LayoutManager overridden so it is only scrollable when I set it to be:

main.setLayoutManager(new LinearLayoutManager(this) {
            @Override
            public boolean canScrollVertically() {
                return canScroll && super.canScrollVertically();
            }
        });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM