【Android】MotionLayout Carousel
作者:访客发布时间:2023-12-27分类:程序开发学习浏览:89
导读:MotionLayout之Carousel<androidx.constraintlayout.helper.widget.Carouselandroid:lay...
MotionLayout之Carousel
<androidx.constraintlayout.helper.widget.Carousel
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/Carousel"
app:carousel_previousState="@id/previous"
app:carousel_forwardTransition="@id/forward"
app:carousel_nextState="@id/next"
app:carousel_backwardTransition="@id/backward"
app:carousel_firstView="@id/view2"
app:carousel_infinite="true"
app:constraint_referenced_ids="view1,view2,view3,view4,view5"
>
</androidx.constraintlayout.helper.widget.Carousel>
我们假设:向上滑动是显示后一个,向下滑动是显示前一个
- previousState:当向下滑动要显示前一个时,且滑动完毕后的状态
- nextState:当向上滑动要显示后一个时,且滑动完毕后的状态
- forwardTransition:当向下滑动要显示前一个时,这个过程的动画效果
- backwardTransition:当向上滑动要显示后一个时,这个过程的动画效果
- firstView:表示当index=0时,指的是哪一个view。
- constraint_referenced_ids:这个顺序也不能乱写,这个例子的意思是:view1是作为view2的前一个view,view1的index值就是4,因为我们使用adapter设置的count数是5,也就是0-4,又因为是循环显示:所以值无法是-1,只能是4,以此类推,view3的index是1,view4的index是2,view5的index是3.
adapter
/**
* Adapter for a Carousel
*/
public interface Adapter {
/**
* Number of items you want to display in the Carousel
* @return number of items
*/
int count();
/**
* Callback to populate the view for the given index
*
* @param view
* @param index
*/
void populate(View view, int index);
/**
* Callback when we reach a new index
* @param index
*/
void onNewItem(int index);
}
这里的count返回值表示,我们view的index的最大值就是count-1,我觉得这里的显示的数量表示不准确,不如说:一个显示周期的item个数。因为这个值无法控制显示的个数。
比如我们有5个view:view1,view2,view3,view4,view5
count返回值: 3
firstView: view1
那么对应的index就是
view1: 0
view2: 1
view3: 2
view4: 0
view5: 1
关于index的计算公式在Carousel中也有。
private void updateItems() {
final int viewCount = mList.size();
for (int i = 0; i < viewCount; i++) {
View view = mList.get(i);
//mIndex表示当前显示的index,这个index是按实际显示的位置来的,默认不滑动时,mIndex就等于0
int index = mIndex + i - mStartIndex;//当view5时:index = 0+4-0 = 4
if (mInfiniteCarousel) {
if (index < 0) {
if (mEmptyViewBehavior != View.INVISIBLE) {
updateViewVisibility(view, mEmptyViewBehavior);
} else {
updateViewVisibility(view, VISIBLE);
}
if (index % mAdapter.count() == 0) {
mAdapter.populate(view, 0);
} else {
mAdapter.populate(view, mAdapter.count() + (index % mAdapter.count()));
}
} else if (index >= mAdapter.count()) {//大于count了,
if (index == mAdapter.count()) {
index = 0;//重回0
} else if (index > mAdapter.count()) {//index=4,
index = index % mAdapter.count();//index = 4%3=1
}
if (mEmptyViewBehavior != View.INVISIBLE) {
updateViewVisibility(view, mEmptyViewBehavior);
} else {
updateViewVisibility(view, VISIBLE);
}
mAdapter.populate(view, index);
} else {
updateViewVisibility(view, VISIBLE);
mAdapter.populate(view, index);
}
}
}
}
populate表示:从index 0到4之间,移动到目标位置后index 0-4都会执行一次populate,因为view在parent的位置没有改变,我们改变的只是index的值,所以对于同一个view,他的index值已经改变,我们需要确定下,在当前位置该view需要再设置成什么样式。当这些操作完成后会再执行一次onNewItem表示我们当前的这一个操作已经完成。
也就是说我们向前滑动完成后,view1的状态需要更新成上一次view5的状态了。
切记 view在父view中的位置没有改变,变得只是对应的index值,比如这里的firstView值是view3,他的初始index是0,当完成一次向上移动时,他的index就变成1了。
附上我自己的scene文件,
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Transition
android:id="@+id/forward"
app:constraintSetEnd="@+id/next"
app:constraintSetStart="@+id/start">
<OnSwipe app:dragDirection="dragUp" />
<KeyFrameSet>
<KeyPosition
app:framePosition="50"
app:keyPositionType="parentRelative"
app:motionTarget="@id/view3"
app:percentY="0.1">
</KeyPosition>
</KeyFrameSet>
</Transition>
<Transition
android:id="@+id/backward"
app:constraintSetEnd="@+id/previous"
app:constraintSetStart="@+id/start">
<OnSwipe app:dragDirection="dragDown" />
<KeyFrameSet>
<KeyPosition
app:framePosition="50"
app:keyPositionType="parentRelative"
app:motionTarget="@id/view3"
app:percentY="0.9">
</KeyPosition>
</KeyFrameSet>
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@id/view1"
android:layout_width="100dp"
android:layout_height="300dp"
android:rotation="-30"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
</Constraint>
<Constraint
android:id="@id/view2"
android:layout_width="100dp"
android:layout_height="300dp"
android:rotation="-15"
android:translationZ="2dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
</Constraint>
<Constraint
android:id="@id/view3"
android:layout_width="100dp"
android:layout_height="300dp"
android:rotation="0"
android:translationZ="4dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
</Constraint>
<Constraint
android:id="@id/view4"
android:layout_width="100dp"
android:layout_height="300dp"
android:rotation="15"
android:translationZ="2dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
</Constraint>
<Constraint
android:id="@id/view5"
android:layout_width="100dp"
android:layout_height="300dp"
android:rotation="30"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/previous">
<Constraint
android:id="@id/view1"
android:layout_width="100dp"
android:layout_height="300dp"
android:rotation="-15"
android:translationZ="2dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
</Constraint>
<Constraint
android:id="@id/view2"
android:layout_width="100dp"
android:layout_height="300dp"
android:rotation="0"
android:translationZ="4dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
</Constraint>
<Constraint
android:id="@id/view3"
android:layout_width="100dp"
android:layout_height="300dp"
android:rotation="15"
android:translationZ="2dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
</Constraint>
<Constraint
android:id="@id/view4"
android:layout_width="100dp"
android:layout_height="300dp"
android:rotation="30"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
</Constraint>
<Constraint
android:id="@id/view5"
android:layout_width="100dp"
android:layout_height="300dp"
android:rotation="-30"
android:translationZ="-2dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/next">
<Constraint
android:id="@id/view1"
android:layout_width="100dp"
android:layout_height="300dp"
android:rotation="30"
android:translationZ="-2dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
</Constraint>
<Constraint
android:id="@id/view2"
android:layout_width="100dp"
android:layout_height="300dp"
android:rotation="-30"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
</Constraint>
<Constraint
android:id="@id/view3"
android:layout_width="100dp"
android:layout_height="300dp"
android:rotation="-15"
android:translationZ="2dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
</Constraint>
<Constraint
android:id="@id/view4"
android:layout_width="100dp"
android:layout_height="300dp"
android:rotation="0"
android:translationZ="4dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
</Constraint>
<Constraint
android:id="@id/view5"
android:layout_width="100dp"
android:layout_height="300dp"
android:rotation="15"
android:translationZ="2dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
</Constraint>
</ConstraintSet>
</MotionScene>
相关推荐
- WPMozo Product Carriage for WooCommerce最好的WordPress常用插件下载博客插件模块
- 轻松上手:
(三)笔记可再编辑 - 如何在iPhone,iPad和Android上使用WordPress应用程序
- 一款简单高效的Android异步框架
- [Android][NDK][Cmake]一文搞懂Android项目中的Cmake
- Android---View中的setMinWidth与setMinimumWidth的踩坑记录
- Android广播如何解决Sending non-protected broadcast问题
- 有关Android Binder面试,你未知的9个秘密
- 开启Android学习之旅-2-架构组件实现数据列表及添加(kotlin)
- Android低功耗蓝牙开发总结
- 程序开发学习排行
-
- 1鸿蒙HarmonyOS:Web组件网页白屏检测
- 2HTTPS协议是安全传输,为啥还要再加密?
- 3HarmonyOS鸿蒙应用开发——数据持久化Preferences
- 4记解决MaterialButton背景颜色与设置值不同
- 5鸿蒙HarmonyOS实战-ArkUI组件(RelativeContainer)
- 6鸿蒙HarmonyOS实战-ArkUI组件(Stack)
- 7[Android][NDK][Cmake]一文搞懂Android项目中的Cmake
- 8Android广播如何解决Sending non-protected broadcast问题
- 9鸿蒙HarmonyOS实战-ArkUI组件(mediaquery)
- 最近发表
-
- WooCommerce最好的WordPress常用插件下载博客插件模块的相关产品
- 羊驼机器人最好的WordPress常用插件下载博客插件模块
- IP信息记录器最好的WordPress常用插件下载博客插件模块
- Linkly for WooCommerce最好的WordPress常用插件下载博客插件模块
- 元素聚合器Forms最好的WordPress常用插件下载博客插件模块
- Promaker Chat 最好的WordPress通用插件下载 博客插件模块
- 自动更新发布日期最好的WordPress常用插件下载博客插件模块
- WordPress官方最好的获取回复WordPress常用插件下载博客插件模块
- Img to rss最好的wordpress常用插件下载博客插件模块
- WPMozo为Elementor最好的WordPress常用插件下载博客插件模块添加精简版