简体   繁体   中英

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. but in wtsapp it set into left alignment, i need to set into center. how can i achieve this?

在此处输入图像描述

after scrolled image will show like that with text in toolbar.(mentioned)

1. Behavior for CoordinatorLayout and 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

    <?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.

  • AppCompatImageView directly inside the CoordinatorLayout so that we can use CoordinatorLayout.Behavior on it, it would be the moving photo. The important prop here is app:onlyVerticalMove="true" , that make your moving photo scrolled vertically. I made the default value to false, it will move the photo to the start point of CoordinatorLayout (top left).
  • Put another ImageView inside the Appbar layout as the final photo displayed in the Appbar. Init this with invisible state, then use AppBarLayout behavior to show the photo when the collapsing toolbar is being collapsed.

If you want to exclude Toolbar from moving elements, just remove android:layout_gravity="bottom"

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