Android: Collapsing Linearlayout instead of Collapsing Toolbar

前端 未结 4 688
生来不讨喜
生来不讨喜 2020-12-30 10:52

I\'m trying to create a Master/Detail transaction in a single fragment. I thought of using LinearLayout as the container of my edittext for my header. Then a RecyclerView fo

相关标签:
4条回答
  • 2020-12-30 11:06

    Based on RIP's tutorial, you can collapse or expand views using the snippet below.

    public class ViewAnimationUtils {
            
            public static void expand(final View v) {
                v.measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
                final int targtetHeight = v.getMeasuredHeight();
        
                v.getLayoutParams().height = 0;
                v.setVisibility(View.VISIBLE);
                Animation a = new Animation()
                {
                    @Override
                    protected void applyTransformation(float interpolatedTime, Transformation t) {
                        v.getLayoutParams().height = interpolatedTime == 1
                                ? LayoutParams.WRAP_CONTENT
                                : (int)(targtetHeight * interpolatedTime);
                        v.requestLayout();
                    }
        
                    @Override
                    public boolean willChangeBounds() {
                        return true;
                    }
                };
        
                a.setDuration((int)(targtetHeight / v.getContext().getResources().getDisplayMetrics().density));
                v.startAnimation(a);
            }
        
            public static void collapse(final View v) {
                final int initialHeight = v.getMeasuredHeight();
        
                Animation a = new Animation()
                {
                    @Override
                    protected void applyTransformation(float interpolatedTime, Transformation t) {
                        if(interpolatedTime == 1){
                            v.setVisibility(View.GONE);
                        }else{
                            v.getLayoutParams().height = initialHeight - (int)(initialHeight * interpolatedTime);
                            v.requestLayout();
                        }
                    }
        
                    @Override
                    public boolean willChangeBounds() {
                        return true;
                    }
                };
        
                a.setDuration((int)(initialHeight / v.getContext().getResources().getDisplayMetrics().density));
                v.startAnimation(a);
            }
        }
    

    In addition, to specify the logic being applied to the animated view, in your case, it could be used a ScrollListener like

    private fun RecyclerView.onViewScroll(title: String): OnScrollListener {
        return object : OnScrollListener() {
            override fun onScrollStateChanged(recyclerView: RecyclerView, state: Int) {
                super.onScrollStateChanged(recyclerView, state)
                rootView.findViewById<ConstraintLayout>(R.id.views_menu_header).let { layout ->
                    if(state == SCROLL_STATE_DRAGGING) {                     
                        collapse(layout)
                    }
                }
            }
        }
    }
    

    then attaching the listener to your recycler

    findViewById<RecyclerView>(R.id.views_menu_items).apply { addOnScrollListener(onViewScroll(title)) }
    

    which would collapse R.id.views_menu_header whenever the R.id.views_menu_items starts being dragged.

    0 讨论(0)
  • 2020-12-30 11:12

    try this I added Coordinator and CollapsingToolbarLayput

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.design.widget.CoordinatorLayout 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:fitsSystemWindows="true">
    
    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true">
        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginEnd="64dp"
            app:expandedTitleMarginStart="15dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorAccent"
            android:orientation="vertical"
            android:padding="@dimen/activity_horizontal_margin">
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">
    
                <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:src="@drawable/ic_date_range_black_24dp"
                    android:tint="@android:color/darker_gray" />
    
                <android.support.v4.widget.Space
                    android:layout_width="@dimen/activity_horizontal_margin"
                    android:layout_height="wrap_content" />
    
                <android.support.design.widget.TextInputLayout
                    android:id="@+id/date_til"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:hint="Date">
    
                    <android.support.design.widget.TextInputEditText
                        android:id="@+id/date"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:cursorVisible="false"
                        android:focusable="false"
                        android:longClickable="false" />
    
                </android.support.design.widget.TextInputLayout>
    
            </LinearLayout>
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">
    
                <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@drawable/ic_store_black_24dp"
                    android:layout_gravity="center"
                    android:tint="@android:color/darker_gray" />
    
                <android.support.v4.widget.Space
                    android:layout_width="@dimen/activity_horizontal_margin"
                    android:layout_height="wrap_content" />
    
                <android.support.design.widget.TextInputLayout
                    android:id="@+id/store_til"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:hint="Store">
    
                    <android.support.design.widget.TextInputEditText
                        android:id="@+id/store"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content" />
    
                </android.support.design.widget.TextInputLayout>
    
            </LinearLayout>
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">
    
                <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:src="@drawable/ic_place_black_24dp"
                    android:tint="@android:color/darker_gray" />
    
                <android.support.v4.widget.Space
                    android:layout_width="@dimen/activity_horizontal_margin"
                    android:layout_height="wrap_content" />
    
                <android.support.design.widget.TextInputLayout
                    android:id="@+id/location_til"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">
    
                    <android.support.design.widget.TextInputEditText
                        android:id="@+id/location"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:hint="Location" />
    
                </android.support.design.widget.TextInputLayout>
    
            </LinearLayout>
    
        </LinearLayout>
        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>
    
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recycler"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scrollbars="vertical"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            tools:listitem="@layout/list_car"
            app:layoutManager="LinearLayoutManager" />
    

    I hope this should help you.

    0 讨论(0)
  • 2020-12-30 11:25

    You can use a timer and gradually shrink the height/margin of the topbar's LinearLayout (Edit: flaws in Anton Maiorov's answer is fixed here)

    See below snippet (tested on devices)

    Approach I: Anton Maiorov's answer, flaws fixed, this is much simpler than the 2nd implementation below

    public class MainActivity extends AppCompatActivity {
    
        LinearLayout toolbar;
        int mOriginalHeight;
        boolean initialSizeObtained = false;    
        boolean isShrink = false;
    
        Animation _hideAnimation = new Animation() {
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) {
                LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) toolbar.getLayoutParams();
                params.topMargin = -(int) (mOriginalHeight * interpolatedTime);
                toolbar.setLayoutParams(params);
            }
        };
    
        Animation _showAnimation = new Animation() {
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) {
                LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) toolbar.getLayoutParams();
                params.topMargin = (int) (mOriginalHeight * (interpolatedTime - 1));
                toolbar.setLayoutParams(params);
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            toolbar = (LinearLayout) findViewById(R.id.toolbar);
            //Get the original height, which is measured according to WRAP_CONTENT
            toolbar.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    if (initialSizeObtained)
                        return;
                    initialSizeObtained = true;
                    mOriginalHeight = toolbar.getMeasuredHeight();
                }
            });
            _hideAnimation.setDuration(2000);
            _showAnimation.setDuration(2000);
        }
    
        //Click on the Olimpic image --> Toggles the top toolbar
        public void ToggleTopBar(View view) {
            isShrink = !isShrink;
    
            toolbar.clearAnimation();  //Important            
            toolbar.startAnimation(isShrink? _hideAnimation : _showAnimation);
        }
    }
    

    Approach II: my original answer by changing the toolbar's height, and also using timer manually, which is more involved:

    public class MainActivity extends AppCompatActivity {
    
        LinearLayout toolbar;
        int mOriginalHeight;
        boolean initialSizeObtained = false;
        int currentHeight;
        boolean isShrink = false;
        Timer timer;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            toolbar = (LinearLayout) findViewById(R.id.toolbar);
            toolbar.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    if (initialSizeObtained)
                        return;
                    initialSizeObtained = true;
                    mOriginalHeight = toolbar.getMeasuredHeight();
                    currentHeight = mOriginalHeight;
                    Log.d("Demo", "Original height is " + mOriginalHeight);
                }
            });
        }
    
        //Click on the Olimpic image --> Toggles the top toolbar
        public void ToggleTopBar(View view) {
            isShrink = !isShrink;
            Resize(isShrink, toolbar, 250);
        }
    
    
        void Resize(final boolean isShrink, final LinearLayout layout, final int minHeight) {
            final int H0 = mOriginalHeight;
            timer = runTimerAction(10, new Runnable() {
                        public void run() {
                            Log.d("demo", "Current Height= " + currentHeight);
                            if (isShrink && currentHeight > minHeight) {
                                currentHeight -= 10;
                                layout.getLayoutParams().height = currentHeight;
                                refreshToolbar();
                            } else if (!isShrink && currentHeight < H0) {
                                currentHeight += 10;
                                layout.getLayoutParams().height = currentHeight;
                                refreshToolbar();
                            } else {
                                layout.getLayoutParams().height = isShrink ? minHeight : H0;
                                refreshToolbar();
                                if (timer != null)
                                    timer.cancel();
                            }
                        }
                    }
            );
        }
    
        public void refreshToolbar() {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    toolbar.requestLayout();
                }
            });
        }
    
    0 讨论(0)
  • 2020-12-30 11:27

    Improved my answer using David's comment.

    I would animate "topMargin" of your header:

    LinearLayout _headerLayout; // expected to be set in "onCreateView"
    int _headerHeight; // expected to be set in "onCreateView" as _headerHeight = getHeaderHeight();
    
    Animation _hideAnimation = new Animation() {
      @Override
      protected void applyTransformation(float interpolatedTime, Transformation t) {
        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) _headerLayout.getLayoutParams();
        params.topMargin = -(int) (_headerHeight * interpolatedTime);
        _headerLayout.setLayoutParams(params);
      }
    };
    
    Animation _showAnimation = new Animation() {
      @Override
      protected void applyTransformation(float interpolatedTime, Transformation t) {
        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) _headerLayout.getLayoutParams();
        params.topMargin = (int) (_headerHeight * (interpolatedTime - 1));
        _headerLayout.setLayoutParams(params);
      }
    };
    
    private int getHeaderHeight()
    {
      _headerLayout.measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
      return _headerLayout.getMeasuredHeight();
    }
    

    Hiding header:

    _headerLayout.clearAnimation();
    _headerLayout.startAnimation(_hideAnimation);
    

    Showing header:

    _headerLayout.clearAnimation();
    _headerLayout.startAnimation(_showAnimation);
    

    You can also easily set duration for your animations:

    _hideAnimation.setDuration(2000) // will hide in 2 seconds
    _showAnimation.setDuration(2000) // will show in 2 seconds
    
    0 讨论(0)
提交回复
热议问题