简体   繁体   中英

what's wrong with my android animation timing?

I have the following switch button (I create this for Android 2.3+ so cannot use native switch).

在此处输入图片说明

with the following XML:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/settingsSwitchMainLayout"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:clickable="true" >

    <ImageView
        android:id="@+id/switch_bg2"
        android:layout_width="90dp"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerInParent="true"
        android:layout_centerVertical="true"
        android:src="@drawable/switch_bg_off" />

    <RelativeLayout
        android:id="@+id/switch_handle"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_alignParentRight="true"
        android:layout_marginTop="7dp"
        android:background="@drawable/switch_handle"
        android:padding="0dp" >

        <ImageView
            android:id="@+id/switch_v"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="17dp"
            android:layout_marginTop="14dp"
            android:src="@drawable/switch_v"
            android:visibility="visible" />
    </RelativeLayout>

</RelativeLayout>

And the following code:

    public class SettingsSwitchView extends RelativeLayout {

        private enum SwitchModes {
            CHECKED, UNCHECKED
        }

        private static final int FULL_DURATION = 18000;

        private ImageView mSwitchBg2;
        private RelativeLayout mSwitchHandle;
        private ImageView mSwitchV;
        private NinePatchDrawable mBgTransition;

        private boolean isChecked;

        public SettingsSwitchView(Context context, AttributeSet attrs) {
            super(context, attrs);
            inflater = LayoutInflater.from(context);
            inflater.inflate(R.layout.settings_switch, this);
            initMemebers();

            isChecked = true; // read from config file
            setOnClickListeners();
        }

        private void setOnClickListeners() {
            mSwitchBg2.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    isChecked = !isChecked;
                    SwitchModes switchMode = (isChecked)? SwitchModes.CHECKED : SwitchModes.UNCHECKED;
                    anim_first(switchMode);
                }
            });
        }


        private void anim_first(SwitchModes mode)
        {
            AnimationSet bgAnimation = new AnimationSet(true);

            //bg fade out
            AlphaAnimation alpha_bg_0_50 = getBgAlphafirst(mode);

            //fade_V
            AlphaAnimation alpha_V_0_100 = getVAlphafirst(mode);

            mSwitchV.startAnimation(alpha_V_0_100);

            //slide 
            Animation slide_box_0_100 = getSlideFirst(mode);

            mSwitchHandle.startAnimation(slide_box_0_100);


            //bg fade in
            AlphaAnimation alpha_bg_50_100 = getBgAlphaSecond();
            bgAnimation.addAnimation(alpha_bg_0_50);
            bgAnimation.addAnimation(alpha_bg_50_100);
            mSwitchBg2.startAnimation(bgAnimation);

            //extra slide, stretch
            mSwitchBg2.startAnimation(getExtraScale(mode));
            mSwitchHandle.startAnimation(getExtraSlide(mode));
        }

public class SettingsSwitchView extends RelativeLayout {

    private enum SwitchModes {
        CHECKED, UNCHECKED
    }

    private static final int FULL_DURATION = 18000;

    private static final int TRANSITION_DURATION = 180;
    private static final int ALPHA_DURATION = 180;
    //private static final int BG_TRANSITION_TIME = 40;
    private LayoutInflater inflater;

    //private RelativeLayout mSwitchBg;
    private ImageView mSwitchBg2;
    private RelativeLayout mSwitchHandle;
    private ImageView mSwitchV;
    // private TransitionDrawable mBgTransition;
    private NinePatchDrawable mBgTransition;

    private boolean isChecked;

    public SettingsSwitchView(Context context, AttributeSet attrs) {
        super(context, attrs);
        inflater = LayoutInflater.from(context);
        inflater.inflate(R.layout.settings_switch, this);
        initMemebers();

        isChecked = true; // read from config file
        setOnClickListeners();
    }

    private void setOnClickListeners() {
        mSwitchBg2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                isChecked = !isChecked;
                SwitchModes switchMode = (isChecked)? SwitchModes.CHECKED : SwitchModes.UNCHECKED;
                anim_first(switchMode);
            }
        });
    }


    private void anim_first(SwitchModes mode)
    {
        AnimationSet bgAnimation = new AnimationSet(true);

        //bg fade out
        AlphaAnimation alpha_bg_0_50 = getBgAlphafirst(mode);

        //fade_V
        AlphaAnimation alpha_V_0_100 = getVAlphafirst(mode);

        mSwitchV.startAnimation(alpha_V_0_100);

        //slide 
        Animation slide_box_0_100 = getSlideFirst(mode);

        mSwitchHandle.startAnimation(slide_box_0_100);


        //bg fade in
        AlphaAnimation alpha_bg_50_100 = getBgAlphaSecond();
        bgAnimation.addAnimation(alpha_bg_0_50);
        bgAnimation.addAnimation(alpha_bg_50_100);
        mSwitchBg2.startAnimation(bgAnimation);

        //extra slide, stretch
        mSwitchBg2.startAnimation(getExtraScale(mode));
        mSwitchHandle.startAnimation(getExtraSlide(mode));
    }

    private TranslateAnimation getExtraSlide(SwitchModes mode) {

        final TranslateAnimation translate;

        switch (mode) {
        case CHECKED: {
            translate = new TranslateAnimation(Animation.RELATIVE_TO_SELF, -15, Animation.RELATIVE_TO_SELF, -5, Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0);
            break;
        }
        default:
        case UNCHECKED: {
            translate =  new TranslateAnimation(Animation.RELATIVE_TO_SELF, -60, Animation.RELATIVE_TO_SELF, -70, Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0);
            break;
        }
        }

        translate.setDuration(FULL_DURATION/4);
        translate.setStartOffset(FULL_DURATION);

        return translate;
    }


    private ScaleAnimation getExtraScale(SwitchModes mode) {
        final ScaleAnimation scaleAnimation;

        switch (mode) {
        case CHECKED: {
            scaleAnimation = new ScaleAnimation(1, (float)1.1, 1, 1, Animation.RELATIVE_TO_SELF, (float)0.1, Animation.RELATIVE_TO_SELF, (float)0.5);
            break;
        }
        default:
        case UNCHECKED: {
            scaleAnimation = new ScaleAnimation(1, (float)1.1, 1, 1, Animation.RELATIVE_TO_SELF, (float)0.9, Animation.RELATIVE_TO_SELF, (float)0.5);
            break;
        }
        }

        scaleAnimation.setDuration(FULL_DURATION/4);
        scaleAnimation.setStartOffset(FULL_DURATION);

        return scaleAnimation;
    }


    private AlphaAnimation getVAlphafirst(SwitchModes mode) {
        AlphaAnimation alpha;
        switch (mode) {
        case CHECKED: {
            mSwitchV.setVisibility(View.VISIBLE);
            alpha = new AlphaAnimation(0, 1);
            break;
        }
        default:
        case UNCHECKED: {
            mSwitchV.setVisibility(View.GONE);
            alpha = new AlphaAnimation(1, 0);
            break;
        }
        }
        alpha.setDuration(FULL_DURATION);
        alpha.setFillAfter(true);
        return alpha;
    }

    private AlphaAnimation getBgAlphafirst(SwitchModes mode) {
        AlphaAnimation alpha;
        alpha = new AlphaAnimation(1, (float) 0.5);
        alpha.setDuration(FULL_DURATION/2);

        switch (mode) {
        case CHECKED: {
            mSwitchBg2.setImageDrawable(getResources().getDrawable(R.drawable.switch_bg_on));
            break;
        }
        case UNCHECKED: {
            mSwitchBg2.setImageDrawable(getResources().getDrawable(R.drawable.switch_bg_off));
            break;
        }
        }
        return alpha;

    }

    private AlphaAnimation getBgAlphaSecond() {
        AlphaAnimation alpha;
        alpha = new AlphaAnimation((float) 0.5, 1);
        alpha.setDuration(FULL_DURATION/2);
        alpha.setStartOffset(FULL_DURATION/2);
        return alpha;
    }

    private Animation getSlideFirst(SwitchModes mode) {
        Animation aniamtion;
        switch (mode) {
        case CHECKED: {
            aniamtion = android.view.animation.AnimationUtils.loadAnimation(
                    AppService.getAppContext(), com.myApp.R.anim.slide_to_right);
            break;
        }
        default:
        case UNCHECKED: {
            aniamtion = android.view.animation.AnimationUtils.loadAnimation(
                    AppService.getAppContext(), com.myApp.R.anim.slide_to_left);
            break;
        }
        }

        aniamtion.setDuration(FULL_DURATION);
        aniamtion.setInterpolator(new AccelerateInterpolator());
        aniamtion.setFillAfter(true);
        return aniamtion;
    }

    private void initMemebers() {
        //mSwitchBg = (RelativeLayout) findViewById(R.id.switch_bg);
        mSwitchBg2 = (ImageView) findViewById(R.id.switch_bg2);

        mSwitchHandle = (RelativeLayout) findViewById(R.id.switch_handle);
        mSwitchV = (ImageView) findViewById(R.id.switch_v);
    }
}

I'm using android animation in order to create this animation:

1) The bg color will translate from "off" to "on" (one will fade in, and the other fade out)

2) at the same time the white box will move from one side to another

3) at half of this time the v sign will completely fade out

Then

4) the white box will stretch the bg a bit and return to its position.

5) at the same time, the bg will be stretched and get back to its size.

slide_to_right.xml

<?xml version="1.0" encoding="utf-8"?>
<set
     xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator">
    <translate
        android:fromXDelta="-15%"
        android:toXDelta="-60%">

    </translate>
</set>

But in realtime , the animation is totally different from what I wanted.

1) after first click the white box disappear - I think the bg change cover everything on top of it.

2) next clicks the bg color change at once, no fade-in and out.

Does someone knows what am I doing wrong?

I would suggest you to use an AnimationListener to wait for one animation to finish before you start the next one and if you want to mix them up, use http://nineoldandroids.com for complex animations.

Nine Old Androids is the backward compatible version of property animations which were introduced in Android 3.0.

Even if you manage to make multiple animations with multiple offsets work on your phone, does not mean it will work on all phones.

I have learned that the hard way, after my app was polished and everything worked fine on my phone, i had a look at some other (even 4.x) mobiles, and i had to refactor all animations.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM