/*
* Copyright (C) 2013 FMSoft (http://www.fmsoft.cn)
*
* 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 org.espier.ios7.ui;
import org.espier.ios7ui.R;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.ImageView;
public class IosLikeToggleButton extends ImageView {
public final static int COLOR_MODE_1 = 0;
public final static int COLOR_MODE_2 = 1;
private final static int DURATION = 200;
private final static int MOVE_LONG_SLOP = 10;
private final static int MOVE_SHORT_SLOP = 1;
private Drawable mToggle;
private Drawable mMask;
private Drawable mMask1;
private float mLastMotionX;
private float mOffsetX;
private int mStartX;
private int mCenterX;
private int mEndX;
private boolean mHasMotionMove;
private boolean mIsChecked;
private OnCheckedChangeListener mOnCheckedChangeListener;
public static interface OnCheckedChangeListener {
void onCheckedChanged(IosLikeToggleButton buttonView, boolean isChecked);
}
private Animation mAnim;
private Transformation mTrans = new Transformation();
public IosLikeToggleButton(Context context, AttributeSet attrs) {
super(context, attrs);
setFocusable(true);
setClickable(true);
setMask(R.drawable.ioslike_toggle_mask_graw);
mMask1 = this.getResources().getDrawable(R.drawable.ioslike_toggle_mask_green);
mToggle = context.getResources().getDrawable(R.drawable.ioslike_toggle_switch);
calcUsefulWidth(mMask, mMask1, mToggle);
}
public void setMask(int rId) {
mMask = this.getResources().getDrawable(rId);
}
public void setToggleColorMode(int colorMode) {
switch(colorMode) {
case COLOR_MODE_1:
mToggle = getContext().getResources().getDrawable(
R.drawable.ioslike_toggle_switch);
calcUsefulWidth(mMask,mMask1, mToggle);
break;
case COLOR_MODE_2:
mToggle = getContext().getResources().getDrawable(
R.drawable.ioslike_toggle_switch_2);
calcUsefulWidth(mMask,mMask1, mToggle);
break;
default:
return;
}
}
public void setChecked(boolean isChecked) {
mIsChecked = isChecked;
mOffsetX = isChecked ? mEndX : mStartX;
invalidate();
}
private void setCheckedInner(boolean isChecked) {
if (mIsChecked != isChecked) {
setChecked(isChecked);
if (mOnCheckedChangeListener != null)
mOnCheckedChangeListener.onCheckedChanged(this, mIsChecked);
invalidate();
}
}
public boolean isChecked() {
return mIsChecked;
}
public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
mOnCheckedChangeListener = listener;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch(ev.getAction()) {
case MotionEvent.ACTION_DOWN:
cancelTranslateAnimation();
mLastMotionX = ev.getX();
break;
case MotionEvent.ACTION_MOVE:
final float x = ev.getX();
final int xDiff = (int) Math.abs(x - mLastMotionX);
final boolean xMoved = xDiff > (mHasMotionMove ? MOVE_SHORT_SLOP : MOVE_LONG_SLOP);
if (xMoved) {
mOffsetX = Math.min(mEndX, Math.max(mStartX, (mOffsetX + x - mLastMotionX)));
mLastMotionX = x;
if (!mHasMotionMove)
mHasMotionMove = true;
postInvalidate();
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (mHasMotionMove) {
mHasMotionMove = false;
if (mOffsetX > mCenterX) {
if (mOffsetX != mStartX) {
startTranslateAnimation((int) mOffsetX, mEndX);
setCheckedInner(true);
}
} else {
if (mOffsetX != mEndX) {
startTranslateAnimation((int) mOffsetX, mStartX);
setCheckedInner(false);
}
}
} else {
if (isChecked()) {
startTranslateAnimation((int) mOffsetX, mStartX);
setCheckedInner(false);
} else {
startTranslateAnimation((int) mOffsetX, mEndX);
setCheckedInner(true);
}
}
break;
}
return true;
}
private void calcUsefulWidth(Drawable mask, Drawable mask1, Drawable toggle) {
final int maskW = mask.getIntrinsicWidth();
final int maskH = mask.getIntrinsicHeight();
final int toggleW = toggle.getIntrinsicWidth();
final int toggleH = toggle.getIntrinsicHeight();
mask.setBounds(0, 0, maskW, maskH);
mask1.setBounds(0, 0, maskW, maskH);
toggle.setBounds(0, 0, toggleW, toggleH);
setMinimumWidth(maskW);
setMinimumHeight(maskH);
mStartX = maskW - toggleW / 2;
mEndX = maskW - mStartX;
mCenterX = (mStartX + mEndX) / 2;
mOffsetX = mStartX;
}
private void cancelTranslateAnimation() {
if (mAnim != null) {
mAnim.cancel();
mAnim = null;
}
}
private void startTranslateAnimation(int startX, int endX) {
cancelTranslateAnimation();
mAnim = new AlphaAnimation(startX, endX);
mAnim.setDuration(DURATION);
mAnim.start();
postInvalidate();
}
@Override
public void draw(Canvas canvas) {
if (mAnim != null && !mAnim.hasEnded()) {
long currentTime = SystemClock.uptimeMillis();
boolean more = mAnim.getTransformation(currentTime, mTrans);
if (more) {
mOffsetX = mTrans.getAlpha();
postInvalidate();
}
}
canvas.save();
canvas.translate(mOffsetX - mEndX, 0);
mToggle.draw(canvas);
canvas.restore();
if(isChecked()){
mMask1.draw(canvas);
}else {
mMask.draw(canvas);
}
}
}