Android逐字符显示文字动画

发布于 2024-11-19 21:41:51 字数 150 浏览 4 评论 0 原文

任何人都知道执行动画的任何有效方法,所要做的就是逐个字符地显示文本?喜欢:

T
Th
Thi

这我
这是
...

等等。

谢谢!

Anyone knows any efficient method of perform an animation that what is has to do is to display a text, character by character? Like:

T
Th
Thi
This
This i
This is
...

And so on.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

望笑 2024-11-26 21:41:52

我使用了递归方法,还在单词之间添加了一点延迟以获得更多人性化的感觉。
将 textView 作为视图与文本一起发送,并发送“1”作为从头开始输入的长度

  private fun typingAnimation(view: TextView, text: String, length: Int) {
    var delay = 100L
    if(Character.isWhitespace(text.elementAt(length-1))){
        delay = 600L
    }
    view.text = text.substring(0,length)
    when (length) {
        text.length -> return
        else -> Handler().postDelayed({
            typingAnimation(view, text, length+1 )
        }, delay)
    }
}

I used a recursive method, also added a bit delay in between words to have more human feel.
Send the textView as view along with the text and send '1' as the length to type from start

  private fun typingAnimation(view: TextView, text: String, length: Int) {
    var delay = 100L
    if(Character.isWhitespace(text.elementAt(length-1))){
        delay = 600L
    }
    view.text = text.substring(0,length)
    when (length) {
        text.length -> return
        else -> Handler().postDelayed({
            typingAnimation(view, text, length+1 )
        }, delay)
    }
}
帅气称霸 2024-11-26 21:41:52

我知道现在已经太晚了,但仍然有人可能从 Google 到达这里。
事实上,我的应用程序也需要这样的东西,所以自己做了一个。
尝试一下 Fade-In TextView,它使每个角色都以平滑的 Alpha 动画出现。使用方法也相当简单。

在 XML 布局中

    <believe.cht.fadeintextview.TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:textColor="@android:color/black"

        app:letterDuration="250"/>

在 Activity/Fragment 中

believe.cht.fadeintextview.TextView textView = (believe.cht.fadeintextview.TextView) findViewById(R.id.textView);

textView.setLetterDuration(250); // sets letter duration programmatically
textView.isAnimating(); // returns current animation state (boolean)
textView.setText(); // sets the text with animation

更多信息

Fade-In TextView 库直接从原生 TextView 类继承其属性,该类意味着支持所有原生 TextView 方法。实际上没有任何限制,包括多行支持。该库还有一些自己的方法和属性,可以提供对视图的完全控制。

I know its too late now but someone still may arrive here from Google.
Actually, I too needed something like this for my app, so made one myself.
Try out Fade-In TextView, it makes every character appear with a smooth alpha animation. Usage is also quite simple.

In the XML layout

    <believe.cht.fadeintextview.TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:textColor="@android:color/black"

        app:letterDuration="250"/>

In the Activity/Fragment

believe.cht.fadeintextview.TextView textView = (believe.cht.fadeintextview.TextView) findViewById(R.id.textView);

textView.setLetterDuration(250); // sets letter duration programmatically
textView.isAnimating(); // returns current animation state (boolean)
textView.setText(); // sets the text with animation

Some more information

The Fade-In TextView library inherits its properties directly from the native TextView class, which means that all the native TextView methods are supported. There are practically no limitations including multiline support. The library also has some of its own methods and attributes which offer full control over the View.

花落人断肠 2024-11-26 21:41:52

理论上,


string text = "hello"
string temp = "h"

iterate: temp += if (text.length > temp.length) text[temp.length]; wait

您当然会在运行方法中进行迭代。

In theory it would be


string text = "hello"
string temp = "h"

iterate: temp += if (text.length > temp.length) text[temp.length]; wait

You will of course do the iterate in your runmethod.

究竟谁懂我的在乎 2024-11-26 21:41:52

上面提供的大多数解决方案都会引发各种错误。我猜解决方案已经很旧了。我偶然发现了这个 android studio 插件,它的作用就像魅力一样。

1.AutoTypeTextView的安装非常简单。只需在 build.gradle 中添加即可

编译'com.krsticdragan:autotypetextview:1.1'

2.添加一个新的命名空间,您将使用该命名空间添加 AutoTypeTextView 并使用其标签。

xmlns:attv="http://schemas.android.com/apk/res-auto"

因此您的根布局应该如下所示

;

  1. 将其添加到您的 xml 文件中。

    <代码>

只需执行这三个步骤,您就可以开始了。您可以查看此处的文档以了解更多详细信息

Most of the solutions provided above throw various errors. I guess the solutions are old. I stumbled on this android studio plugin and it works like charm.

1.Installation of AutoTypeTextView is preety simple. Just add in build.gradle

compile 'com.krsticdragan:autotypetextview:1.1'

2.Add a new namespace which you will use for adding AutoTypeTextView and using its tags.

xmlns:attv="http://schemas.android.com/apk/res-auto"

Hence your root layout should look like this

<?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:attv="http://schemas.android.com/apk/res-auto"

  1. Add this to your xml file.

    <com.dragankrstic.autotypetextview.AutoTypeTextView
    android:id="@+id/lblTextWithoutMistakes"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    attv:animateTextTypeWithoutMistakes="Hello World!" />

With just these three steps you are good to go. You can check out the documentation here for more details

冬天的雪花 2024-11-26 21:41:52

只是为了在使用 Kotlin 代码时添加 @Devunwired 的答案,
我改变了(在 animateText 函数中):
mHandler.postDelayed(mRunnable,mDelay)mRunnable.run()

所以我的最后一个 Kotlin 类看起来像这样:

class TextViewAnimationComponent(context: Context,attributeSet: AttributeSet?) : TextView(context,attributeSet) {
    private var mHandler = Handler()
    private var mText:CharSequence = ""
    private var mIndex:Int = 0
    private var mDelay:Long = 500

    private val mRunnable = object: Runnable{
        override fun run() {
            text = mText.subSequence(0,mIndex++)
            if(mIndex <= mText.length){
                mHandler.postDelayed(this,mDelay)
            }
        }
    }

    fun animateText(mText:CharSequence){
        this.mText = mText
        mIndex = 0

        text = ""
        mHandler.removeCallbacks(mRunnable)
        mRunnable.run()
//        mHandler.postDelayed(mRunnable,mDelay)
    }

    fun setCharacterDelay(millis:Long){
        mDelay = millis
    }
}

另外,这是一个快速而肮脏的代码(仍在 Kotlin 中),没有子类化。
内部 Activity:

    private fun animateText(mText: CharSequence, delayMillis: Long, postFunction:() -> Unit){
        var mIndex = 0

        val runnable = object : Runnable {
            override fun run() {

                // RunRunnable is a boolean flag; used in case you want to interrupt the execution
                if(runRunnable) {
                    if (mIndex <= mText.length) {

                        // change textViewSwitchStateValue with your own TextView id
                        textViewSwitchStateValue.text = mText.subSequence(0, mIndex++)
                        Handler().postDelayed(this, delayMillis)
                    } else {

                        // After all the characters finished animating; Clear the TextView's text and then run the postFunction
                        textViewSwitchStateValue.text = ""
                        postFunction()
                    }
                }
            }
        }
        runOnUiThread(runnable)

一个加载点动画的简单示例:
animateText(". . .", 400){switchStateON()}

Just to add to @Devunwired's answer when working with Kotlin code,
I changed (in animateText function):
mHandler.postDelayed(mRunnable,mDelay) to mRunnable.run()

so my final Kotlin class looks like this:

class TextViewAnimationComponent(context: Context,attributeSet: AttributeSet?) : TextView(context,attributeSet) {
    private var mHandler = Handler()
    private var mText:CharSequence = ""
    private var mIndex:Int = 0
    private var mDelay:Long = 500

    private val mRunnable = object: Runnable{
        override fun run() {
            text = mText.subSequence(0,mIndex++)
            if(mIndex <= mText.length){
                mHandler.postDelayed(this,mDelay)
            }
        }
    }

    fun animateText(mText:CharSequence){
        this.mText = mText
        mIndex = 0

        text = ""
        mHandler.removeCallbacks(mRunnable)
        mRunnable.run()
//        mHandler.postDelayed(mRunnable,mDelay)
    }

    fun setCharacterDelay(millis:Long){
        mDelay = millis
    }
}

Also, a quick and dirty code (still in Kotlin) without subclassing.
Inside Activity:

    private fun animateText(mText: CharSequence, delayMillis: Long, postFunction:() -> Unit){
        var mIndex = 0

        val runnable = object : Runnable {
            override fun run() {

                // RunRunnable is a boolean flag; used in case you want to interrupt the execution
                if(runRunnable) {
                    if (mIndex <= mText.length) {

                        // change textViewSwitchStateValue with your own TextView id
                        textViewSwitchStateValue.text = mText.subSequence(0, mIndex++)
                        Handler().postDelayed(this, delayMillis)
                    } else {

                        // After all the characters finished animating; Clear the TextView's text and then run the postFunction
                        textViewSwitchStateValue.text = ""
                        postFunction()
                    }
                }
            }
        }
        runOnUiThread(runnable)

A simple example for animating a loading dots:
animateText(". . .", 400){switchStateON()}

吃不饱 2024-11-26 21:41:52

是的,我知道已经有一段时间了,但我希望能够使用 ValueAnimator 以不同的方法帮助其他人

val text = "This is your sentence"
val textLength = text.length-1
val textView = findViewById<TextView>(R.id.sampleText)

ValueAnimator.ofInt(0, textLength).apply {
     var _Index = -1
     interpolator = LinearInterpolator()
     duration = 2000
     addUpdateListener { valueAnimator ->
         val currentCharIndex = valueAnimator.animatedValue as Int
         if (_Index != currentCharIndex) {
             val currentChar = text[currentCharIndex]
             textView.text = textView.text.toString().plus(currentChar.toString())
         }
        _Index = currentCharIndex
     }
}.start()

更新

我认为更合适,而不是上面的解决方案,当然如果你使用的是 RxJava

 Observable.range(0, textLength)
        .concatMap { Observable.just(it).delay(75, TimeUnit.MILLISECONDS) }
        .map { text[it].toString() }
        .subscribeOn(Schedulers.computation())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe { char ->
            println("Item: $char")
            textView.text = textView.text.toString().plus(char)
        }

Yep,I know it's been a while but I hope to help others with a different approach using ValueAnimator

val text = "This is your sentence"
val textLength = text.length-1
val textView = findViewById<TextView>(R.id.sampleText)

ValueAnimator.ofInt(0, textLength).apply {
     var _Index = -1
     interpolator = LinearInterpolator()
     duration = 2000
     addUpdateListener { valueAnimator ->
         val currentCharIndex = valueAnimator.animatedValue as Int
         if (_Index != currentCharIndex) {
             val currentChar = text[currentCharIndex]
             textView.text = textView.text.toString().plus(currentChar.toString())
         }
        _Index = currentCharIndex
     }
}.start()

Update

I think is more appropriate, rather solution above, of course if you are using RxJava

 Observable.range(0, textLength)
        .concatMap { Observable.just(it).delay(75, TimeUnit.MILLISECONDS) }
        .map { text[it].toString() }
        .subscribeOn(Schedulers.computation())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe { char ->
            println("Item: $char")
            textView.text = textView.text.toString().plus(char)
        }
昔梦 2024-11-26 21:41:52

这种方式非常简单并且可爱

fun TextView.animateTextWithUnderscore(mText: CharSequence, delayMillis: Long = 15) {
    text = null
    var index = 0
    val handler = Handler()

    val typewriterRunnable = object : Runnable {
        override fun run() {
            val newText = "${mText.subSequence(0, index)}_" <-- underscore is optioanal
            text = newText

            if (index < mText.length) {
                handler.postDelayed(this, delayMillis)
            }
            index++
        }
    }

    handler.postDelayed(typewriterRunnable, delayMillis)
}

This way is very easy and LOVELY

fun TextView.animateTextWithUnderscore(mText: CharSequence, delayMillis: Long = 15) {
    text = null
    var index = 0
    val handler = Handler()

    val typewriterRunnable = object : Runnable {
        override fun run() {
            val newText = "${mText.subSequence(0, index)}_" <-- underscore is optioanal
            text = newText

            if (index < mText.length) {
                handler.postDelayed(this, delayMillis)
            }
            index++
        }
    }

    handler.postDelayed(typewriterRunnable, delayMillis)
}
简美 2024-11-26 21:41:51

这可能不是最优雅的解决方案,但最简单的可能是 TextView 的快速子类,其中带有 Handler ,它会经常更新文本,直到显示完整的序列:

public class Typewriter extends TextView {

    private CharSequence mText;
    private int mIndex;
    private long mDelay = 500; //Default 500ms delay
    
    
    public Typewriter(Context context) {
        super(context);
    }
    
    public Typewriter(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
    private Handler mHandler = new Handler();
    private Runnable characterAdder = new Runnable() {
        @Override
        public void run() {
            setText(mText.subSequence(0, mIndex++));
            if(mIndex <= mText.length()) {
                mHandler.postDelayed(characterAdder, mDelay);
            }
        }
    };
    
    public void animateText(CharSequence text) {
        mText = text;
        mIndex = 0;
        
        setText("");
        mHandler.removeCallbacks(characterAdder);
        mHandler.postDelayed(characterAdder, mDelay);
    }
    
    public void setCharacterDelay(long millis) {
        mDelay = millis;
    }
}

然后,您可以在 Activity 中使用它,如下所示:

public class MyActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Typewriter writer = new Typewriter(this);
        setContentView(writer);

        //Add a character every 150ms
        writer.setCharacterDelay(150);
        writer.animateText("Sample String");
    }
}

如果您想要添加每个字母的一些动画效果,也许可以考虑子类化 TextSwitcher

This may not be the most elegant solution, but the simplest is probably a quick subclass of TextView with a Handler that updates the text every so often until the complete sequence is displayed:

public class Typewriter extends TextView {

    private CharSequence mText;
    private int mIndex;
    private long mDelay = 500; //Default 500ms delay
    
    
    public Typewriter(Context context) {
        super(context);
    }
    
    public Typewriter(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
    private Handler mHandler = new Handler();
    private Runnable characterAdder = new Runnable() {
        @Override
        public void run() {
            setText(mText.subSequence(0, mIndex++));
            if(mIndex <= mText.length()) {
                mHandler.postDelayed(characterAdder, mDelay);
            }
        }
    };
    
    public void animateText(CharSequence text) {
        mText = text;
        mIndex = 0;
        
        setText("");
        mHandler.removeCallbacks(characterAdder);
        mHandler.postDelayed(characterAdder, mDelay);
    }
    
    public void setCharacterDelay(long millis) {
        mDelay = millis;
    }
}

You can then use this in an Activity like so:

public class MyActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Typewriter writer = new Typewriter(this);
        setContentView(writer);

        //Add a character every 150ms
        writer.setCharacterDelay(150);
        writer.animateText("Sample String");
    }
}

If you want some animation effects with each letter added, perhaps look at subclassing TextSwitcher instead.

丶视觉 2024-11-26 21:41:51

不需要设置额外的类使用这个,这里电视是布局中的文本视图
只需调用

setCharacterDelay(150);
animateText("示例字符串");

private Handler mHandler = new Handler();
private Runnable characterAdder = new Runnable() {
    @Override
    public void run() {
        tv.setText(mText.subSequence(0, mIndex++));
        if(mIndex <= mText.length()) {
            mHandler.postDelayed(characterAdder, mDelay);
        }
    }
};

public void animateText(CharSequence text) {
    mText = text;
    mIndex = 0;

    tv.setText("");
    mHandler.removeCallbacks(characterAdder);
    mHandler.postDelayed(characterAdder, mDelay);

}

public void setCharacterDelay(long millis) {
    mDelay = millis;
}

No need to set an extra class Use this, here tv is a textview in your layout
just call

setCharacterDelay(150);
animateText("Sample String");

private Handler mHandler = new Handler();
private Runnable characterAdder = new Runnable() {
    @Override
    public void run() {
        tv.setText(mText.subSequence(0, mIndex++));
        if(mIndex <= mText.length()) {
            mHandler.postDelayed(characterAdder, mDelay);
        }
    }
};

public void animateText(CharSequence text) {
    mText = text;
    mIndex = 0;

    tv.setText("");
    mHandler.removeCallbacks(characterAdder);
    mHandler.postDelayed(characterAdder, mDelay);

}

public void setCharacterDelay(long millis) {
    mDelay = millis;
}
ˉ厌 2024-11-26 21:41:51

这个新的 Devunwired 副本与 xml 布局

    public class Typewriter extends TextView {

    private CharSequence mText;
    private int mIndex;
    private long mDelay = 500; //Default 500ms delay


    public Typewriter(Context context) {
        super(context);
    }

    public Typewriter(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    private Handler mHandler = new Handler();
    private Runnable characterAdder = new Runnable() {
        @Override
        public void run() {
            setText(mText.subSequence(0, mIndex++));
            if(mIndex <= mText.length()) {
                mHandler.postDelayed(characterAdder, mDelay);
            }
        }
    };

    public void animateText(CharSequence text) {
        mText = text;
        mIndex = 0;

        setText("");
        mHandler.removeCallbacks(characterAdder);
        mHandler.postDelayed(characterAdder, mDelay);
    }

    public void setCharacterDelay(long millis) {
        mDelay = millis;
    }
}

代码一起使用,

        textView = (Typewriter)findViewById(R.id.textView1);
    //Add a character every 150ms
    textView.setCharacterDelay(150);
    textView.animateText("Sample String");

然后在 classStart 中定义 textView

this new copy for Devunwired with xml layout

    public class Typewriter extends TextView {

    private CharSequence mText;
    private int mIndex;
    private long mDelay = 500; //Default 500ms delay


    public Typewriter(Context context) {
        super(context);
    }

    public Typewriter(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    private Handler mHandler = new Handler();
    private Runnable characterAdder = new Runnable() {
        @Override
        public void run() {
            setText(mText.subSequence(0, mIndex++));
            if(mIndex <= mText.length()) {
                mHandler.postDelayed(characterAdder, mDelay);
            }
        }
    };

    public void animateText(CharSequence text) {
        mText = text;
        mIndex = 0;

        setText("");
        mHandler.removeCallbacks(characterAdder);
        mHandler.postDelayed(characterAdder, mDelay);
    }

    public void setCharacterDelay(long millis) {
        mDelay = millis;
    }
}

code use

        textView = (Typewriter)findViewById(R.id.textView1);
    //Add a character every 150ms
    textView.setCharacterDelay(150);
    textView.animateText("Sample String");

then define textView in classStart

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文