簡體   English   中英

滾動行為 coordinatorLayout 自定義視圖

[英]Scroll behavior coordinatorLayout custom view

在此處輸入圖像描述

我需要這種類型的行為來實現。圖像應該滾動並使用 wtsapp 之類的文本設置到中心。 但在 wtsapp 中,它設置為左側 alignment,我需要設置為中心。 我怎樣才能做到這一點?

在此處輸入圖像描述

滾動后的圖像將在工具欄中顯示類似的文本。(提到)

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

請注意,您應該在布局中放置兩個 ImageView。

  • AppCompatImageView直接在 CoordinatorLayout 里面,這樣我們就可以使用 CoordinatorLayout.Behavior 就可以了,它會是移動的照片。 這里的重要道具是app:onlyVerticalMove="true" ,它可以讓你的動態照片垂直滾動。 我將默認值設置為 false,它會將照片移動到 CoordinatorLayout 的起點(左上角)。
  • 將另一張 ImageView 放入 Appbar 布局中,作為 Appbar 中顯示的最終照片。 使用不可見的 state 初始化它,然后在折疊工具欄折疊時使用 AppBarLayout 行為顯示照片。

如果要從移動元素中排除Toolbar ,只需刪除android:layout_gravity="bottom"

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM