Syntax :
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="WaitingDots">
<attr name="dotsColor" format="color" />
<attr name="period" format="integer" />
<attr name="jumpHeight" format="integer" />
<attr name="autoplay" format="boolean" />
</declare-styleable>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dots="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.example.extext.DotsTextView
android:id="@+id/dots"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#F00"
android:textSize="45sp"
dots:autoplay="false"
dots:period="1000" />
</LinearLayout>
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Handler;
import android.os.Looper;
import android.text.SpannableString;
import android.text.Spanned;
import android.util.AttributeSet;
import android.widget.TextView;
public class DotsTextView extends TextView {
private JumpingSpan dotOne;
private JumpingSpan dotTwo;
private JumpingSpan dotThree;
private int showSpeed = 700;
private int jumpHeight;
private boolean autoPlay;
private boolean isPlaying;
private boolean isHide;
private int period;
private long startTime;
private boolean lockDotOne;
private boolean lockDotTwo;
private boolean lockDotThree;
private Handler handler;
private AnimatorSet mAnimatorSet = new AnimatorSet();
private float textWidth;
public DotsTextView(Context context) {
super(context);
init(context, null);
}
public DotsTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public DotsTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
handler = new Handler(Looper.getMainLooper());
if (attrs != null) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.WaitingDots);
period = typedArray.getInt(R.styleable.WaitingDots_period, 6000);
jumpHeight = typedArray.getInt(R.styleable.WaitingDots_jumpHeight, (int) (getTextSize() / 4));
autoPlay = typedArray.getBoolean(R.styleable.WaitingDots_autoplay, true);
typedArray.recycle();
}
dotOne = new JumpingSpan();
dotTwo = new JumpingSpan();
dotThree = new JumpingSpan();
SpannableString spannable = new SpannableString("...");
spannable.setSpan(dotOne, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
spannable.setSpan(dotTwo, 1, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
spannable.setSpan(dotThree, 2, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
setText(spannable, BufferType.SPANNABLE);
textWidth = getPaint().measureText(".", 0, 1);
ObjectAnimator dotOneJumpAnimator = createDotJumpAnimator(dotOne, 0);
dotOneJumpAnimator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
invalidate();
}
});
mAnimatorSet.playTogether(dotOneJumpAnimator, createDotJumpAnimator(dotTwo,
period / 6), createDotJumpAnimator(dotThree, period * 2 / 6));
isPlaying = autoPlay;
if(autoPlay) {
start();
}
}
public void start() {
isPlaying = true;
setAllAnimationsRepeatCount(ValueAnimator.INFINITE);
mAnimatorSet.start();
}
private ObjectAnimator createDotJumpAnimator(JumpingSpan jumpingSpan, long delay) {
ObjectAnimator jumpAnimator = ObjectAnimator.ofFloat(jumpingSpan, "translationY", 0, -jumpHeight);
jumpAnimator.setEvaluator(new TypeEvaluator<Number>() {
@Override
public Number evaluate(float fraction, Number from, Number to) {
return Math.max(0, Math.sin(fraction * Math.PI * 2)) * (to.floatValue() - from.floatValue());
}
});
jumpAnimator.setDuration(period);
jumpAnimator.setStartDelay(delay);
jumpAnimator.setRepeatCount(ValueAnimator.INFINITE);
jumpAnimator.setRepeatMode(ValueAnimator.RESTART);
return jumpAnimator;
}
public void stop() {
isPlaying = false;
setAllAnimationsRepeatCount(0);
}
private void setAllAnimationsRepeatCount(int repeatCount) {
for (Animator animator : mAnimatorSet.getChildAnimations()) {
if (animator instanceof ObjectAnimator) {
((ObjectAnimator) animator).setRepeatCount(repeatCount);
}
}
}
public void hide() {
createDotHideAnimator(dotThree, 2).start();
ObjectAnimator dotTwoMoveRightToLeft = createDotHideAnimator(dotTwo, 1);
dotTwoMoveRightToLeft.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
invalidate();
}
});
dotTwoMoveRightToLeft.start();
isHide = true;
}
public void show() {
ObjectAnimator dotThreeMoveRightToLeft = createDotShowAnimator(dotThree, 2);
dotThreeMoveRightToLeft.start();
ObjectAnimator dotTwoMoveRightToLeft = createDotShowAnimator(dotTwo, 1);
dotTwoMoveRightToLeft.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
invalidate();
}
});
dotTwoMoveRightToLeft.start();
isHide = false;
}
private ObjectAnimator createDotHideAnimator(JumpingSpan span, float widthMultiplier) {
return createDotHorizontalAnimator(span, 0, -textWidth * widthMultiplier);
}
private ObjectAnimator createDotShowAnimator(JumpingSpan span, int widthMultiplier) {
return createDotHorizontalAnimator(span, -textWidth * widthMultiplier, 0);
}
private ObjectAnimator createDotHorizontalAnimator(JumpingSpan span, float from, float to) {
ObjectAnimator dotThreeMoveRightToLeft = ObjectAnimator.ofFloat(span, "translationX", from, to);
dotThreeMoveRightToLeft.setDuration(showSpeed);
return dotThreeMoveRightToLeft;
}
public void showAndPlay() {
show();
start();
}
public void hideAndStop() {
hide();
stop();
}
public boolean isHide() {
return isHide;
}
public boolean isPlaying() {
return isPlaying;
}
public void setJumpHeight(int jumpHeight) {
this.jumpHeight = jumpHeight;
}
public void setPeriod(int period) {
this.period = period;
}
}
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.FontMetricsInt;
import android.text.style.ReplacementSpan;
public class JumpingSpan extends ReplacementSpan {
private float translationX = 0;
private float translationY = 0;
@Override
public int getSize(Paint paint, CharSequence text, int start, int end, FontMetricsInt fontMetricsInt) {
return (int) paint.measureText(text, start, end);
}
@Override
public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
canvas.drawText(text, start, end, x + translationX, y + translationY, paint);
}
public void setTranslationX(float translationX) {
this.translationX = translationX;
}
public void setTranslationY(float translationY) {
this.translationY = translationY;
}
}
import android.app.Activity;
import android.os.Bundle;
public class TestWaitingDots extends Activity{
DotsTextView dots;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_waiting_dots);
dots=(DotsTextView)findViewById(R.id.dots);
dots.start();
//dots.hideAndStop();
}
}
Syntax :
/**
* Created by ${"Name :Raju; emailID:rraju1039@gmail.com"} on 1/1/16.
*/
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
/**
* Created by lgp on 2015/10/5.
*/
public class AnimCheckBox extends View {
private final String TAG = "AnimCheckBox";
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private int radius;
private RectF mRectF = new RectF();
private RectF mInnerRectF = new RectF();
private Path mPath = new Path();
private float mSweepAngle;
private final double mSin27 = Math.sin(Math.toRadians(27));
private final double mSin63 = Math.sin(Math.toRadians(63));
private float mHookStartY;
private float mBaseLeftHookOffset;
private float mBaseRightHookOffset;
private float mEndLeftHookOffset;
private float mEndRightHookOffset;
private int size;
private boolean mChecked = true;
private float mHookOffset;
private float mHookSize;
private int mInnerCircleAlpha = 0XFF;
private int mStrokeWidth = 2;
private final int mDuration = 500;
private int mStrokeColor = Color.BLUE;
private int mCircleColor = Color.WHITE;
private final int defaultSize = 40;
private OnCheckedChangeListener mOnCheckedChangeListener;
public AnimCheckBox(Context context) {
this(context, null);
}
public AnimCheckBox(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
private void init(AttributeSet attrs) {
if (attrs != null) {
TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.AnimCheckBox);
mStrokeWidth = (int) array.getDimension(R.styleable.AnimCheckBox_stroke_width, dip(mStrokeWidth));
mStrokeColor = array.getColor(R.styleable.AnimCheckBox_stroke_color, mStrokeColor);
mCircleColor = array.getColor(R.styleable.AnimCheckBox_circle_color, mCircleColor);
array.recycle();
} else {
mStrokeWidth = dip(mStrokeWidth);
}
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mStrokeWidth);
mPaint.setColor(mStrokeColor);
setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
setChecked(!mChecked);
}
});
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST &&
MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) getLayoutParams();
width = height = Math.min(dip(defaultSize) - params.leftMargin - params.rightMargin,
dip(defaultSize) - params.bottomMargin - params.topMargin);
}
int size = Math.min(width - getPaddingLeft() - getPaddingRight(),
height - getPaddingBottom() - getPaddingTop());
setMeasuredDimension(size, size);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
size = getWidth();
radius = (getWidth() - (2 * mStrokeWidth)) / 2;
mRectF.set(mStrokeWidth, mStrokeWidth, size - mStrokeWidth, size - mStrokeWidth);
mInnerRectF.set(mRectF);
mInnerRectF.inset(mStrokeWidth / 2, mStrokeWidth / 2);
mHookStartY = (float) (size / 2 - (radius * mSin27 + (radius - radius * mSin63)));
mBaseLeftHookOffset = (float) (radius * (1 - mSin63)) + mStrokeWidth / 2;
mBaseRightHookOffset = 0f;
mEndLeftHookOffset = mBaseLeftHookOffset + (2 * size / 3 - mHookStartY) * 0.33f;
mEndRightHookOffset = mBaseRightHookOffset + (size / 3 + mHookStartY) * 0.38f;
mHookSize = size - (mEndLeftHookOffset + mEndRightHookOffset);
mHookOffset = mChecked ? mHookSize + mEndLeftHookOffset - mBaseLeftHookOffset : 0;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawCircle(canvas);
drawHook(canvas);
}
private void drawCircle(Canvas canvas) {
initDrawStrokeCirclePaint();
canvas.drawArc(mRectF, 202, mSweepAngle, false, mPaint);
initDrawAlphaStrokeCirclePaint();
canvas.drawArc(mRectF, 202, mSweepAngle - 360, false, mPaint);
initDrawInnerCirclePaint();
canvas.drawArc(mInnerRectF, 0, 360, false, mPaint);
}
private void drawHook(Canvas canvas) {
if (mHookOffset == 0)
return;
initDrawHookPaint();
mPath.reset();
float offset;
if (mHookOffset <= (2 * size / 3 - mHookStartY - mBaseLeftHookOffset)) {
mPath.moveTo(mBaseLeftHookOffset, mBaseLeftHookOffset + mHookStartY);
mPath.lineTo(mBaseLeftHookOffset + mHookOffset, mBaseLeftHookOffset + mHookStartY + mHookOffset);
} else if (mHookOffset <= mHookSize) {
mPath.moveTo(mBaseLeftHookOffset, mBaseLeftHookOffset + mHookStartY);
mPath.lineTo(2 * size / 3 - mHookStartY, 2 * size / 3);
mPath.lineTo(mHookOffset + mBaseLeftHookOffset,
2 * size / 3 - (mHookOffset - (2 * size / 3 - mHookStartY - mBaseLeftHookOffset)));
} else {
offset = mHookOffset - mHookSize;
mPath.moveTo(mBaseLeftHookOffset + offset, mBaseLeftHookOffset + mHookStartY + offset);
mPath.lineTo(2 * size / 3 - mHookStartY, 2 * size / 3);
mPath.lineTo(mHookSize + mBaseLeftHookOffset + offset,
2 * size / 3 - (mHookSize - (2 * size / 3 - mHookStartY - mBaseLeftHookOffset) + offset));
}
canvas.drawPath(mPath, mPaint);
}
private void initDrawHookPaint() {
mPaint.setAlpha(0xFF);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mStrokeWidth);
mPaint.setColor(mStrokeColor);
}
private void initDrawStrokeCirclePaint() {
mPaint.setAlpha(0xFF);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mStrokeWidth);
mPaint.setColor(mStrokeColor);
}
private void initDrawAlphaStrokeCirclePaint() {
mPaint.setStrokeWidth(mStrokeWidth);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(mStrokeColor);
mPaint.setAlpha(0x40);
}
private void initDrawInnerCirclePaint() {
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(mCircleColor);
mPaint.setAlpha(mInnerCircleAlpha);
}
private void startCheckedAnim() {
ValueAnimator animator = new ValueAnimator();
final float hookMaxValue = mHookSize + mEndLeftHookOffset - mBaseLeftHookOffset;
final float circleMaxFraction = mHookSize / hookMaxValue;
final float circleMaxValue = 360 / circleMaxFraction;
animator.setFloatValues(0, 1);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float fraction = animation.getAnimatedFraction();
mHookOffset = fraction * hookMaxValue;
if (fraction <= circleMaxFraction) {
mSweepAngle = (int) ((circleMaxFraction - fraction) * circleMaxValue);
} else {
mSweepAngle = 0;
}
mInnerCircleAlpha = (int) (fraction * 0xFF);
invalidate();
}
});
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.setDuration(mDuration).start();
}
private void startUnCheckedAnim() {
ValueAnimator animator = new ValueAnimator();
final float hookMaxValue = mHookSize + mEndLeftHookOffset - mBaseLeftHookOffset;
final float circleMinFraction = (mEndLeftHookOffset - mBaseLeftHookOffset) / hookMaxValue;
final float circleMaxValue = 360 / (1 - circleMinFraction);
animator.setFloatValues(0, 1);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float circleFraction = animation.getAnimatedFraction();
float fraction = 1 - circleFraction;
mHookOffset = fraction * hookMaxValue;
if (circleFraction >= circleMinFraction) {
mSweepAngle = (int) ((circleFraction - circleMinFraction) * circleMaxValue);
} else {
mSweepAngle = 0;
}
mInnerCircleAlpha = (int) (fraction * 0xFF);
invalidate();
}
});
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.setDuration(mDuration).start();
}
private void startAnim() {
clearAnimation();
if (mChecked) {
startCheckedAnim();
} else {
startUnCheckedAnim();
}
}
private int getAlphaColor(int color, int alpha) {
alpha = alpha < 0 ? 0 : alpha;
alpha = alpha > 255 ? 255 : alpha;
return (color & 0x00FFFFFF) | alpha << 24;
}
public boolean isChecked() {
return mChecked;
}
/**
* setChecked with Animation
*
* @param checked true if checked, false if unchecked
*/
public void setChecked(boolean checked) {
setChecked(checked, true);
}
/**
* @param checked true if checked, false if unchecked
* @param animation true with animation,false without animation
*/
public void setChecked(boolean checked, boolean animation) {
if (checked == this.mChecked) {
return;
}
this.mChecked = checked;
if (animation) {
startAnim();
} else {
if (mChecked) {
mInnerCircleAlpha = 0xFF;
mSweepAngle = 0;
mHookOffset = mHookSize + mEndLeftHookOffset - mBaseLeftHookOffset;
} else {
mInnerCircleAlpha = 0x00;
mSweepAngle = 360;
mHookOffset = 0;
}
invalidate();
}
if (mOnCheckedChangeListener != null) {
mOnCheckedChangeListener.onChange(mChecked);
}
}
private int dip(int dip) {
return (int) getContext().getResources().getDisplayMetrics().density * dip;
}
@Override
protected Parcelable onSaveInstanceState() {
return super.onSaveInstanceState();
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
super.onRestoreInstanceState(state);
}
/**
* setOnCheckedChangeListener
*
* @param listener the OnCheckedChangeListener listener
*/
public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
this.mOnCheckedChangeListener = listener;
}
public interface OnCheckedChangeListener {
void onChange(boolean checked);
}
}
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="AnimCheckBox">
<attr name="stroke_width" format="dimension"/>
<attr name="checked" format="boolean"/>
<attr name="stroke_color" format="color"/>
<attr name="circle_color" format="color"/>
</declare-styleable>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<com.example.androidcollegeppt.AnimCheckBox
android:id="@+id/checkbox_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="1dp"
app:circle_color="#795548"
app:stroke_color="#607D8B"
app:stroke_width="2dp" />
<com.example.androidcollegeppt.AnimCheckBox
android:id="@+id/checkbox_2"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_gravity="center_horizontal"
android:padding="4dp"
app:circle_color="#FFFFFF"
app:stroke_color="#9C27B0"
app:stroke_width="3dp" />
<com.example.androidcollegeppt.AnimCheckBox
android:id="@+id/checkbox_3"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:padding="4dp"
app:circle_color="#1976D2"
app:stroke_color="#2196F3"
app:stroke_width="4dp" />
<com.example.androidcollegeppt.AnimCheckBox
android:id="@+id/checkbox_4"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:padding="4dp"
app:circle_color="#4CAF50"
app:stroke_color="#009688"
app:stroke_width="4dp" />
<com.example.androidcollegeppt.AnimCheckBox
android:id="@+id/checkbox_5"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:padding="6dp"
app:circle_color="#9C27B0"
app:stroke_color="#512DA8"
app:stroke_width="4dp" />
</LinearLayout>
</LinearLayout>
import android.app.Activity;
import android.os.Bundle;
public class TestDemo extends Activity{
AnimCheckBox checkbox_1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_demo);
checkbox_1=(AnimCheckBox)findViewById(R.id.checkbox_1);
checkbox_1.setChecked(false, false);
}
}