【问题标题】:Android: Collapsing Linearlayout instead of Collapsing ToolbarAndroid:折叠线性布局而不是折叠工具栏
【发布时间】:2016-08-25 05:17:47
【问题描述】:

我正在尝试在单个片段中创建主/明细事务。我想使用 LinearLayout 作为我的标题的编辑文本的容器。然后是 RecyclerView 了解详情。

如何实现类似于 CollapsingToolbar 效果的 LinearLayout 的折叠/展开?

这是我正在尝试做的截图。

到目前为止我的 xml 代码。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:background="@color/colorAccent"
        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:layout_gravity="center"
                android:src="@drawable/ic_store_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/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.v7.widget.RecyclerView
        android:id="@+id/recycler"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical"
        app:layoutManager="LinearLayoutManager"
        tools:listitem="@layout/list_car" />

</LinearLayout>

另外,不确定这是否可以使用 CollapsingToolbar 完成,因为我大多只看到 Toolbar 中的 ImageView 折叠。

感谢任何帮助。

更新:基本上我在这里想要做的是能够在向上滚动时折叠标题视图。然后向下滚动时展开。

【问题讨论】:

  • 在此处更新您的 xml 文件

标签: android android-collapsingtoolbarlayout


【解决方案1】:

您可以使用计时器并逐渐缩小顶部栏的 LinearLayout 的高度/边距(编辑:Anton Maiorov 的回答中的缺陷已在此处修复)

参见下面的 sn-p(在设备上测试)

方法一:Anton Maiorov 的回答,修复了缺陷,这比下面的第二个实现简单得多

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);
    }
}

方法二:我原来的答案是通过改变工具栏的高度,也手动使用计时器,这更复杂:

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();
            }
        });
    }

【讨论】:

  • 滚动时如何调用这些动画?
  • 方法1我能理解,但是点击它看起来像动画一样,向上滚动时可以展开,向下滚动时可以折叠吗?
【解决方案2】:

使用大卫的评论改进了我的回答。

我会为您的标题的“topMargin”设置动画:

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();
}

隐藏标题:

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

显示标题:

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

您还可以轻松设置动画的持续时间:

_hideAnimation.setDuration(2000) // will hide in 2 seconds
_showAnimation.setDuration(2000) // will show in 2 seconds

【讨论】:

  • 很好的答案,虽然有一些缺陷。 (1) 切换动画前需要清除动画; (2) params.height 始终为 -2,因为使用了 WRAP_CONTENT。我在回答中修复了这两个问题。无论如何,点赞!
  • @David 关于身高,你是对的,谢谢。但是我之前使用 startAnimation 没有 clearAnimation 很好,你认为这是一个错误吗?
  • 我刚试了一下,不清除动画,直接切换到另一个动画是没有效果的。没有理由,:)
  • @David 好的,我同意。使用“clearAnimation”更安全 =)
【解决方案3】:

试试这个我添加了 Coordinator 和 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" />

希望对你有所帮助。

【讨论】:

    【解决方案4】:

    基于RIP's tutorial,您可以使用下面的sn-p折叠或展开视图。

    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);
            }
        }
    

    此外,要指定应用于动画视图的逻辑,在您的情况下,可以使用 ScrollListener 之类的

    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)
                    }
                }
            }
        }
    }
    

    然后,将侦听器附加到您的回收器

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

    只要R.id.views_menu_items 开始被拖动,R.id.views_menu_header 就会折叠。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-14
      相关资源
      最近更新 更多