[英]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 的起点(左上角)。 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.