在 TextView 上动画删除线

问题描述 投票:0回答:5

我一直在搜索如何对 TextView 上的删除线效果进行动画处理,但没有结果。我在论坛和 StackOverflow 上得到的唯一信息是:

some_text_view.setPaintFlags(some_text_view.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG)

我想要做的是,像 Play 商店上的待办事项应用程序一样设置删除线效果的动画,例如Any.do 在从左到右滑动的项目上有它。

android animation textview swipe strikethrough
5个回答
4
投票
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

}


3
投票

您有几个选择:

  • 扩展 TextView 并创建一个自定义视图,检查是否设置了 STRIKE_THRU_TEXT_FLAG 并触发一个动画,该动画将在文本上绘制一条小线,并在动画的每一帧上增加其宽度。

  • 使用一个空视图并将其放置在 TextView 上(使用relativelayout、framelayout等)。确保该视图的尺寸与您的 TextView 完全匹配。然后按照与之前相同的策略对该视图进行动画处理:在视图中心绘制一条水平线,其宽度在动画的每一帧处递增。

如果你想了解动画本身,那么你可以查找AnimatorAnimatorSet等及其相关指南


3
投票

我用这种方法制作了删除线动画:

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();
}

0
投票
// 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;
}
}

0
投票

基于@oferiko的回答,罢工动画:

private static ValueAnimator startStrikeThruAnimation(TextView textView, int duration){

    final SpannableString span = new SpannableString(textView.getText());
    final StrikethroughSpan strikeSpan = new StrikethroughSpan();
    final ValueAnimator animator = ValueAnimator.ofInt(textView.getText().length());

    animator.setDuration(duration);
    animator.addUpdateListener(valueAnimator -> {
        span.setSpan(strikeSpan, 0, (int) valueAnimator.getAnimatedValue(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        textView.setText(span);
        textView.invalidate();
    });

    animator.start();
    return animator;
}

对于反向动画:

private static ValueAnimator reverseStrikeThruAnimation(TextView textView, int duration){

    final CharSequence originalText = textView.getText();
    final Spannable span = new SpannableString(originalText);
    final StrikethroughSpan strikeSpan = new StrikethroughSpan();
    final ValueAnimator animator = ValueAnimator.ofInt(originalText.length(), 0);

    // Remove existing strike-through span if present
    StrikethroughSpan[] existingSpans = span.getSpans(0, span.length(), StrikethroughSpan.class);
    for (StrikethroughSpan existingSpan : existingSpans) {
        span.removeSpan(existingSpan);
    }

    animator.setDuration(duration);
    animator.addUpdateListener(animation -> {
        int animatedValue = (int) animation.getAnimatedValue();
        span.setSpan(strikeSpan, 0, animatedValue, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        textView.setText(span);
        textView.invalidate();
    });

    animator.start();
    return animator;
}

用途:

startStrikeThruAnimation(sampleTextView, 150);
reverseStrikeThruAnimation(nicknameTextView, 150);
© www.soinside.com 2019 - 2024. All rights reserved.