效果圖
備註:效果是四個自定義的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();