| /** |
| * Copyright (C) 2013 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy |
| * of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package com.android.inputmethod.dictionarypack; |
| |
| import android.animation.Animator; |
| import android.animation.AnimatorListenerAdapter; |
| import android.content.Context; |
| import android.util.AttributeSet; |
| import android.view.View; |
| import android.view.ViewPropertyAnimator; |
| import android.widget.Button; |
| import android.widget.FrameLayout; |
| |
| import com.android.inputmethod.latin.R; |
| |
| /** |
| * A view that handles buttons inside it according to a status. |
| */ |
| public class ButtonSwitcher extends FrameLayout { |
| public static final int NOT_INITIALIZED = -1; |
| public static final int STATUS_NO_BUTTON = 0; |
| public static final int STATUS_INSTALL = 1; |
| public static final int STATUS_CANCEL = 2; |
| public static final int STATUS_DELETE = 3; |
| // One of the above |
| private int mStatus = NOT_INITIALIZED; |
| private int mAnimateToStatus = NOT_INITIALIZED; |
| |
| // Animation directions |
| public static final int ANIMATION_IN = 1; |
| public static final int ANIMATION_OUT = 2; |
| |
| private Button mInstallButton; |
| private Button mCancelButton; |
| private Button mDeleteButton; |
| private OnClickListener mOnClickListener; |
| |
| public ButtonSwitcher(Context context, AttributeSet attrs) { |
| super(context, attrs); |
| } |
| |
| public ButtonSwitcher(Context context, AttributeSet attrs, int defStyle) { |
| super(context, attrs, defStyle); |
| } |
| |
| @Override |
| protected void onLayout(final boolean changed, final int left, final int top, final int right, |
| final int bottom) { |
| super.onLayout(changed, left, top, right, bottom); |
| mInstallButton = (Button)findViewById(R.id.dict_install_button); |
| mCancelButton = (Button)findViewById(R.id.dict_cancel_button); |
| mDeleteButton = (Button)findViewById(R.id.dict_delete_button); |
| mInstallButton.setOnClickListener(mOnClickListener); |
| mCancelButton.setOnClickListener(mOnClickListener); |
| mDeleteButton.setOnClickListener(mOnClickListener); |
| setButtonPositionWithoutAnimation(mStatus); |
| if (mAnimateToStatus != NOT_INITIALIZED) { |
| // We have been asked to animate before we were ready, so we took a note of it. |
| // We are now ready: launch the animation. |
| animateButtonPosition(mStatus, mAnimateToStatus); |
| mStatus = mAnimateToStatus; |
| mAnimateToStatus = NOT_INITIALIZED; |
| } |
| } |
| |
| private Button getButton(final int status) { |
| switch(status) { |
| case STATUS_INSTALL: |
| return mInstallButton; |
| case STATUS_CANCEL: |
| return mCancelButton; |
| case STATUS_DELETE: |
| return mDeleteButton; |
| default: |
| return null; |
| } |
| } |
| |
| public void setStatusAndUpdateVisuals(final int status) { |
| if (mStatus == NOT_INITIALIZED) { |
| setButtonPositionWithoutAnimation(status); |
| mStatus = status; |
| } else { |
| if (null == mInstallButton) { |
| // We may come here before we have been layout. In this case we don't know our |
| // size yet so we can't start animations so we need to remember what animation to |
| // start once layout has gone through. |
| mAnimateToStatus = status; |
| } else { |
| animateButtonPosition(mStatus, status); |
| mStatus = status; |
| } |
| } |
| } |
| |
| private void setButtonPositionWithoutAnimation(final int status) { |
| // This may be called by setStatus() before the layout has come yet. |
| if (null == mInstallButton) return; |
| final int width = getWidth(); |
| // Set to out of the screen if that's not the currently displayed status |
| mInstallButton.setTranslationX(STATUS_INSTALL == status ? 0 : width); |
| mCancelButton.setTranslationX(STATUS_CANCEL == status ? 0 : width); |
| mDeleteButton.setTranslationX(STATUS_DELETE == status ? 0 : width); |
| } |
| |
| private void animateButtonPosition(final int oldStatus, final int newStatus) { |
| final View oldButton = getButton(oldStatus); |
| final View newButton = getButton(newStatus); |
| if (null != oldButton && null != newButton) { |
| // Transition between two buttons : animate out, then in |
| animateButton(oldButton, ANIMATION_OUT).setListener( |
| new AnimatorListenerAdapter() { |
| @Override |
| public void onAnimationEnd(final Animator animation) { |
| if (newStatus != mStatus) return; |
| animateButton(newButton, ANIMATION_IN); |
| } |
| }); |
| } else if (null != oldButton) { |
| animateButton(oldButton, ANIMATION_OUT); |
| } else if (null != newButton) { |
| animateButton(newButton, ANIMATION_IN); |
| } |
| } |
| |
| public void setInternalOnClickListener(final OnClickListener listener) { |
| mOnClickListener = listener; |
| } |
| |
| private ViewPropertyAnimator animateButton(final View button, final int direction) { |
| final float outerX = getWidth(); |
| final float innerX = button.getX() - button.getTranslationX(); |
| if (ANIMATION_IN == direction) { |
| button.setClickable(true); |
| return button.animate().translationX(0); |
| } else { |
| button.setClickable(false); |
| return button.animate().translationX(outerX - innerX); |
| } |
| } |
| } |