我在其他两个视图之间放置了一个片段,需要平滑地过渡到其他视图之外。我设置了一个片段动画以将片段缩放到视线之外。这很好。但是,一旦动画开始,片段的视图就会立即从视图层次结构中移出,从而导致片段下方的视图在片段的视图上方折叠。如何获取片段下方的视图以随着片段的缩放平滑地上下过渡?
以下是发生的情况的一个示例:
这是MainActivity.java
public class MainActivity extends AppCompatActivity {
public final String TAG = "MainActivity";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnHide = findViewById(R.id.btn_hide);
Button btnShow = findViewById(R.id.btn_show);
final FragmentManager fm = getSupportFragmentManager();
final Fragment fragment = fm.findFragmentById(R.id.frag_middle);
btnHide.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(fragment != null) {
FragmentTransaction ft = fm.beginTransaction();
ft.setCustomAnimations(R.anim.fade_in, R.anim.fade_out);
ft.hide(fragment);
ft.commit();
}else{
Log.d(TAG, "fragment is null!");
}
}
});
btnShow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(fragment != null){
FragmentTransaction ft = fm.beginTransaction();
ft.setCustomAnimations(R.anim.fade_in, R.anim.fade_out);
ft.show(fragment);
ft.commit();
}else{
Log.d(TAG, "fragment is null!");
}
}
});
}
}
这是activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp"
tools:context=".MainActivity">
<TextView
android:id="@+id/tv_top"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:padding="16dp"
android:text="TextViewTop"
android:textAlignment="center"
android:textStyle="bold"
android:textColor="@android:color/white"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:background="@color/colorPrimary"/>
<fragment
android:id="@+id/frag_middle"
android:name="my.packagename.mytestapplication.TestFragment"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/tv_top"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<TextView
android:id="@+id/tv_bottom"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:padding="16dp"
android:text="TextViewBottom"
android:textAlignment="center"
android:textStyle="bold"
android:textColor="@android:color/white"
app:layout_constraintTop_toBottomOf="@+id/frag_middle"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:background="@color/colorPrimary"/>
<Button
android:id="@+id/btn_hide"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hide Fragment"
app:layout_constraintTop_toBottomOf="@id/tv_bottom"
app:layout_constraintStart_toStartOf="parent"
/>
<Button
android:id="@+id/btn_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Show Fragment"
app:layout_constraintTop_toBottomOf="@id/tv_bottom"
app:layout_constraintEnd_toEndOf="parent"/>
这是动画xml的示例:
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000">
<scale
android:fromYScale="0"
android:toYScale="1"
android:fromXScale="1"
android:toXScale="1" />
任何帮助将不胜感激!谢谢
答案 0 :(得分:1)
使用Transition API
实现此动画的简便方法。 TransitionManager
可以处理视图或视图层次结构更改并为其设置动画。隐藏/显示片段时,您只需更改片段视图的可见性即可。
private void toggle() {
final FragmentManager fm = getSupportFragmentManager();
final Fragment fragment = fm.findFragmentById(R.id.frag_middle);
ViewGroup parentViewGroup = findViewById(R.id.parentViewGroup);
TransitionManager.beginDelayedTransition(parentViewGroup, new AutoTransition());
FragmentTransaction ft = fm.beginTransaction();
if (show) {
ft.show(fragment);
} else {
ft.hide(fragment);
}
ft.commitNow();
show = !show;
}
这里重要的是使用commitNow
方法而不是commit
。因为commitNow
立即执行片段事务,这就是TransitionManager
处理视图更改的原因。使用commit
无效,因为commit
异步执行事务。
<android.support.constraint.ConstraintLayout
...
android:id="@+id/parentViewGroup">
<fragment
android:id="@+id/frag_middle"
android:name="TestFragment"
android:layout_width="300dp"
android:layout_height="200dp"
app:layout_constraintTop_toBottomOf="@id/tv_top"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
</android.support.constraint.ConstraintLayout>
我已在此xml中将width
和height
添加到fragment
中。结果如下:
答案 1 :(得分:0)
经过几个小时的研究,我想出了自己的解决方案。它不是完美的,我不确定这是正确的方法还是最好的方法,但是确实如此。
我完全放弃了使用FragmentTransaction的setCustomAnimations方法的想法,并改为使用ObjectAnimator对片段的视图进行动画处理。
我从上面更改的唯一代码是两个按钮onClick侦听器。这是更新的onClickListener代码:
btnHide.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(fragment != null && fragment.getView() != null) {
final ViewGroup.LayoutParams params = fragment.getView().getLayoutParams();
final int startHeight = fragment.getView().getMeasuredHeight();
Log.d(TAG, "startHeight is " + startHeight);
ObjectAnimator animator = ObjectAnimator.ofFloat(fragment.getView(), "scaleY", 0f).setDuration(500);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float yVal = (float)animation.getAnimatedValue();
params.height = (int)(yVal * startHeight);
fragment.getView().requestLayout();
}
});
animator.addListener(new Animator.AnimatorListener() {
@Override public void onAnimationStart(Animator animation) {}
@Override public void onAnimationEnd(Animator animation) {
FragmentTransaction ft = fm.beginTransaction();
ft.hide(fragment);
ft.commit();
}
@Override public void onAnimationCancel(Animator animation) {}
@Override public void onAnimationRepeat(Animator animation) {}
});
animator.start();
}else{
Log.d(TAG, "fragment is null!");
}
}
});
btnShow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(fragment != null && fragment.getView() != null){
final ViewGroup.LayoutParams params = fragment.getView().getLayoutParams();
fragment.getView().measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
final int endHeight = fragment.getView().getMeasuredHeight();
Log.d(TAG, "endHeight is " + endHeight);
ObjectAnimator animator = ObjectAnimator.ofFloat(fragment.getView(), "scaleY", 1f).setDuration(500);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float yVal = (float)animation.getAnimatedValue();
Log.d(TAG, "animation height is " + yVal);
params.height = (int)(yVal * endHeight);
Log.d(TAG, "height is " + params.height);
fragment.getView().requestLayout();
}
});
animator.addListener(new Animator.AnimatorListener() {
@Override public void onAnimationStart(Animator animation) {
FragmentTransaction ft = fm.beginTransaction();
ft.show(fragment);
ft.commit();
}
@Override public void onAnimationEnd(Animator animation) {}
@Override public void onAnimationCancel(Animator animation) {}
@Override public void onAnimationRepeat(Animator animation) {}
});
animator.start();
}else{
Log.d(TAG, "fragment is null!");
}
}
});
这是现在的样子:
它仍然不完美,但是更接近我想要的。