MotionLayout之Carousel
xml
<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
java
/**
* 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就是
makefile
view1: 0
view2: 1
view3: 2
view4: 0
view5: 1
关于index的计算公式在Carousel中也有。
java
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文件,
xml<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>