如何更新TextView文本(解码文本效果)

本文关键字:文本 解码 何更新 TextView 更新 | 更新日期: 2023-09-27 18:14:19

我需要标题中提到的帮助。

我有一个计时器例程,它将更新标签的文本。这是一种解码文本效果,但当计时器例程执行时,它似乎不会更新。我正在使用c#。

MainActivity.cs

using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using System.Text;
using System.Timers;
using System.Linq;
namespace ValidateCreditCardNumber_Android
{
    [Activity (Label = "ValidateCreditCardNumber_Android", MainLauncher = true, Icon = "@drawable/icon")]
    public class MainActivity : Activity
    {
        EditText editText;
        DecodeTextView resultLabel;
        protected override void OnCreate (Bundle bundle)
        {
            base.OnCreate (bundle);
            // Set our view from the "main" layout resource
            SetContentView (Resource.Layout.Main);
            editText = FindViewById<EditText> (Resource.Id.editText);
            Button validateButton = FindViewById<Button> (Resource.Id.validateButton);
            resultLabel = FindViewById<DecodeTextView> (Resource.Id.resultLabel);
            editText.KeyListener = Android.Text.Method.DigitsKeyListener.GetInstance("0123456789" + System.Globalization.CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalDigits);
            validateButton.Click += OnNumberEntryCompleted;
        }
        void OnNumberEntryCompleted(object sender, EventArgs args)
        {
            var entry = editText;
            var resultText = "";
            if (Mod10Check (entry.Text)) {
//              resultLabel.SetTextColor(Android.Graphics.Color.White);
                resultText = "__VALID NUMBER";
            } else {
                resultText = "INVALID NUMBER";
            }
//          entry.Enabled = false;
//          resultLabel.AnimateText (true, resultText, 10);
            RunOnUiThread(() => resultLabel.AnimateText (true, resultText, 10));
        }
        public static bool Mod10Check(string creditCardNumber)
        {
            // Check whether input string is null or empty.
            if (string.IsNullOrEmpty(creditCardNumber)) {
                return false;
            }
            char[] charArray = creditCardNumber.ToCharArray();
            // 1. Starting with the check digit double the value of every other digit 
            // 2. If doubling of a number results in a two digits number, add up.
            //    the digits to get a single digit number. This will results in eight single digit numbers.
            // 3. Get the sum of the digits.
            int sumOfDigits = charArray.Where((e) => e >= '0' && e <= '9')
                .Reverse()
                .Select((e, i) => ((int)e - 48) * (i % 2 == 0 ? 1 : 2))
                .Sum((e) => e / 10 + e % 10);

            // If the final sum is divisible by 10, then the credit card number.
            // is valid. If it is not divisible by 10, the number is invalid.            
            return sumOfDigits % 10 == 0;
        }
    }
}

DecodeTextView.cs

using System;
using System.Text;
using System.Timers;
//using Android.Runtime;
using Android.Content;
using Android.Util;
namespace ValidateCreditCardNumber_Android
{
    public class DecodeTextView : Android.Widget.TextView
    {
        private readonly Timer _timerAnimate = new Timer();
        private TextDecodeEffect _decodeEffect;
        private bool _showing;
        private int _initGenCount;
        public int Interval
        {
            get { return (int)_timerAnimate.Interval; }
            set { _timerAnimate.Interval = value; }
        }
//      protected DecodeTextView(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
        public DecodeTextView(Context c, IAttributeSet args) : base(c, args)
        {
            _timerAnimate.Interval = 100;
            _timerAnimate.Elapsed += _timerAnimate_Tick;
        }
        public void AnimateText(bool show, string text, int initGenCount)
        {
            _initGenCount = initGenCount;
            _decodeEffect = new TextDecodeEffect(text) { TextVisible = !show };
            Text = _decodeEffect.Peek (DecodeMode.None);
            _showing = show;
            _timerAnimate.Start ();
        }
        private void _timerAnimate_Tick(object sender, EventArgs e)
        {
            if (_initGenCount != 0) {
                Text = _decodeEffect.GenerateNumberRange (Text.Length);
                _initGenCount--;
                return;
            }
            var decodeMode = _showing ? DecodeMode.Show : DecodeMode.Hide;
            var text = _decodeEffect.Peek (decodeMode);
            if (text == null) {
                _timerAnimate.Stop ();
            } else {
                Text = text;
            }
        }
    }
    public enum DecodeMode
    {
        None,
        Show,
        Numbers,
        Hide
    }
    class TextDecodeEffect
    {
        private int _visibleCount;
        private readonly Random _random = new Random ();
        public bool TextVisible
        {
            get { return _visibleCount == OriginalText.Length; }
            set { _visibleCount = value ? OriginalText.Length : 0; }
        }
        public string OriginalText { get; private set; }
        public TextDecodeEffect(string text)
        {
            OriginalText = text;
        }
        public string Peek(DecodeMode mode)
        {
            switch (mode) {
            case DecodeMode.Numbers:
                return GenerateNumberRange (OriginalText.Length);
            case DecodeMode.Hide:
                if (_visibleCount == 0)
                    return null;
                _visibleCount--;
                break;
            case DecodeMode.Show:
                if (_visibleCount == OriginalText.Length)
                    return null;
                _visibleCount++;
                break;
            }
            var text = GenerateNumberRange (OriginalText.Length - _visibleCount);
            text += OriginalText.Substring (OriginalText.Length - _visibleCount, _visibleCount);
            return text;
        }
        public string GenerateNumberRange(int count)
        {
            var SB = new StringBuilder ();
            for (int i = 0; i < count; i++)
                SB.Append(_random.Next(0, 10));
            return SB.ToString();
        }
    }
}

在这里你可以找到项目

请帮我解决这个问题:(谢谢。

如何更新TextView文本(解码文本效果)

这是一个线程问题,你只能在UI线程上更改UI元素,定时器回调_timerAnimate_Tick将在后台线程上执行。

你可以通过记录DecodeTextView的构造函数和它的_timerAnimate_Tick方法的线程ID来看到这一点:

public DecodeTextView(Context c, IAttributeSet args) : base(c, args)
{
    // ...
    Console.WriteLine ("DecodeTextView executing on thread: " + System.Threading.Thread.CurrentThread.ManagedThreadId);
}
private void _timerAnimate_Tick(object sender, EventArgs e)
{
    Console.WriteLine ("_timerAnimate_Tick executing on thread: " + System.Threading.Thread.CurrentThread.ManagedThreadId);
    // ...
}

将在日志输出中呈现以下内容:

DecodeTextView executing on thread: 1
_timerAnimate_Tick executing on thread: 6 

这可以通过使用Post方法在UI线程上改变DecodeTextViewText属性来修复:

private void _timerAnimate_Tick(object sender, EventArgs e)
{
    if (_initGenCount != 0) {
        Post (() => {
            Text = _decodeEffect.GenerateNumberRange (Text.Length);
        });
        _initGenCount--;
        return;
    }
    var decodeMode = _showing ? DecodeMode.Show : DecodeMode.Hide;
    var text = _decodeEffect.Peek (decodeMode);
    if (text == null) {
        _timerAnimate.Stop ();
    } else {
        Post (() => {
            Text = text;
        });
    }
}