从按钮到编辑框的转换

9

我希望我的Android views中有一个transition,其中一个是Button,另一个是EditText,过渡效果必须像这个动画。

Button to EditText Transitions

我用这种方式尝试过

布局xml是

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    tools:context="app.itc.org.todo.MainActivity">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:weightSum="2">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:orientation="vertical"
            android:background="@android:color/white"
            android:gravity="center_horizontal|center_vertical">

            <TextView
                android:id="@+id/title_tv"
                android:text="@string/to_do"
                android:textSize="22sp"
                android:textStyle="bold"
                android:textColor="@android:color/black"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="10dp"/>

            <TextView
                android:id="@+id/date_tv"
                android:textSize="16sp"
                android:textColor="@android:color/darker_gray"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />


        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:background="@color/colorGray"
            android:gravity="center_horizontal|center_vertical"
            android:orientation="vertical">

            <TextView
                android:text="@string/what_do_you_want_to_do_today"
                android:textSize="16sp"
                android:textColor="@android:color/darker_gray"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="10dp"/>

            <TextView
                android:text="@string/start_adding_items_to_your_to_do_list"
                android:textSize="16sp"
                android:textColor="@android:color/darker_gray"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>


        </LinearLayout>

    </LinearLayout>

    <FrameLayout
        android:id="@+id/transitions_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="visible">

        <Button
            android:id="@+id/add_btn"
            android:layout_width="200dp"
            android:layout_height="60dp"
            android:text="@string/add_item"
            android:textSize="18sp"
            android:paddingLeft="20dp"
            android:textColor="@android:color/white"
            android:drawableLeft="@drawable/ic_add_24dp"
            android:background="@drawable/rounded_black_bg"
            android:layout_gravity="center"/>

        <EditText
            android:id="@+id/item_input_et"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:visibility="gone"
            android:minHeight="50dp"
            android:layout_marginLeft="@dimen/margin_30dp"
            android:layout_marginRight="@dimen/margin_30dp"
            android:paddingLeft="@dimen/dimen_20dp"
            android:paddingRight="@dimen/dimen_50dp"
            android:textColor="@android:color/black"
            android:inputType="text"
            android:background="@drawable/rounded_edit_text"
            android:layout_gravity="center"/>


    </FrameLayout>

</RelativeLayout>

预览是

Java代码是

public class MainActivity extends AppCompatActivity {

    private EditText mItemInputEditText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView dateTextView = (TextView) findViewById(R.id.date_tv);

        mItemInputEditText = (EditText) findViewById(R.id.item_input_et);
        final Button addButton = (Button) findViewById(R.id.add_btn);

        final ViewGroup transitionsContainer = (ViewGroup) findViewById(R.id.transitions_container);

        mItemInputEditText.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {



                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                    TransitionSet set = new TransitionSet()
                            .addTransition(new Fade())
                            .setInterpolator(new FastOutLinearInInterpolator());

                    TransitionManager.beginDelayedTransition(transitionsContainer, set);
                }

                addButton.setVisibility(View.VISIBLE);
                mItemInputEditText.setVisibility(View.GONE);
            }
        });

        addButton.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                    TransitionSet set = new TransitionSet()
                            .addTransition(new Fade())
                            .setInterpolator(new FastOutLinearInInterpolator());

                    TransitionManager.beginDelayedTransition(transitionsContainer, set);
                }

                addButton.setVisibility(View.GONE);
                mItemInputEditText.setVisibility(View.VISIBLE);
            }

        });

        SimpleDateFormat dt = new SimpleDateFormat("EEE d MMM yyyy");
        dateTextView.setText(dt.format(new Date()));

    }
}

但是使用这段代码,产生的过渡效果是:

My Resulting transition

如您所见,与预期的相比,这有些奇怪,请问有人能建议我做出一些改变以获得所需的过渡效果吗?


你想要的过渡效果不是淡入淡出,而是ChangeBounds。请参考https://developer.android.com/reference/android/transition/ChangeBounds.html。 同时,使用单独的场景可以更好地实现过渡效果。 - Sourav Bagchi
一个例子,请... - Arshad Ali
创建场景-https://developer.android.com/training/transitions/scenes.html - Sourav Bagchi
如果您不想使用单独的场景,我建议您创建一个自定义动画器。几天前,我也尝试将FloatingActionButton转换为CardView。但是过渡效果并不如预期。因此,我为我的目的创建了一个动画器。 - Sourav Bagchi
@azizbekian,我已经在GitHub上发布了这个项目,网址为https://github.com/arshadalisoomro/ToDo。 - Arshad Ali
显示剩余4条评论
3个回答

16

过渡 API 肯定是一个很好的东西,但它不能为您解决所有问题。如果您没有指示过渡框架执行动画,那么它怎么知道您想要执行的最终动画是什么呢?

我不确定这个动画能否仅使用 Transitions API 来实现。相反,您可以坚持使用标准动画 API,例如 ValueAnimator

该动画由几个阶段组成。当单击按钮时,您希望其变得略微更宽,并失去其透明度。完成这些步骤后,您希望 EditText 进入场景,并从按钮着陆的宽度开始,以其最终值进行动画处理。

因此,在按钮点击侦听器中:

@Override注解表示当前方法覆盖了父类或接口中的同名方法 public void onClick(View v) { //当按钮被点击后执行的方法
final int from = addButton.getWidth(); //获取当前添加按钮的宽度 final int to = (int) (from * 1.2f); //增加20%的宽度(即放大) final LinearInterpolator interpolator = new LinearInterpolator(); //插值器,用于动画效果
ValueAnimator firstAnimator = ValueAnimator.ofInt(from, to); //创建值动画从from到to firstAnimator.setTarget(addButton); //设置动画目标为添加按钮 firstAnimator.setInterpolator(interpolator); //设置插值器 firstAnimator.setDuration(DURATION); //设置动画持续时间
final ViewGroup.LayoutParams params = addButton.getLayoutParams(); firstAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { params.width = (Integer) animation.getAnimatedValue(); //将动画的值赋给按钮的宽度 addButton.setAlpha(1 - animation.getAnimatedFraction()); //改变按钮的透明度 addButton.requestLayout(); //请求重新布局以应用新的宽度和透明度 } });
firstAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { //当第一个动画结束时执行以下内容 addButton.setAlpha(1.0f); //重置按钮透明度 addButton.setVisibility(View.GONE); //隐藏添加按钮
mItemInputEditText.setVisibility(View.VISIBLE); //显示输入框
ValueAnimator secondAnimator = ValueAnimator.ofInt(to, editTextWidth); //创建值动画从to到输入框宽度 secondAnimator.setTarget(mItemInputEditText); //设置动画目标为输入框 secondAnimator.setInterpolator(interpolator); //设置插值器 secondAnimator.setDuration(DURATION); //设置动画持续时间
final ViewGroup.LayoutParams params = mItemInputEditText.getLayoutParams(); secondAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { params.width = (Integer) animation.getAnimatedValue(); //将动画的值赋给输入框宽度 mItemInputEditText.requestLayout(); //请求重新布局以应用新的宽度 } });
secondAnimator.start(); //开始第二个动画 } });
firstAnimator.start(); //开始第一个动画 }

EditText 返回按钮时执行类似的动作:


    @Override
    public void onClick(View view) {
final int from = mItemInputEditText.getWidth();//获取输入框的初始宽度 final int to = (int) (from * 0.8f);//将其收缩至原来的0.8倍 final LinearInterpolator interpolator = new LinearInterpolator();//设置动画插值器,即动画变化速率
ValueAnimator firstAnimator = ValueAnimator.ofInt(from, to);//第一个动画,将输入框宽度从from变为to firstAnimator.setTarget(mItemInputEditText); firstAnimator.setInterpolator(interpolator);//设置动画插值器 firstAnimator.setDuration(DURATION);//设置动画持续时间
final ViewGroup.LayoutParams params = mItemInputEditText.getLayoutParams(); firstAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {//设置第一个动画的监听器,实现动画效果 @Override public void onAnimationUpdate(ValueAnimator animation) { params.width = (Integer) animation.getAnimatedValue();//改变输入框宽度的参数 mItemInputEditText.requestLayout();//重新布局输入框 } });
firstAnimator.addListener(new AnimatorListenerAdapter() {//第一个动画结束后执行的监听器 @Override public void onAnimationEnd(Animator animation) { mItemInputEditText.setVisibility(View.GONE);//隐藏输入框 addButton.setVisibility(View.VISIBLE);//显示按钮
ValueAnimator secondAnimator = ValueAnimator.ofInt(to, buttonWidth);//第二个动画,将按钮宽度从to变为buttonWidth secondAnimator.setTarget(addButton);//指定目标对象为按钮 secondAnimator.setInterpolator(interpolator);//设置动画插值器 secondAnimator.setDuration(DURATION);//设置动画持续时间
final ViewGroup.LayoutParams params = addButton.getLayoutParams(); secondAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {//设置第二个动画的监听器,实现动画效果 @Override public void onAnimationUpdate(ValueAnimator animation) { params.width = (Integer) animation.getAnimatedValue();//改变按钮宽度的参数 addButton.setAlpha(animation.getAnimatedFraction());//改变按钮透明度 addButton.requestLayout();//重新布局按钮 } });
secondAnimator.addListener(new AnimatorListenerAdapter() {//第二个动画开始前执行的监听器 @Override public void onAnimationStart(Animator animation) { addButton.setAlpha(0.0f);//将按钮透明度设为0 } });
secondAnimator.start();//启动第二个动画 } });
firstAnimator.start();//启动第一个动画 }

editTextWidthbuttonWidth是视图的初始大小:


    private int editTextWidth, buttonWidth;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
...
// `transitions_container`是`EditText`和`Button`的父容器, // 因此在该容器上发布,确保在执行此可运行项时,这两个视图都已布局完毕。 findViewById(R.id.transitions_container).post(new Runnable() { @Override public void run() { editTextWidth = mItemInputEditText.getWidth(); // 在能够测量之前,`mItemInputEditText`应在XML中保持可见。 // 在获取实际宽度后设置为GONE mItemInputEditText.setVisibility(View.GONE); buttonWidth = addButton.getWidth(); } }); }

这是输出结果:

输入图像描述

你可以在这里获取更改的补丁文件。


1
看起来是完美的答案。 - IntelliJ Amiya
我会在我的端上测试,并给予奖励。 - Arshad Ali
哦,天啊!奖励有限制,等限制解除后我会给你奖励的。 - Arshad Ali
@ArshadAli,如果您愿意,可以不给出奖励,只要它是一个被接受的答案,在赏金期结束时将自动获得奖励。 - azizbekian
1
最后我想问的是,“我该如何获得像第一张 GIF 图片中那样的添加图标动画?” - Arshad Ali
1
@ArshadAli,那看起来像是Animated Vector Drawable。可以看看ShapeShifter - azizbekian

0
首先,更改您的布局XML。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    tools:context="app.itc.org.todo.MainActivity">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:weightSum="2">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:orientation="vertical"
            android:background="@android:color/white"
            android:gravity="center_horizontal|center_vertical">

            <TextView
                android:id="@+id/title_tv"
                android:text="@string/to_do"
                android:textSize="22sp"
                android:textStyle="bold"
                android:textColor="@android:color/black"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="10dp"/>

            <TextView
                android:id="@+id/date_tv"
                android:textSize="16sp"
                android:textColor="@android:color/darker_gray"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />


        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:background="@color/colorGray"
            android:gravity="center_horizontal|center_vertical"
            android:orientation="vertical">

            <TextView
                android:text="@string/what_do_you_want_to_do_today"
                android:textSize="16sp"
                android:textColor="@android:color/darker_gray"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="10dp"/>

            <TextView
                android:text="@string/start_adding_items_to_your_to_do_list"
                android:textSize="16sp"
                android:textColor="@android:color/darker_gray"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>


        </LinearLayout>

    </LinearLayout>

    <FrameLayout
        android:id="@+id/transitions_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="visible">
        <include layout="@layout/a_scene" />
    </FrameLayout>

</RelativeLayout>

接下来为按钮创建你的第一个场景。 第一个场景的布局如下所示:

res/layout/a_scene.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/scene_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <Button
            android:id="@+id/add_btn"
            android:layout_width="200dp"
            android:layout_height="60dp"
            android:text="@string/add_item"
            android:textSize="18sp"
            android:paddingLeft="20dp"
            android:textColor="@android:color/white"
            android:drawableLeft="@drawable/ic_add_24dp"
            android:background="@drawable/rounded_black_bg"
            android:layout_gravity="center"/>
</RelativeLayout>

第二个场景的布局包含了具有相同ID的editText,并定义如下:
res/layout/another_scene.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/scene_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
        <EditText
                android:id="@+id/add_btn"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:visibility="gone"
                android:minHeight="50dp"
                android:layout_marginLeft="@dimen/margin_30dp"
                android:layout_marginRight="@dimen/margin_30dp"
                android:paddingLeft="@dimen/dimen_20dp"
                android:paddingRight="@dimen/dimen_50dp"
                android:textColor="@android:color/black"
                android:inputType="text"
                android:background="@drawable/rounded_edit_text"
                android:layout_gravity="center"/>
    </RelativeLayout>

Java 代码:
public class MainActivity extends AppCompatActivity {

    private EditText mItemInputEditText;
    private Scene mAScene;
    private Scene mAnotherScene;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView dateTextView = (TextView) findViewById(R.id.date_tv);

        mItemInputEditText = (EditText) findViewById(R.id.item_input_et);
        final Button addButton = (Button) findViewById(R.id.add_btn);

        final ViewGroup transitionsContainer = (ViewGroup) findViewById(R.id.transitions_container);

        // Create the scenes
        mAScene = Scene.getSceneForLayout(mSceneRoot, R.layout.a_scene, this);
        mAnotherScene = Scene.getSceneForLayout(mSceneRoot, R.layout.another_scene, this);

        mItemInputEditText.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {



                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                    Transition transition = new ChangeBounds();

                    TransitionManager.go(mAScene, transition);
                }

                addButton.setVisibility(View.VISIBLE);
                mItemInputEditText.setVisibility(View.GONE);
            }
        });

        addButton.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                    Transition transition = new ChangeBounds();

                    TransitionManager.go(mAnotherScenetransition);
                }

                addButton.setVisibility(View.GONE);
                mItemInputEditText.setVisibility(View.VISIBLE);
            }

        });

        SimpleDateFormat dt = new SimpleDateFormat("EEE d MMM yyyy");
        dateTextView.setText(dt.format(new Date()));

    }
}

然后使用ValueAnimator为此动画创建自己的动画程序。 - Sourav Bagchi

0
你可以使用FABReveal Layout来实现这个功能。参考一下它的代码,将Relative layout改为button,并根据需要进行修改。
XML
<com.truizlop.fabreveallayout.FABRevealLayout
    android:id="@+id/fab_reveal_layout"
    android:layout_width="match_parent"
    android:layout_height="@dimen/fab_reveal_height"
    >

    <android.support.design.widget.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:backgroundTint="@color/some_color"
        android:src="@drawable/some_drawable"
        />

    <RelativeLayout
        android:id="@+id/main_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        ...
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/secondary_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        ...
    </RelativeLayout>

</com.truizlop.fabreveallayout.FABRevealLayout>

https://github.com/truizlop/FABRevealLayout

https://github.com/saulmm/Curved-Fab-Reveal-Example


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接