Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
614 views
in Technique[技术] by (71.8m points)

android - NestedScrollView + CoodinatorLayout scrollBy() scrollTo() methods do nothing

I have a NestedScrollView being used with CoordinatorLayout + AppBarLayout + CollapsingToolbarLayout with parallax effect similar to this tutorial

I need to scroll the content programmatically (preferably a smooth scroll, i.e. animated), however calling the scroll methods (scrollBy(), scrollTo(), smoothScrollTo(), smoothScrollBy()) do nothing.

Note that I am using app:layout_behavior="@string/appbar_scrolling_view_behavior" <-- Not sure if the issue is related to this.

I'm calling nsv_form.smoothScrollBy(0, 300) in Kotlin when a button is clicked by the user, but nothing happens :(

(Also tried scrollTo(), scrollBy(), +- 300, all sorts of different variations)

UPDATE: I dug into source code and it seems like the *scroll*() methods expect the content of the layout to be larger than the parent view (makes sense). In my case, the content is smaller, so I suspect that's why the scrolling methods do not work. Perhaps I need something different instead of scroll?

The NestedScrollView's position starts partially off the screen with an image above it in a CollapsingToolbarLayout, like this, so it seems like I need to programmatically move the position of the NestedScrollView AND trigger the CoordinatorLayout's scrolling behavior. -- How do I do this?

Here's my layout:

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/transparent">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:expandedTitleMarginEnd="64dp"
            app:expandedTitleMarginStart="48dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                android:id="@+id/iv_image"
                android:layout_width="match_parent"
                android:layout_height="@dimen/image_height"
                android:scaleType="centerCrop"
                app:layout_collapseMode="parallax"
                tools:src="@drawable/some_image" />

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

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

    <androidx.core.widget.NestedScrollView
        android:id="@+id/nsv_form"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/white"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:animateLayoutChanges="true"
            android:orientation="vertical">

            [... child views...]

        </LinearLayout>

    </androidx.core.widget.NestedScrollView>    
</androidx.coordinatorlayout.widget.CoordinatorLayout>

TLDR: How do I scroll like this programmatically?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

How do I scroll like this programmatically?

For that scrolling behavior you need collapse or expand CollapsingToolbarLayout no need to scroll your the NestedScrollView

Here is the sample code for that

Try this Make some below changes in your Layout

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/rootView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/app_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/transparent"
        android:fitsSystemWindows="true">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:expandedTitleMarginEnd="64dp"
            app:expandedTitleMarginStart="48dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                android:id="@+id/iv_image"
                android:layout_width="match_parent"
                android:layout_height="250dp"
                android:adjustViewBounds="true"
                android:scaleType="fitXY"
                android:src="@drawable/goku"
                app:layout_collapseMode="parallax"
                app:layout_collapseParallaxMultiplier="0.7" />

            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:contentInsetLeft="0dp"
                app:contentInsetStart="0dp"
                app:contentInsetStartWithNavigation="0dp"
                app:titleTextAppearance="@style/AppTheme.Toolbar.Title"
                app:popupTheme="@style/AppTheme.PopupOverlay" />

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

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


    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:background="@color/Boxcolordiabled"
        app:layout_anchor="@id/app_bar"
        app:layout_anchorGravity="bottom|end"
        app:srcCompat="@drawable/ic_favorite" />

    <androidx.core.widget.NestedScrollView
        android:id="@+id/nsv_form"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/holo_blue_light"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:animateLayoutChanges="true"
            android:orientation="vertical">


            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="10dp"
                android:text="@string/demo" />


            <Button
                android:id="@+id/btnColl"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="10dp"
                android:text="Expand " />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="10dp"
                android:text="@string/demo" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="10dp"
                android:text="@string/demo" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="10dp"
                android:text="@string/demo" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="10dp"
                android:text="@string/demo" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="10dp"
                android:text="@string/demo" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="10dp"
                android:text="@string/demo" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="10dp"
                android:text="@string/demo" />


        </LinearLayout>

    </androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

Activity code

import android.animation.ValueAnimator;
import android.os.Bundle;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.widget.Button;
import android.widget.Toast;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import neel.com.bottomappbar.R;

public class MainActivity extends AppCompatActivity {

    Toolbar toolbar;
    AppBarLayout app_bar;
    Button btnColl;
    FloatingActionButton fab;
    CoordinatorLayout rootView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setTitle("Stack Demo");

        app_bar = findViewById(R.id.app_bar);
        btnColl = findViewById(R.id.btnColl);
        fab = findViewById(R.id.fab);
        rootView = findViewById(R.id.rootView);


        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                Toast.makeText(MainActivity.this, "Collapse FAB Clicked", Toast.LENGTH_SHORT).show();

                CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) app_bar.getLayoutParams();
                final AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();

                if (behavior != null) {
                    ValueAnimator valueAnimator = ValueAnimator.ofInt();
                    valueAnimator.setInterpolator(new DecelerateInterpolator());

                    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                        @Override
                        public void onAnimationUpdate(ValueAnimator animation) {
                            behavior.setTopAndBottomOffset((Integer) animation.getAnimatedValue());
                            app_bar.requestLayout();
                        }
                    });

                    valueAnimator.setIntValues(0, -900);
                    valueAnimator.setDuration(1000);
                    valueAnimator.start();
                }
            }
        });

        btnColl.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                Toast.makeText(MainActivity.this, "Expand btnColl Clicked", Toast.LENGTH_SHORT).show();

                CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) app_bar.getLayoutParams();
                final AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
                if (behavior != null) {

                    ValueAnimator valueAnimator = ValueAnimator.ofInt();
                    valueAnimator.setInterpolator(new DecelerateInterpolator());

                    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                        @Override
                        public void onAnimationUpdate(ValueAnimator animation) {
                            behavior.setTopAndBottomOffset((Integer) animation.getAnimatedValue());
                            app_bar.requestLayout();
                        }
                    });

                    valueAnimator.setIntValues(-900, 0);
                    valueAnimator.setDuration(400);
                    valueAnimator.start();
                }


            }
        });
    }


}

OUTPUT

https://www.youtube.com/watch?v=nZY1zPxjRt0


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...