我一直在寻找很多关于如何将 TextView 上的删除线效果设置为没有结果的动画。我在论坛和 StackOverflow 上得到的唯一东西是:
some_text_view.setPaintFlags(some_text_view.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG)
我想要做的是,像在 Play Store 上的待办事项应用程序中一样为删除线效果设置动画,例如 Any.do 将它放在从左到右滑动的项目上。
我一直在寻找很多关于如何将 TextView 上的删除线效果设置为没有结果的动画。我在论坛和 StackOverflow 上得到的唯一东西是:
some_text_view.setPaintFlags(some_text_view.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG)
我想要做的是,像在 Play Store 上的待办事项应用程序中一样为删除线效果设置动画,例如 Any.do 将它放在从左到右滑动的项目上。
你有几个选择:
扩展 TextView 并创建一个自定义视图,该视图检查是否设置了 STRIKE_THRU_TEXT_FLAG 并触发动画,该动画将在文本上绘制一条小线,在动画的每一帧上增加它的宽度。
使用一个空视图并将其放置在您的 TextView 上(使用 RelativeLayout、FrameLayout 等)。确保此视图的尺寸与您的 TextView 完全匹配。然后按照与之前相同的策略为该视图设置动画:在视图的中心绘制一条水平线,其宽度在动画的每一帧处递增。
如果您想了解动画本身的制作方法,您可以查看Animator、AnimatorSet等及其相关指南。
我使用这种方法制作删除线动画:
private void animateStrikeThrough1(final TextView tv) {
final int ANIM_DURATION = 1000; //duration of animation in millis
final int length = tv.getText().length();
new CountDownTimer(ANIM_DURATION, ANIM_DURATION/length) {
Spannable span = new SpannableString(tv.getText());
StrikethroughSpan strikethroughSpan = new StrikethroughSpan();
@Override
public void onTick(long millisUntilFinished) {
//calculate end position of strikethrough in textview
int endPosition = (int) (((millisUntilFinished-ANIM_DURATION)*-1)/(ANIM_DURAT [ION/length));
endPosition = endPosition > length ?
length : endPosition;
span.setSpan(strikethroughSpan, 0, endPosition,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.setText(span);
}
@Override
public void onFinish() {
}
}.start();
}
private fun TextView.startStrikeThroughAnimation(): ValueAnimator {
val span = SpannableString(text)
val strikeSpan = StrikethroughSpan()
val animator = ValueAnimator.ofInt(text.length)
animator.addUpdateListener {
span.setSpan(strikeSpan, 0, it.animatedValue as Int, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
text = span
invalidate()
}
animator.start()
return animator
}
private fun TextView.reverseStrikeThroughAnimation(): ValueAnimator {
val span = SpannableString(text.toString())
val strikeSpan = StrikethroughSpan()
val animator = ValueAnimator.ofInt(text.length, 0)
animator.addUpdateListener {
span.setSpan(strikeSpan, 0, it.animatedValue as Int, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
text = span
invalidate()
}
animator.start()
return animator
}
// Created by kot32 on 2017/10/26.
public class AnimationText extends TextView {
private boolean isAnimationStarted;
private float targetLength;
private float totalLength;
private Paint strikePaint;
private float startY;
//should always show Strike-Through
private boolean isDeleted;
public AnimationText(Context context, AttributeSet attrs) {
super(context, attrs);
strikePaint = new Paint();
strikePaint.setColor(Color.BLACK);
strikePaint.setAntiAlias(true);
strikePaint.setStyle(Paint.Style.FILL_AND_STROKE);
strikePaint.setStrokeWidth(5);
}
public AnimationText(Context context) {
super(context);
strikePaint = new Paint();
strikePaint.setColor(Color.BLACK);
strikePaint.setAntiAlias(true);
strikePaint.setStyle(Paint.Style.FILL_AND_STROKE);
strikePaint.setStrokeWidth(5);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isAnimationStarted) {
//画线
canvas.drawLine(0, startY, targetLength, startY, strikePaint);
}
if (isDeleted && !isAnimationStarted) {
canvas.drawLine(0, startY, totalLength, startY, strikePaint);
}
}
public void startStrikeThroughAnimation() {
totalLength = getWidth();
startY = (float) getHeight() / 2;
isAnimationStarted = true;
//利用动画逐渐画出一条删除线
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(this, "targetLength", 0, totalLength);
objectAnimator.setInterpolator(new AccelerateInterpolator());
objectAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
isAnimationStarted = false;
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
objectAnimator.setDuration(300);
objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
invalidate();
}
});
objectAnimator.start();
postInvalidate();
}
public void setDeleted(boolean deleted) {
isDeleted = deleted;
totalLength = getWidth();
}
public float getTargetLength() {
return targetLength;
}
public void setTargetLength(float targetLength) {
this.targetLength = targetLength;
}
}