有没有一种方法可以将自定义视图制作成一个方向的动画

时间:2019-05-20 15:05:20

标签: android android-animation

我想创建一个自定义的FAB,其工作方式如下图所示 Desired Animation

但是我能做的就是这样

actual image

我在这里所做的是创建一个包含自定义视图的XML布局。

并创建了一个扩展了Constraint layout的视图并创建了自定义背景,并添加了ValueAnimator来更改视图的高度

这是我的代码:

<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:id="@+id/parent_fab"
    android:layout_width="60dp"
    android:layout_height="60dp"
    android:animateLayoutChanges="true"
    android:background="@drawable/fab"
    android:clipChildren="false"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">


    <ImageView
        android:id="@+id/firstIcon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:alpha="0"
        android:background="?attr/selectableItemBackgroundBorderless"
        android:padding="20dp"
        android:src="@drawable/ic_account_balance_black_24dp"
        android:tooltipText="Remise Par Scanbox"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="ContentDescription" />

    <ImageView
        android:id="@+id/secondIcon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:alpha="0"
        android:background="?attr/selectableItemBackgroundBorderless"
        android:padding="20dp"
        android:src="@drawable/ic_photo_camera_black_24dp"
        android:tooltipText="Remise Par Courrier"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        tools:ignore="ContentDescription" />

    <ImageView

        android:id="@+id/mainIcon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:background="?attr/selectableItemBackgroundBorderless"
        android:padding="20dp"
        android:src="@drawable/ic_add_black_24dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="ContentDescription" />

</android.support.constraint.ConstraintLayout>

java代码:

public class ExpandableFabView extends ConstraintLayout {


    private ConstraintLayout fab;
    private ImageView mainIcon;
    private ImageView firstIcon;
    private ImageView seconIcon;
    private int width;
    private int height;
    private Context context;
    private LayerDrawable ld;
    private ShapeDrawable fabDrawable;
    private boolean expanded = false;
    private long mLastClickTime = 0;


    public ExpandableFabView(@NonNull Context context) {
        super(context);
        this.context = context;
        init();
    }

    public ExpandableFabView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        init();


    }

    public ExpandableFabView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        init();

    }

    void init() {
        LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mInflater.inflate(R.layout.expandablefab, this, true);

        fab = findViewById(R.id.parent_fab);
        mainIcon = findViewById(R.id.mainIcon);
        firstIcon = findViewById(R.id.firstIcon);
        seconIcon = findViewById(R.id.secondIcon);


        mainIcon.setOnClickListener(v -> {
            if (SystemClock.elapsedRealtime() - mLastClickTime < 500) {
                return;
            }
            mLastClickTime = SystemClock.elapsedRealtime();
            slideView(fab.getHeight(), expanded ? fab.getHeight() / 3 : fab.getHeight() * 3, expanded);
            expanded = !expanded;
        });


        setViewBackground();
        dropShadow();

    }





    public void slideView(int currentHeight, int newHeight, boolean reversed) {


        fab.setPivotY(0f);
        ValueAnimator scaleAnimator = ValueAnimator
                .ofInt(currentHeight, newHeight)
                .setDuration(500);

        ValueAnimator slideAnimator = ValueAnimator
                .ofFloat(fab.getY(), fab.getBottom())
                .setDuration(500);

        /* We use an update listener which listens to each tick
         * and manually updates the height of the view  */

        scaleAnimator.addUpdateListener(animation1 -> {
            fab.getLayoutParams().height = (int) (Integer) animation1.getAnimatedValue();
            fab.requestLayout();
            fab.postInvalidate();
            requestLayout();
            invalidate();
        });

        /*slideAnimator.addUpdateListener(animation1 -> {
            fab.animate().translationY(-(Float) animation1.getAnimatedValue());
            fab.requestLayout();
            fab.postInvalidate();
        });
*/
        /*  We use an animationSet to play the animation  */

        AnimatorSet animationSet = new AnimatorSet();
        animationSet.setInterpolator(new AccelerateDecelerateInterpolator());
        animationSet.play(scaleAnimator).with(slideAnimator);
        animationSet.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                super.onAnimationStart(animation);
                mainIcon.animate().rotation(reversed ? 0 : 315);
                firstIcon.animate().alpha(reversed ? 0 : 1).rotation(reversed ? -360 : 0).setStartDelay(100);
                seconIcon.animate().alpha(reversed ? 0 : 1).rotation(reversed ? 360 : 0).setStartDelay(200);


            }
        });


        animationSet.start();
    }


    void dropShadow() {
        RoundRectShape roundRectShape = new RoundRectShape(new float[]{100f, 100f, 100f,
                100f, 100f, 100f, 100f, 100f}, null, null);
        ShapeDrawable shapeDrawable = new ShapeDrawable(roundRectShape);
        shapeDrawable.setShaderFactory(new ShaderFactory() {
            @Override
            public Shader resize(int width, int height) {
                return new LinearGradient(0, 0, 0, height,
                        new int[]{Color.MAGENTA, Color.BLUE},
                        new float[]{0, 1f},
                        Shader.TileMode.REPEAT);
            }

        });

        ld = new LayerDrawable(new Drawable[]{fabDrawable, shapeDrawable});

        ld.setLayerInset(0, 5, 5, 0, 0); // inset the shadow so it doesn't start right at the left/top
        ld.setLayerInset(1, 0, 0, 5, 5);

        fab.setBackground(ld);
    }


    void setViewBackground() {
        RoundRectShape roundRectShape = new RoundRectShape(new float[]{100f, 100f, 100f,
                100f, 100f, 100f, 100f, 100f}, null, null);
        fabDrawable = new ShapeDrawable(roundRectShape);
        fabDrawable.setShaderFactory(new ShaderFactory() {
            @Override
            public Shader resize(int width, int height) {
                return new LinearGradient(0, 0, 0, height,
                        new int[]{Color.parseColor("#e5e5e5"), Color.parseColor("#e5e5e5")},
                        new float[]{0, 1},
                        Shader.TileMode.REPEAT);
            }

        });


        fab.setBackground(fabDrawable);
    }

1 个答案:

答案 0 :(得分:0)

您应该像这样更改PivotPoint,

parentFab.setPivotY(0f);

这会将固定点(当前在y轴和x轴上居中)设置为顶部,因此动画将向下展开。如果需要,可以简单地设置为0f的parentFab高度。