效果图
备注:效果是四个自定义的CircleTextView设置不同的旋转方向、速度、透明度居中对齐的最终效果。
实现原理:
1、绘制圆环形路径TextView
private void drawCircleText(Canvas canvas) {
Path path = new Path();
path.addCircle(centerX, centerY, radius, Path.Direction.CW);
canvas.drawTextOnPath(getText().toString(), path, 0, 0, paint);
}
2、设置rotation属性动画
public void doAnimation() {
if (rotationCM)
animator = ObjectAnimator.ofFloat(this, "rotation", 0f, 360f);
else
animator = ObjectAnimator.ofFloat(this, "rotation", 360f, 0f);
animator.setDuration(rotationTime);
animator.setRepeatMode(ValueAnimator.RESTART);
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.setInterpolator(new LinearInterpolator());
animator.start();
}
3、备注:自定义的xml属性,诸如:旋转方向、文字透明度、旋转一圈用时…请见详细代码
详细代码
1、自定义CircleTextView代码
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.text.Layout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.animation.LinearInterpolator;
import android.widget.TextView;
import com.example.zpf.animmenu.R;
/**
* Created by zpf on 2016/11/9.
* 圆形路径旋转文字
*/
public class CircleTextView extends TextView {
/**
* 默认文字透明度
*/
private final int DEFAULT_ALPHA = 120;
/**
* 默认的旋转一周的时间
*/
private final int DEFAULT_ROTATION_TIME = 4000;
/**
* 文字旋转中心点坐标
*/
private float centerX, centerY;
/**
* 根据控件长宽测量的半径
*/
private float radius;
/**
* 文字画笔
*/
private TextPaint paint;
/**
* text alpha
*/
private int alpha = DEFAULT_ALPHA;
/**
* 是否顺时针旋转(默认逆时针)
*/
private boolean rotationCM = false;
/**
* 旋转一圈的时间
*/
private int rotationTime = DEFAULT_ROTATION_TIME;
private ObjectAnimator animator;
public CircleTextView(Context context) {
super(context);
}
public CircleTextView(Context context, AttributeSet attrs) {
super(context, attrs);
initDefineAttr(context, attrs);
initPaint();
}
public CircleTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initDefineAttr(context, attrs);
initPaint();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
radius = Math.min(w, h) / 2 - getTextSize();
centerX = w / 2;
centerY = h / 2;
super.onSizeChanged(w, h, oldw, oldh);
}
private void initDefineAttr(Context context, AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CircleTextView);
int count = array.getIndexCount();
for (int i = 0; i < count; i++) {
int attr = array.getIndex(i);
switch (attr) {
case R.styleable.CircleTextView_circleTextAlpha:
alpha = array.getInt(attr, DEFAULT_ALPHA);
if (alpha < 0 || alpha > 255)
alpha = DEFAULT_ALPHA;
break;
case R.styleable.CircleTextView_circleRotationCW:
rotationCM = array.getBoolean(attr, false);
break;
case R.styleable.CircleTextView_circleRotationTime:
rotationTime = array.getInt(attr, DEFAULT_ROTATION_TIME);
break;
default:
break;
}
}
array.recycle();
}
/**
* init Paint
*/
private void initPaint() {
paint = new TextPaint();
paint.setAntiAlias(true);
paint.setColor(getCurrentTextColor());
paint.setStyle(Paint.Style.FILL);
paint.setTextSize(getTextSize());
paint.setAlpha(alpha);
//文本渐变
// float textWidth = paint.measureText(getText().toString());
// Shader shader = new LinearGradient(0, 0, textWidth, 0, Color.TRANSPARENT,
// getCurrentTextColor(), Shader.TileMode.CLAMP);
// paint.setShader(shader);
}
@Override
protected void onDraw(Canvas canvas) {
drawCircleText(canvas);
}
/**
* draw circle text
*/
private void drawCircleText(Canvas canvas) {
Path path = new Path();
path.addCircle(centerX, centerY, radius, Path.Direction.CW);
canvas.drawTextOnPath(getText().toString(), path, 0, 0, paint);
}
public void doAnimation() {
if (rotationCM)
animator = ObjectAnimator.ofFloat(this, "rotation", 0f, 360f);
else
animator = ObjectAnimator.ofFloat(this, "rotation", 360f, 0f);
animator.setDuration(rotationTime);
animator.setRepeatMode(ValueAnimator.RESTART);
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.setInterpolator(new LinearInterpolator());
animator.start();
}
public void cancelAnimation() {
animator.cancel();
}
}
2、用到的自定义属性的attrs.xml内部的样式表declare-styleable声明
<!-- CircleTextView -->
<declare-styleable name="CircleTextView">
<!-- 文本透明度(0-255,数值越小越透明) -->
<attr name="circleTextAlpha" format="integer" />
<!-- 顺时针旋转文字 -->
<attr name="circleRotationCW" format="boolean" />
<!-- 旋转文字一圈的时间(毫秒) -->
<attr name="circleRotationTime" format="integer" />
</declare-styleable>
3、xml布局文件当中引用
<customview.CircleTextView
android:id="@+id/ctv_one"
android:layout_centerInParent="true"
android:layout_width="80dp"
android:layout_height="80dp"
android:text="殷疑曙霞染,巧类匣刀裁"
android:textColor="@color/colorWhite"
android:textSize="12sp"
app:circleTextAlpha="60"
app:circleRotationCW="true"
app:circleRotationTime="4000"/>
备注:
a、app:circleTextAlpha=“integer”为文字透明度,取值[0-255]
b、app:circleRotationCW=”boolean” 为是否为顺时针旋转
c、app:circleRotationTime=“long”为旋转一周用时,单位毫秒
4、activity中启动动画使用
//启动动画:调用CircleTextView的
doAnimation();
//取消动画:调用CircleTextView的
CircleTextView.cancelAnimation();