这是Java Android应用程序中的一个问题,它在MainActivity中具有非常简单的自定义可拖动抽屉。
这是它在Android 10(API级别29)模拟器上运行时的行为,这是预期的行为。
但是问题是,当它在Android L(API级别21)模拟器上运行时,其行为异常如下:
在动画期间,UI组件不可见。但是,当应用程序进入后台并返回时,它们就变得可见。
应用程序的实现细节:
为了检测挥动/拖动触摸手势,使用了GestureDetectorCompat
。当检测到甩动手势时,将启动自定义抽屉打开动画。动画是使用ConstraintSet
,ConstraintLayout
和TransitionManager
来实现的。
这是触摸手势检测和TransitionManager动画的实现。
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。
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。
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>
来自这两个布局的约束集被用作动画的开始和结束关键帧。
最小SDK版本设置为API级别19。
build.gradle
android { defaultConfig { minSdkVersion 19 ... } ... }
可以在this GitHub gist中找到完整的实现。
这是Java Android应用程序中的一个问题,它在MainActivity中具有非常简单的自定义可拖动抽屉。它在Android 10(API级别29)模拟器上运行时的行为方式,它是...
要达到预期效果,您需要在布局android:clipChildren="false"
中将ViewGroup
添加到根目录ConstaintLayout
中。当然,这种解决方案仅适用于您的视图在视口之外的情况。