Elad Katz - Cool Stories

Monday, May 4, 2009

Overcoming the AbsoluteLayout deprecation, Part Deux

Okay, so I fixed the bottom part as well - it was not fun...
first thing I did was to replace the absolutelayout to linearLayout
Surprisingly there were no compilation errors however when I tried running it, it crashed...

So I went about fixing it, but in order to explain the process I'm gonna have to give a little background, it's gonna be as short as possible, I swear!
The project I'm currently working on is a card game, and in it there is a method for redrawing the player's cards. It does this by going over the logical card objects and checking some properties and drawing them according to it. One of these properties is the "isSelected" status of the PlayingCard object. According to this property, we draw the card - if it is indeed selected - we show it as slightly (10px) above the rest of the cards, else, it is in line with the others.
One final thing to note is that this method is called after every action is done on any cards, and that this method is called and will henceforth be referred to as redrawHand().
The redrawHand() method used to draw the selected cards using absouluteLayout like this:
boolean isSelected = hand.isCardSelected(i);
android.view.ViewGroup.LayoutParams currentParams = cardView[i].getLayoutParams();
cardView[i].setLayoutParams(
new AbsoluteLayout.LayoutParams
(currentParams.width,currentParams.height,
((AbsoluteLayout.LayoutParams)currentParams).x,
isSelected ? 0 : 10));

basically, I would set the 'y' location (relative to it's container) to 0 or 10 according to the isSelected status.
Unfortunately, this is not possible in other layouts. and that's why the run failed on the first run after the change.
what I did next is try to use some of the properties inherited from LinearLayout to acheive the same result. I tried:
  • setting the Layout_gravity of the selected cards to top and the others to bottom
  • setting the Gravity of the selected cards to top and the others to bottom
    • (Ever wonder what the difference is between Layout_Gravity and Gravity? well, it's simple - Layout_Gravity is the gravity of the view in relation to it's parent and Gravity is the gravity of the contents of the view itself)
  • setting the bottom_padding to 10px for the selected cards
  • setting the layout_margin_bottom to 10px for the selected cards
  • setting the height to 10px bigger for the selected cards
  • and other fun stuff...
as you can imagine, none of these worked - most of them did the same thing - when one card is selected, the others appear selected as well - the cards go up as one...
after allot of digging and frustration i figured it out - the container for the cards was in a wrap content mode in layout height and when one of the cards was selected, all the cards filled the content of the parent and in effect went up. now I know this doesn't make a whole lot of sense now, but after a while you get used to these things and they start making sense...
So I managed to get it to work in the layout xml (was able to change the bottom margin for 2 cards and see them up) , but when it came to run-time that was a whole different story: for some strange reason - when I clicked on one of the cards, it did seem selected, but it would be the only one I could select - now this was really weird for a few reasons: a) the method worked with absoluteLayout and b) the behaviour was extremely strange: if I pick card 2 and then card 3, card 2 will pop up but 3 won't, and if I would want to show 3 as selected, i would have to click it again (to unselect it) and then unselect card 2 and then select card 3.
WTF???
after posting yet another question on the group I was told to use the container.requestLayout() method at the end of the redraw method. What this method does is basically invalidate the view so that on the next drawing cycle, it will appear as dirty and will have to be drawn again by the graphics engine. Now this all would make perfect sense if it werent for the fact that I have have been using this method for a whole bunch of other stuff and they worked and the fact that have something that's supposed to do just that - the container.invalidate() method.
Amazingly - this fixed it - I'm still not completly sure how this miracle occured but I'm gonna get to the bottom of it and let you know if there are requests for that.
so now it all works, and you are all encouraged to go the project site and look at the code - should be intersting...
http://code.google.com/p/bestcardgameever-android/
Enjoy!

No comments:

Post a Comment