NestedScrollView + CoodinatorLayout scrollBy() scrollTo() 方法什么都不做
NestedScrollView + CoodinatorLayout scrollBy() scrollTo() methods do nothing
我有一个 NestedScrollView 与 CoordinatorLayout + AppBarLayout + CollapsingToolbarLayout 一起使用,视差效果类似于 this tutorial
我需要以编程方式滚动内容(最好是平滑滚动,即动画),但是调用滚动方法(scrollBy()、scrollTo()、smoothScrollTo()、smoothScrollBy())什么都不做。
请注意,我正在使用 app:layout_behavior="@string/appbar_scrolling_view_behavior"
<-- 不确定问题是否与此相关。
当用户单击按钮时,我在 Kotlin 中调用 nsv_form.smoothScrollBy(0, 300)
,但没有任何反应:(
(还尝试了 scrollTo()
、scrollBy()
、+- 300,各种不同的变体)
更新:我深入研究了源代码,似乎 *scroll*()
方法期望布局的内容大于父视图(有道理)。就我而言,内容较小,所以我怀疑这就是滚动方法不起作用的原因。也许我需要一些不同的东西而不是 scroll
?
NestedScrollView 的位置开始部分离开屏幕,在 CollapsingToolbarLayout 中其上方有一个图像,like this,因此我似乎需要以编程方式移动 NestedScrollView 的位置并触发 CoordinatorLayout 的滚动行为。 -- 我该怎么做?
这是我的布局:
<?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:如何以编程方式滚动 like this?
滚动 (scrollBy()
/scrollTo()
/smoothScrollTo()
/smoothScrollBy()
) 需要从 UI thread.
在 Kotlin 中,您可以使用
Handler().post {
nsv_form.scrollBy(0, 300)
}
How do I scroll like this programmatically?
对于滚动行为,您需要折叠或展开 CollapsingToolbarLayout
无需滚动 NestedScrollView
这是示例代码
试试这个 在您的布局中进行以下更改
<?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();
}
}
});
}
}
输出
我有一个 NestedScrollView 与 CoordinatorLayout + AppBarLayout + CollapsingToolbarLayout 一起使用,视差效果类似于 this tutorial
我需要以编程方式滚动内容(最好是平滑滚动,即动画),但是调用滚动方法(scrollBy()、scrollTo()、smoothScrollTo()、smoothScrollBy())什么都不做。
请注意,我正在使用 app:layout_behavior="@string/appbar_scrolling_view_behavior"
<-- 不确定问题是否与此相关。
当用户单击按钮时,我在 Kotlin 中调用 nsv_form.smoothScrollBy(0, 300)
,但没有任何反应:(
(还尝试了 scrollTo()
、scrollBy()
、+- 300,各种不同的变体)
更新:我深入研究了源代码,似乎 *scroll*()
方法期望布局的内容大于父视图(有道理)。就我而言,内容较小,所以我怀疑这就是滚动方法不起作用的原因。也许我需要一些不同的东西而不是 scroll
?
NestedScrollView 的位置开始部分离开屏幕,在 CollapsingToolbarLayout 中其上方有一个图像,like this,因此我似乎需要以编程方式移动 NestedScrollView 的位置并触发 CoordinatorLayout 的滚动行为。 -- 我该怎么做?
这是我的布局:
<?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:如何以编程方式滚动 like this?
滚动 (scrollBy()
/scrollTo()
/smoothScrollTo()
/smoothScrollBy()
) 需要从 UI thread.
在 Kotlin 中,您可以使用
Handler().post {
nsv_form.scrollBy(0, 300)
}
How do I scroll like this programmatically?
对于滚动行为,您需要折叠或展开 CollapsingToolbarLayout
无需滚动 NestedScrollView
这是示例代码
试试这个 在您的布局中进行以下更改
<?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();
}
}
});
}
}
输出