UI组件在TransitionManager动画中不可见 [英] UI components not visible in TransitionManager animations
问题描述
这是Java Android应用程序中的一个问题,该应用程序具有MainActivity中非常简单的自定义可拖动抽屉.
This is an issue in a Java Android application with a very simple custom draggable drawer in MainActivity.
这是它在Android 10(API级别29)模拟器上运行时的行为,这是预期的行为.
This is how it behaves when it runs on Android 10 (API level 29) emulator, and it is the expected behavior.
但是问题是,当它在Android L(API级别21)模拟器上运行时,其行为异常如下:
But the problem is, when it runs on Android L (API level 21) emulator, it behaves unexpectedly as follows :
在动画过程中,UI组件不可见.但是当应用程序进入后台并返回时,它们就变得可见.
During the animation, UI components are not visible. But when app goes to background and comes back, they become visible.
应用的实现细节:
要检测挥动/拖动触摸手势,请使用GestureDetectorCompat
.
当检测到甩动手势时,将启动自定义抽屉打开动画.
动画是使用ConstraintSet
,ConstraintLayout
和TransitionManager
来实现的.
To detect fling / drag touch gesture, GestureDetectorCompat
was used.
When a fling gesture is detected, the custom drawer open animation is being initiated.
Animation is implemented using ConstraintSet
, ConstraintLayout
and TransitionManager
.
这是触摸手势检测和TransitionManager动画的实现.
This is the implementation of touch gesture detections and TransitionManager animations.
MainActivity.java
MainActivity.java
public class MainActivity extends AppCompatActivity {
private boolean mIsDrawerOpened;
private ConstraintLayout mRootConstraintLayout;
private final ConstraintSet mDrawerClosedConstraintSet = new ConstraintSet();
private final ConstraintSet mDrawerOpenedConstraintSet = new ConstraintSet();
private GestureDetectorCompat mGestureDetector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_drawer_closed);
// Drawer is initially closed
mIsDrawerOpened = false;
mRootConstraintLayout = findViewById(R.id.rootConstraintLayout);
mDrawerClosedConstraintSet.clone(this, R.layout.activity_main_drawer_closed);
mDrawerOpenedConstraintSet.clone(this, R.layout.activity_main_drawer_opened);
mGestureDetector = new GestureDetectorCompat(
getApplicationContext(),
new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// Drag / Fling gesture detected
// TODO: Recongnize unwanted drag / fling gestures and ignore them.
TransitionManager.beginDelayedTransition(mRootConstraintLayout);
// Drawer is closed?
if(!mIsDrawerOpened) {
// Open the drawer
mDrawerOpenedConstraintSet.applyTo(mRootConstraintLayout);
mIsDrawerOpened = true;
}
return true;
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
// Single tap detected
// TODO: If user has tapped on the drawer, do not close it.
TransitionManager.beginDelayedTransition(mRootConstraintLayout);
// Drawer is opened?
if(mIsDrawerOpened) {
// Close the drawer
mDrawerClosedConstraintSet.applyTo(mRootConstraintLayout);
mIsDrawerOpened = false;
}
return true;
}
@Override
public boolean onDown(MotionEvent e) {
return true;
}
}
);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mGestureDetector.onTouchEvent(event);
return super.onTouchEvent(event);
}
}
这是封闭抽屉的布局XML.
This is the layout XML of closed drawer.
res/layout/activity_main_drawer_closed.xml
res/layout/activity_main_drawer_closed.xml
<ConstraintLayout
android:id="@+id/rootConstraintLayout">
<ConstraintLayout
android:id="@+id/drawerConstraintLayout"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
<!-- Constraint start (left) of drawer to end (right) of parent (drawer is outside the parent) -->
app:layout_constraintStart_toEndOf="parent"
... >
<Button
android:id="@+id/button1"
android:text="1"
... />
<Button
android:id="@+id/button2"
android:text="2"
... />
</ConstraintLayout>
<ImageView
android:id="@+id/notch"
android:src="@drawable/drawer_notch"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/drawerConstraintLayout"
... />
</ConstraintLayout>
这是打开的抽屉的布局XML.
This is the layout XML of opened drawer.
res/layout/activity_main_drawer_opened.xml
res/layout/activity_main_drawer_opened.xml
<ConstraintLayout
android:id="@+id/rootConstraintLayout">
<ConstraintLayout
android:id="@+id/drawerConstraintLayout"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
<!-- Constraint end (right) of drawer to end (right) of parent (drawer is inside the parent) -->
app:layout_constraintEnd_toEndOf="parent"
... >
<Button
android:id="@+id/button1"
android:text="1"
... />
<Button
android:id="@+id/button2"
android:text="2"
... />
</ConstraintLayout>
<ImageView
android:id="@+id/notch"
android:src="@drawable/drawer_notch"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/drawerConstraintLayout"
... />
</ConstraintLayout>
这两个布局中的约束集被用作动画的开始和结束关键帧.
ConstraintSets from those 2 layouts are taken as start and end key-frames for animations.
最低SDK版本设置为API级别19.
Min SDK version is set to API level 19.
build.gradle
build.gradle
android {
defaultConfig {
minSdkVersion 19
...
}
...
}
完整实现可在此GitHub要点中找到.
推荐答案
要按预期进行此操作,您需要将android:clipChildren="false"
添加到根目录ViewGroup
,如果您的情况是布局activity_main_drawer_closed.xml
中的ConstaintLayout
.当然,这种解决方案仅适用于您的视图在视口之外的情况.
To do this works as expected you need to add android:clipChildren="false"
to your root ViewGroup
in your case is ConstaintLayout
in your layout activity_main_drawer_closed.xml
. Of course such solution applicable only when your view is outside of the viewport.
我不知道为什么这种行为在Android版本中会有所不同.从理论上讲,从Android棉花糖开始,场景切换时,根视图因TransitionManager
无效而被重画.
I don't know why this behaviour differ through versions of Android. In theory, from Android Marshmallow, when you start scene transition root view became invalidated by TransitionManager
and being redraw.
这篇关于UI组件在TransitionManager动画中不可见的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!