Friday, July 31, 2015

Data Validation of Numeric Edit Text in Android

After spending some time to learn Material design, I felt it would be worth my time to take a break and focus on actually getting data onto my app and start progressing, then do a design pass later. I was churning my wheels trying to get all the character attributes set up and decided it was best to just get something on paper. I settled on a TableLayout to organize the labels from the character attributes and modifiers. I also did a bit of playing with design and cleanup and had something at least organized:

Overall this is rather respectable, it has a semi clean look and gives logical organization of the data. Am I in love with it? No, but it is something. The biggest challenge was getting the labels to stretch across the entirety of the view, instead of getting clumped. It took a bit of searching, but I found this attribute:

android:stretchColumns

Which made all the difference. It allowed me to get the desired spread. I likely should revisit the spacing size of the central Numeric EditText but since this is more placeholder I say sufficient for now.

The next big step was setting it so that when the user sets his Attribute value, it would auto update the modifier on the back end. The initial setup was not terrible, you hook up a "TextChanged" event handler, grab the values, update accordingly.

        void OnStrengthChanged (object sender, Android.Text.TextChangedEventArgs e)
{ 

     var numField = (EditText)sender;
     var value = int.Parse (numField.Text);
     characterData.SetSingleAttribute (new Attributes{ Strength = value });

     var mod = FindViewById<TextView> (Resource.Id.strengthMod);
     mod.Text = testCharacter.FinalAttributes.StrengthModifier.ToString ();

}

Overall, rather straight forward. I currently store Attributes as a single object that contains the individual properties for both Values and modifiers, basically a special array container with some validation inside. "characterData" is my storage for all applicable data. All of that is defined in my shared PCL. I think this is an area that could use a refactor. Currently my SetSingleAttribute is something like this:

        public void SetSingleAttribute(Attributes attributes)
        {
            baseAttributes.Strength = attributes.Strength == 0 ? baseAttributes.Strength : attributes.Strength;
            baseAttributes.Dexterity = attributes.Dexterity == 0 ? baseAttributes.Dexterity : attributes.Dexterity;
            baseAttributes.Constitution = attributes.Constitution == 0 ? baseAttributes.Constitution : attributes.Constitution;
            baseAttributes.Intelligence = attributes.Intelligence == 0 ? baseAttributes.Intelligence : attributes.Intelligence;
            baseAttributes.Wisdom = attributes.Wisdom == 0 ? baseAttributes.Wisdom : attributes.Wisdom;
            baseAttributes.Charisma = attributes.Charisma == 0 ? baseAttributes.Charisma : attributes.Charisma;

            baseAttributes = baseAttributes - Race.BonusAttributes;
        }







Basically I find the attribute that has been modified as all the others have been nulled out. I need to spend some more time on this, especially once I implement racial and feat bonuses. For now, it gets things moving forward while I block out all the data.

One challenge that I ran into was editing attribute values. The default behavior when clicking these fields (as they are just text fields) is to allow the user to edit the entry. To handle the scenario where a user deletes the existing values, I was running into an awkward case of trying to convert an empty string to a number, which does not work very well, and left an unintuitive experience. What I did to solve it was set the fields "Hint" parameter:

strValue.Hint = "8"; 

Then you get a nice greyed out sample field, without disrupting your flow:
As you can see, there is a nice greyed entry, more intuitive.
This is definitely coming along well. For some preliminary data validation I also set maxLength to 2 to prevent numbers larger than 2 digits. Ideally I  should limit to something like 6-20 as per the rules, but it is a start. As a note, a more complete complete implementation would use either a custom class of EditText or InputFilters.


1 comment: