Wednesday, December 31, 2008

listView with background

hello,


I had some questions about my issue with listView (here).

So I will make it clear :
When you use a listView with a background, you must use
android:cacheColorHint="#00000000"


Not to have any display problem !

Sunday, December 28, 2008

Numeric only editText

Based on what we have done yesterday (here ), it's very easy to limit our EditText to whatever we want !

And a common application would be to implement a numeric only editText :

Here's a first int version :

editEntryView.addTextChangedListener
(
new TextWatcher()
{
String CurrentWord;
private boolean IsValid( CharSequence s )
{
for ( int i = 0; i < s.length(); i ++ )
{
if ( !Character.isDigit( s.charAt(i)))
return false;
}
return true;
}
public void afterTextChanged(Editable s)
{
}
public void beforeTextChanged(CharSequence s, int start, int count, int after)
{
CurrentWord = s.toString();
}
public void onTextChanged(CharSequence s, int start, int before, int count)
{
if( !IsValid(s) )
{
editEntryView.setText(CurrentWord);
editEntryView.setSelection( start );
}
}
}
);


That simple !

And if you want any decimal numeric, just write another IsValid method :

private boolean IsValid( CharSequence s )
{
// special autorization for empty field
if (s.length() == 0)
return true;
// special autorization for '.', in order to enter .5
if (s.length() == 1 && s.charAt(0) == '.')
return true;
try
{
Double.parseDouble( s.toString() );
return true;
}
catch( Exception e)
{
return false;
}
}

We just have to be careful for special cases like the empty field, or just a dot ( this is the needed transition to enter something like .5 ).

And we must take into account those special cases when we will validate the entry.

Saturday, December 27, 2008

EditView with limited number of character, the end ?

I was still not completely OK with the last version.
In particular, when reaching the number of character limit while entering letters in the middle of the word, the behavior was not really natural : the new letter is added and the last letter of the words are erased !

So I had to find something better !

As I was entering the TextWatcher realm, I felt I could use it more to reach my goal : I want that reaching the character limit prevent any new character to be entered !

the new solution : saving the word before it is altered, then restoring the saved word if it is not Ok after being changed.

Here we go:

editEntryView.addTextChangedListener
(
new TextWatcher()
{
String CurrentWord;
public void afterTextChanged(Editable s)
{
}
public void beforeTextChanged(CharSequence s, int start, int count, int after)
{
CurrentWord = s.toString();
}
public void onTextChanged(CharSequence s, int start, int before, int count)
{
if( s.length() > MAX_CHAR )
{
EditText NameView = (EditText ) editEntryView.findViewById( R.id.PlayerName );
NameView.setText(CurrentWord);
}
}
}
);



This is good, the behaviour is OK, but... there is still a 'but' :
I don't replace the caret at the proper place. I could do the same trick I did last time : get the previous caret pos before the setText, and set it after, but this is still wrong : in this case, the caret place will take into account the rejected letter, so it will be moved one letter on the right.
I could still set the caret at the last pos minus one. But what will happen when there is a copy and paste feature ( does it already exist ? ), and several letters have been added at the same time ?

The solution seems cleaner, and is simpler : I use the start parameter given to the onTextChanged method. This parameter tells us the place where the word has been changed : this is the place I want to put the caret back.
So here's my final version, and I think I completely happy with it :

editEntryView.addTextChangedListener
(
new TextWatcher()
{
String CurrentWord;
public void afterTextChanged(Editable s)
{
}
public void beforeTextChanged(CharSequence s, int start, int count, int after)
{
CurrentWord = s.toString();
}
public void onTextChanged(CharSequence s, int start, int before, int count)
{
if( s.length() > MAX_CHAR )
{
editEntryView.setText(CurrentWord);
editEntryView.setSelection( start );
}
}
}
);

Enjoy !

Thursday, December 25, 2008

EditText, Sligh return !

First of all, merry Christmas to everyone !!!

That's said, let's get back to the EditText.

I've written a blog entry on how to make a EditText with a limited number of characters ( there )
It works by intercepting the key pressed event, and deciding whether to use the new entered letter or not.
It's all good and working, but I read on the forum that that was not the best of the solutions !
Actually, it's intercepting the physical keyboard entry at the view level, and it is not right. The most important thing is : when the software keyboard is out, it won't work anymore...
So I restarted to work on it, and used a the 'addTextChangedListener' listener, in order to detect when the text was changed, whoever had changed it.
This sound much more right.
So I started with something like that :

editEntryView.addTextChangedListener
(
new TextWatcher()
{
public void afterTextChanged(Editable s)
{
}
public void beforeTextChanged(CharSequence s, int start, int count, int after)
{
}
public void onTextChanged(CharSequence s, int start, int before, int count)
{
if( s.length() > 8 )
{
EditText NameView = (EditText ) editEntryView.findViewById( R.id.PlayerName );
String TextContent = NameView.getText().toString();
if ( TextContent.length() > 8 )
{
TextContent = TextContent.substring(0, 8 );
NameView.setText(TextContent);
NameView.setSelection( currentCarretPos );
}
}
}
}
);


That was a good start.
But there is still a issue with this code :
If I reach the character limit, and execute the NameView.SetText code, it puts the caret before the first character of the entry !
Imagine you're writing your name in this edit text, and suddenly, some characters disappear, and you're now typing at the start of your Name.

Not a very good experience !

I had to change that !
So i decided to replace the caret, just where it was before the change :
There is not such a thing as a caret, in the Android world, but there is a selection, and it looks like it's ok for what I want.
Here is what I came up with :

public void onTextChanged(CharSequence s, int start, int before, int count)
{
if( s.length() > 8 )
{
EditText NameView = (EditText ) editEntryView.findViewById( R.id.PlayerName );
int currentCarretPos = NameView.getSelectionStart();
String TextContent = NameView.getText().toString();
if ( TextContent.length() > 8 )
{
TextContent = TextContent.substring(0, 8 );
NameView.setText(TextContent);
if ( currentCarretPos > 8 )
currentCarretPos = 8;
NameView.setSelection( currentCarretPos );
}
}
}


Much better.
In a "normal" 'I'm entering my name' utilization, it works just fine !
I'm still not completely sure it is the way to go, in peculiar, when too much letters are entered from the middle of the word.
But it's enough for tonight( 3 AM looks like a good time to stop !)

Monday, December 22, 2008

Solution for the traceview problem !

At last, a good samaritan (fadden, whoever you are, big thanks !! ) helps me find the solution for my traceview problem.

And actually, I can't imagine how he find it !
The data created by the Debug.startMethodTracing / Debug.stopMethodTracing pair only works when the debugger is NOT attached !

You can still launch it from Eclipse, but when the data file is created eclipse can't be used as a debugger ( though it still can be used as a way to get the log !).

I launched Eclipse, then my application ( so it started the emulator - with a -sdcard optional parameter ).
Then terminate my application with Eclipse.

At this point, I could use the android interface to launch my application, go to the part I wanted to profile, and generate a valid .trace file !!
I could get it from my emulated SD Card with the Eclipse DDMS perspective, and launch traceview with this file, and at last have a correct result (and quite interesting... More on that latter )

Thanks again fadden !


On a side note, one could be a little worried by a debugger that produce a different behaviour - in this case a different file - than the without debugger case.
For now, I will just close my eyes, and hope it is just in this case ( famous last words again ? )