简体   繁体   English

滚动行为 coordinatorLayout 自定义视图

[英]Scroll behavior coordinatorLayout custom view

在此处输入图像描述

I need this type of behavior to implement.Image should be scroll and set into center with text like wtsapp.我需要这种类型的行为来实现。图像应该滚动并使用 wtsapp 之类的文本设置到中心。 but in wtsapp it set into left alignment, i need to set into center.但在 wtsapp 中,它设置为左侧 alignment,我需要设置为中心。 how can i achieve this?我怎样才能做到这一点?

在此处输入图像描述

after scrolled image will show like that with text in toolbar.(mentioned)滚动后的图像将在工具栏中显示类似的文本。(提到)

1. Behavior for CoordinatorLayout and AppBarLayout 1. CoordinatorLayout 和 AppBarLayout 的行为

    public class AvatarImageBehavior extends CoordinatorLayout.Behavior<ImageView> {

        // calculated from given layout
        private int startXPositionImage;
        private int startYPositionImage;
        private int startHeight;
        private int startToolbarHeight;

        private boolean initialised = false;

        private float amountOfToolbarToMove;
        private float amountOfImageToReduce;
        private float amountToMoveXPosition;
        private float amountToMoveYPosition;

        // user configured params
        private float finalToolbarHeight, finalXPosition, finalYPosition, finalHeight;
        private boolean onlyVerticalMove;

        public AvatarImageBehavior(
                final Context context,
                final AttributeSet attrs) {

            if (attrs != null) {
                TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AvatarImageBehavior);
                finalXPosition = a.getDimension(R.styleable.AvatarImageBehavior_finalXPosition, 0);
                finalYPosition = a.getDimension(R.styleable.AvatarImageBehavior_finalYPosition, 0);
                finalHeight = a.getDimension(R.styleable.AvatarImageBehavior_finalHeight, 0);
                finalToolbarHeight = a.getDimension(R.styleable.AvatarImageBehavior_finalToolbarHeight, 0);
                onlyVerticalMove = a.getBoolean(R.styleable.AvatarImageBehavior_onlyVerticalMove, false);
                a.recycle();
            }
        }

        @Override
        public boolean layoutDependsOn(@NotNull final CoordinatorLayout parent, @NotNull final ImageView child, @NotNull final View dependency) {
            return dependency instanceof AppBarLayout; // change if you want another sibling to depend on
        }

        @Override
        public boolean onDependentViewChanged(@NotNull final CoordinatorLayout parent, @NotNull final ImageView child, @NotNull final View dependency) {

            // make child (avatar) change in relation to dependency (toolbar) in both size and position, init with properties from layout
            initProperties(child, dependency);

            // calculate progress of movement of dependency
            float currentToolbarHeight = startToolbarHeight + dependency.getY(); // current expanded height of toolbar
            // don't go below configured min height for calculations (it does go passed the toolbar)
            currentToolbarHeight = Math.max(currentToolbarHeight, finalToolbarHeight);
            final float amountAlreadyMoved = startToolbarHeight - currentToolbarHeight;
            final float progress = 100 * amountAlreadyMoved / amountOfToolbarToMove; // how much % of expand we reached

            // update image size
            final float heightToSubtract = progress * amountOfImageToReduce / 100;
            CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
            lp.width = (int) (startHeight - heightToSubtract);
            lp.height = (int) (startHeight - heightToSubtract);
            child.setLayoutParams(lp);

            // update image position
            final float distanceXToSubtract = progress * amountToMoveXPosition / 100;
            final float distanceYToSubtract = progress * amountToMoveYPosition / 100;
            float newXPosition = startXPositionImage - distanceXToSubtract;
            //newXPosition = newXPosition < endXPosition ? endXPosition : newXPosition; // don't go passed end position
            if (!onlyVerticalMove) {
                child.setX(newXPosition);
            }
            child.setY(startYPositionImage - distanceYToSubtract);

            return true;
        }

        private void initProperties(
                final ImageView child,
                final View dependency) {

            if (!initialised) {
                // form initial layout
                startHeight = child.getHeight();
                startXPositionImage = (int) child.getX();
                startYPositionImage = (int) child.getY();
                startToolbarHeight = dependency.getHeight();
                // some calculated fields
                amountOfToolbarToMove = startToolbarHeight - finalToolbarHeight;
                amountOfImageToReduce = startHeight - finalHeight;
                amountToMoveXPosition = startXPositionImage - finalXPosition;
                amountToMoveYPosition = startYPositionImage - finalYPosition;
                initialised = true;
            }
        }
    }

```java
    public class AppBarScrollWatcher implements AppBarLayout.OnOffsetChangedListener {
        private int scrollRange = -1;
        private OffsetListener listener;

        public AppBarScrollWatcher(OffsetListener listener) {
            this.listener = listener;
        }

        @Override
        public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
            if (scrollRange == -1) {
                scrollRange = appBarLayout.getTotalScrollRange();
            }

            int appbarHeight = scrollRange + verticalOffset;
            float alpha = (float) appbarHeight / scrollRange;
            if (alpha < 0) {
                alpha = 0;
            }
            float alphaZeroOnCollapsed = shrinkAlpha(alpha);
            float alphaZeroOnExpanded = Math.abs(alphaZeroOnCollapsed - 1);
            int argbZeroOnExpanded = (int) Math.abs((alphaZeroOnCollapsed * 255) - 255);
            int argbZeroOnCollapsed = (int) Math.abs(alphaZeroOnCollapsed * 255);

            listener.onAppBarExpanding(alphaZeroOnExpanded <= 0, alphaZeroOnCollapsed <= 0, argbZeroOnExpanded, argbZeroOnCollapsed, alphaZeroOnCollapsed, alphaZeroOnExpanded);
        }

        private float shrinkAlpha(float alpha) {
            NumberFormat formatter = NumberFormat.getInstance(Locale.getDefault());
            formatter.setMaximumFractionDigits(2);
            formatter.setMinimumFractionDigits(2);
            formatter.setRoundingMode(RoundingMode.HALF_DOWN);
            return Float.parseFloat(formatter.format(alpha));
        }

        public interface OffsetListener {
            void onAppBarExpanding(boolean expanded, boolean collapsed, int argbZeroOnExpanded, int argbZeroOnCollapsed, float alphaZeroOnCollapsed, float alphaZeroOnExpanded);
        }
    }
res/values/attrs.xml
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="AvatarImageBehavior">
            <attr name="finalXPosition" format="dimension" />
            <attr name="finalYPosition" format="dimension" />
            <attr name="finalHeight" format="dimension" />
            <attr name="finalToolbarHeight" format="dimension" />
            <attr name="onlyVerticalMove" format="boolean" />
        </declare-styleable>
    </resources>

2. Implementation in Activity/Fragment 2. Activity/Fragment中的实现

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/root"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center">

        <com.google.android.material.appbar.AppBarLayout
            android:id="@+id/app_bar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

            <com.google.android.material.appbar.CollapsingToolbarLayout
                android:id="@+id/toolbar_layout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:contentScrim="@color/colorPrimary"
                app:layout_scrollFlags="scroll|exitUntilCollapsed"
                app:titleEnabled="false">

                <LinearLayout
                    android:id="@+id/header_container"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:background="@android:color/holo_orange_light"
                    android:gravity="center_horizontal"
                    android:orientation="vertical"
                    android:paddingStart="24dp"
                    android:paddingTop="160dp"
                    android:paddingEnd="24dp"
                    android:paddingBottom="56dp">

                </LinearLayout>

                <androidx.appcompat.widget.Toolbar
                    android:id="@+id/toolbar"
                    android:layout_width="match_parent"
                    android:layout_height="?android:attr/actionBarSize"
                    android:layout_gravity="bottom"
                    app:contentInsetStart="0dp"
                    app:layout_collapseMode="pin"
                    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                    app:titleMarginStart="0dp">

                    <androidx.constraintlayout.widget.ConstraintLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:gravity="center_vertical">

                        <ImageView
                            android:id="@+id/still_photo"
                            android:layout_width="48dp"
                            android:layout_height="48dp"
                            android:layout_gravity="center"
                            android:contentDescription="@string/app_name"
                            android:scaleType="fitCenter"
                            android:visibility="invisible"
                            app:layout_constraintBottom_toBottomOf="parent"
                            app:layout_constraintEnd_toEndOf="parent"
                            app:layout_constraintStart_toStartOf="parent"
                            app:layout_constraintTop_toTopOf="parent"
                            app:srcCompat="@drawable/ic_ph_person_male_80dp" />

                        <ImageView
                            android:id="@+id/ic_more"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:alpha="0.7"
                            android:clickable="true"
                            android:contentDescription="@string/app_name"
                            android:focusable="true"
                            android:padding="8dp"
                            android:tint="@android:color/white"
                            app:layout_constraintBottom_toBottomOf="parent"
                            app:layout_constraintEnd_toEndOf="parent"
                            app:layout_constraintTop_toTopOf="parent"
                            app:srcCompat="@drawable/ic_more_vert_black_24dp" />
                    </androidx.constraintlayout.widget.ConstraintLayout>

                </androidx.appcompat.widget.Toolbar>

            </com.google.android.material.appbar.CollapsingToolbarLayout>

        </com.google.android.material.appbar.AppBarLayout>

        <androidx.core.widget.NestedScrollView
            android:id="@+id/v_sections"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:behavior_overlapTop="24dp"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

            <androidx.cardview.widget.CardView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_margin="16dp">

                <View
                    android:layout_width="match_parent"
                    android:layout_height="1000dp" />
            </androidx.cardview.widget.CardView>
        </androidx.core.widget.NestedScrollView>

        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/moving_photo"
            android:layout_width="120dp"
            android:layout_height="120dp"
            android:layout_gravity="top|center_horizontal"
            android:layout_marginTop="64dp"
            android:contentDescription="@string/app_name"
            android:scaleType="fitCenter"
            app:finalHeight="48dp"
            app:finalToolbarHeight="?android:attr/actionBarSize"
            app:finalYPosition="4dp"
            app:layout_behavior=".custom.AvatarImageBehavior"
            app:onlyVerticalMove="true"
            app:srcCompat="@drawable/ic_ph_person_male_80dp" />

    </androidx.coordinatorlayout.widget.CoordinatorLayout>
    private lateinit var appBarScrollListener: AppBarScrollWatcher

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_launcher)
            setupAppBar()
        }

        private fun setupAppBar() {
            appBarScrollListener =
                AppBarScrollWatcher(AppBarScrollWatcher.OffsetListener { _, collapsed, _, _, _, _ ->
                    still_photo.visibility = if (collapsed) View.VISIBLE else View.INVISIBLE
                })
            app_bar.addOnOffsetChangedListener(appBarScrollListener)
        }

        override fun onDestroy() {
            app_bar.removeOnOffsetChangedListener(appBarScrollListener)
            super.onDestroy()
        }

Note that you should put two ImageView in the layout.请注意,您应该在布局中放置两个 ImageView。

  • AppCompatImageView directly inside the CoordinatorLayout so that we can use CoordinatorLayout.Behavior on it, it would be the moving photo. AppCompatImageView直接在 CoordinatorLayout 里面,这样我们就可以使用 CoordinatorLayout.Behavior 就可以了,它会是移动的照片。 The important prop here is app:onlyVerticalMove="true" , that make your moving photo scrolled vertically.这里的重要道具是app:onlyVerticalMove="true" ,它可以让你的动态照片垂直滚动。 I made the default value to false, it will move the photo to the start point of CoordinatorLayout (top left).我将默认值设置为 false,它会将照片移动到 CoordinatorLayout 的起点(左上角)。
  • Put another ImageView inside the Appbar layout as the final photo displayed in the Appbar.将另一张 ImageView 放入 Appbar 布局中,作为 Appbar 中显示的最终照片。 Init this with invisible state, then use AppBarLayout behavior to show the photo when the collapsing toolbar is being collapsed.使用不可见的 state 初始化它,然后在折叠工具栏折叠时使用 AppBarLayout 行为显示照片。

If you want to exclude Toolbar from moving elements, just remove android:layout_gravity="bottom"如果要从移动元素中排除Toolbar ,只需删除android:layout_gravity="bottom"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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