效果
MotionScene
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ConstraintSet
android:id="@+id/start">
<Constraint
android:id="@+id/music_control_background"
>
<Layout
android:layout_width="match_parent"
android:layout_height="50dp"
app:layout_constraintBottom_toTopOf="@id/bottom_navi"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
/>
</Constraint>
<Constraint
android:id="@+id/profile_photo"
>
<Layout
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="20dp"
app:layout_constraintBottom_toBottomOf="@+id/music_control_background"
app:layout_constraintStart_toStartOf="@id/music_control_background"
app:layout_constraintTop_toTopOf="@id/music_control_background"
/>
</Constraint>
<Constraint
android:id="@+id/music_button"
>
<PropertySet android:visibility="visible"/>
</Constraint>
<Constraint
android:id="@+id/music_progress"
>
<Layout
android:layout_width="400dp"
android:layout_height="20dp"
app:layout_constraintTop_toBottomOf="@+id/profile_photo"
app:layout_constraintStart_toStartOf="@id/music_control_background"
app:layout_constraintEnd_toEndOf="@id/music_control_background"
android:layout_marginTop="50dp"
/>
<PropertySet
android:visibility="gone"
/>
</Constraint>
<Constraint
android:id="@+id/close_button"
>
<Layout
android:layout_width="80dp"
android:layout_height="10dp"
app:layout_constraintStart_toStartOf="@id/music_control_background"
app:layout_constraintEnd_toEndOf="@id/music_control_background"
app:layout_constraintTop_toTopOf="@id/music_control_background"
android:layout_marginTop="15dp"
/>
<PropertySet
android:visibility="gone"
/>
</Constraint>
</ConstraintSet>
<ConstraintSet
android:id="@+id/end">
<Constraint
android:id="@+id/music_control_background"
>
<Layout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
</Constraint>
<Constraint
android:id="@+id/profile_photo"
>
<Layout
android:layout_width="200dp"
android:layout_height="200dp"
app:layout_constraintEnd_toEndOf="@id/music_control_background"
app:layout_constraintStart_toStartOf="@id/music_control_background"
app:layout_constraintTop_toTopOf="@id/music_control_background"
android:layout_marginTop="120dp"
/>
</Constraint>
<Constraint
android:id="@+id/music_button"
>
<PropertySet
android:visibility="gone"
/>
</Constraint>
<Constraint
android:id="@+id/music_progress"
>
<Layout
android:layout_width="400dp"
android:layout_height="20dp"
app:layout_constraintTop_toBottomOf="@+id/profile_photo"
app:layout_constraintStart_toStartOf="@id/music_control_background"
app:layout_constraintEnd_toEndOf="@id/music_control_background"
android:layout_marginTop="50dp"
/>
<PropertySet
android:visibility="visible"
/>
</Constraint>
<Constraint
android:id="@+id/close_button"
>
<Layout
android:layout_width="80dp"
android:layout_height="10dp"
app:layout_constraintStart_toStartOf="@id/music_control_background"
app:layout_constraintEnd_toEndOf="@id/music_control_background"
app:layout_constraintTop_toTopOf="@id/music_control_background"
android:layout_marginTop="15dp"
/>
<PropertySet
android:visibility="visible"
/>
</Constraint>
</ConstraintSet>
<Transition
app:constraintSetStart="@+id/start"
app:constraintSetEnd="@+id/end"
>
<OnSwipe
app:touchAnchorId="@+id/profile_photo"
app:dragDirection="dragUp"
app:moveWhenScrollAtTop="true"
app:nestedScrollFlags="disableScroll"
app:maxAcceleration="1.5"
app:maxVelocity="4"
/>
<OnClick
app:targetId="@+id/close_button"
app:clickAction="toggle"
/>
<KeyFrameSet>
<KeyAttribute
app:motionTarget="@+id/music_button"
app:framePosition="20"
android:alpha="0"
>
</KeyAttribute>
<KeyPosition
app:motionTarget="@+id/profile_photo"
app:keyPositionType="deltaRelative"
app:framePosition="20"
app:sizePercent="1"
app:percentX="1"
app:percentY="0.2"
/>
<KeyPosition
app:motionTarget="@+id/music_control_background"
app:keyPositionType="pathRelative"
app:framePosition="30"
app:percentHeight="0.5"
app:percentX="0.5"/>
<KeyPosition
app:motionTarget="@+id/close_button"
app:framePosition="30"
app:sizePercent="1"
app:keyPositionType="pathRelative"
app:percentX="0.5"
/>
<KeyAttribute
app:motionTarget="@+id/close_button"
app:framePosition="30"
android:alpha="1"
>
</KeyAttribute>
</KeyFrameSet>
</Transition>
</MotionScene>
疑惑
moveWhenScrollAtTop=”true” + app:nestedScrollFlags=”disableScroll” 可以保证滑动正常
<OnSwipe
app:touchAnchorId="@+id/profile_photo"
app:dragDirection="dragUp"
app:moveWhenScrollAtTop="true"
app:nestedScrollFlags="disableScroll"
app:maxAcceleration="1.5"
app:maxVelocity="4"
/>
部分源码 (看的不是很懂
@Override
public void onNestedPreScroll(@NonNull View target,
int dx,
int dy,
@NonNull int[] consumed,
int type) {
MotionScene scene = mScene;
if (scene == null) {
return;
}
MotionScene.Transition currentTransition = scene.mCurrentTransition;
if (currentTransition == null || !currentTransition.isEnabled()) {
return;
}
if (currentTransition.isEnabled()) {
TouchResponse touchResponse = currentTransition.getTouchResponse();
if (touchResponse != null) {
int regionId = touchResponse.getTouchRegionId();
if (regionId != MotionScene.UNSET && target.getId() != regionId) {
return;
}
}
}
// 好像是在这里判断的
if (scene.getMoveWhenScrollAtTop()) {
// This blocks transition during scrolling
TouchResponse touchResponse = currentTransition.getTouchResponse();
int vert = -1;
if (touchResponse != null) {
if ((touchResponse.getFlags() & TouchResponse.FLAG_SUPPORT_SCROLL_UP) != 0) {
vert = dy;
}
}
if ((mTransitionPosition == 1 || mTransitionPosition == 0)
&& target.canScrollVertically(vert)) {
return;
}
}
// This should be disabled in androidx
if (currentTransition.getTouchResponse() != null
&& (currentTransition.getTouchResponse().getFlags()
& TouchResponse.FLAG_DISABLE_POST_SCROLL) != 0) {
float dir = scene.getProgressDirection(dx, dy);
if ((mTransitionLastPosition <= 0.0f && (dir < 0))
|| (mTransitionLastPosition >= 1.0f && (dir > 0))) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
target.setNestedScrollingEnabled(false);
// TODO find a better hack
target.post(new Runnable() {
@Override
public void run() {
target.setNestedScrollingEnabled(true);
}
});
}
return;
}
}
if (DEBUG) {
Log.v(TAG, "********** onNestedPreScroll(target:"
+ Debug.getName(target) + ", dx:" + dx + ", dy:" + dy + ", type:" + type);
}
float progress = mTransitionPosition;
long time = getNanoTime();
mScrollTargetDX = dx;
mScrollTargetDY = dy;
mScrollTargetDT = (float) ((time - mScrollTargetTime) * 1E-9);
mScrollTargetTime = time;
if (DEBUG) {
Log.v(TAG, "********** dy = " + dx + " dy = " + dy + " dt = " + mScrollTargetDT);
}
scene.processScrollMove(dx, dy);
if (progress != mTransitionPosition) {
consumed[0] = dx;
consumed[1] = dy;
}
evaluate(false);
if (consumed[0] != 0 || consumed[1] != 0) {
mUndergoingMotion = true;
}
}
Layout
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
</data>
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/teal_200"
app:layoutDescription="@xml/motion"
app:showPaths="true"
tools:context=".MainActivity">
<View
android:id="@+id/bottom_navi"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<View
android:id="@+id/music_control_background"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/white"
app:layout_constraintBottom_toTopOf="@id/bottom_navi"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ImageView
android:id="@+id/profile_photo"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="20dp"
android:scaleType="centerCrop"
android:src="@drawable/ic_toma"
android:contentDescription="23"
app:layout_constraintBottom_toBottomOf="@+id/music_control_background"
app:layout_constraintStart_toStartOf="@id/music_control_background"
app:layout_constraintTop_toTopOf="@id/music_control_background" />
<Button
android:id="@+id/music_button"
android:layout_width="100dp"
android:layout_height="40dp"
android:layout_marginEnd="20dp"
android:text="play"
app:layout_constraintBottom_toBottomOf="@id/music_control_background"
app:layout_constraintEnd_toEndOf="@id/music_control_background"
app:layout_constraintTop_toTopOf="@id/music_control_background" />
<ProgressBar
android:id="@+id/music_progress"
android:layout_width="400dp"
android:layout_height="20dp"
android:visibility="gone"
android:layout_marginTop="50dp"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
app:layout_constraintTop_toBottomOf="@+id/profile_photo"
app:layout_constraintStart_toStartOf="@id/profile_photo"
app:layout_constraintEnd_toEndOf="@id/profile_photo"
/>
<View
android:id="@+id/close_button"
android:layout_width="80dp"
android:layout_height="10dp"
android:background="@color/black"
app:layout_constraintStart_toStartOf="@id/music_control_background"
app:layout_constraintEnd_toEndOf="@id/music_control_background"
app:layout_constraintTop_toTopOf="@id/music_control_background"
android:layout_marginTop="15dp"
android:visibility="gone"
/>
<androidx.core.widget.NestedScrollView
android:id="@+id/scroll_test"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/music_control_background"
>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/black"
/>
<View
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/white"
/>
<View
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/black"
/>
<View
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/white"
/>
<View
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/black"
/>
<View
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/white"
/>
<View
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/black"
/>
<View
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/white"
/><View
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/black"
/>
<View
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/white"
/>
<View
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/black"
/>
<View
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/white"
/>
<View
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/black"
/>
<View
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/white"
/>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.motion.widget.MotionLayout>
</layout>