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

时间:2015-09-23 18:53:53

标签: c# android xamarin textview xamarin.android

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

我有一个计时器例程,它将更新标签的文本。它是一种解码文本效果,但在执行定时器例程时似乎没有更新。我正在使用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();
        }
    }
}

Here you can found the project

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

1 个答案:

答案 0 :(得分:1)

这是一个线程问题,您只能更改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线程上Text的{​​{1}}属性即可解决此问题:

DecodeTextView