Good evening guys.
I'm currently designing a social networking client for Twitter and Facebook in Firemonkey FM2
(delphi) and I'm experiencing a frustrating issue. At present, I've only got the Twitter code in process, but the issue is related to the [re]drawing of visual objects.
I've created a custom-styled TListboxItem
layout in a stylebook consisting of multiple child components such as TText
, TButton
, and TImage
. I've already dealt with connecting to Twitter and retrieving feed details. Each item retrieved is added to a TListbox
and styled using my custom ListboxItem style layout.
Now, the issue is related to updating information on items in the list that aren't visible. For example, the items that are visible in the list without scrolling show their information correctly. Those that aren't visible besides the final item in the list have several of their details not set/visible. When I scroll the list downwards, and then back up, there's often 1 of the items that was originally visible will now be missing it's information.
To explain this a little more, i've got a TImage (known as photo) which is used to show the photo of the person who posted the 'tweet'. I've got the standard TText (known as text) used to show the contents/text of the tweet itself. I've got 2 buttons (known as Like and Share) used to perform their respective functions. I've then finally got another TText (known as NameDate) used to show the name of the tweeter and the date the tweet was posted.
I'm using this code to create the object and modify the data it shows;
for i := 0 to TwitObj.Statuses.Count-1 do
begin
FeedItem := TListBoxItem.Create(LBFeed);
FeedItem.Parent := LBFeed;
FeedItem.StyleLookup := 'FeedItem';
FeedItem.WordWrap := True;
FeedItem.StyledSettings := [TStyledSetting.ssFamily, TStyledSetting.ssSize, TStyledSetting.ssStyle, TStyledSetting.ssFontColor, TStyledSetting.ssOther];
NameDate := Feeditem.FindStyleResource('txtnamedate') as TText;
Photo := FeedItem.FindStyleResource('photo') as TImage;
Like := FeedItem.FindStyleResource('btnlike') as TButton;
Share := FeedItem.FindStyleResource('btnshare') as TButton;
Share.Text := 'Retweet';
Like.Text := 'Favorite';
NameDate.Text := Twitobj.Statuses.Items[i].User.Name +
'(@'+TwitObj.Statuses.Items[i].User.ScreenName+
') - '+DateTimeToStr(TwitObj.Statuses.Items[i].CreatedAt);
FeedItem.Text := TwitObj.Statuses.Items[i].Text;
begin
if DirectoryExists('imagecache\') = false then CreateDir('imagecache\');
if FileExists('imagecache\'+TwitObj.Statuses.Items[i].User.ScreenName+'.jpg') = False then
begin
try
rcv := TMemoryStream.Create;
GtPhoto.URL := TwitObj.Statuses.Items[i].User.ImageURL;
GtPhoto.RcvdStream := rcv;
GtPhoto.Get;
rcv.SaveToFile('imagecache\'+TwitObj.Statuses.Items[i].User.ScreenName+'.jpg');
finally
Rcv.Free;
end;
end;
end;
Photo.Bitmap.LoadFromFile('imagecache\'+TwitObj.Statuses.Items[i].User.ScreenName+'.jpg');
GTPhoto
is a standard ICS HTTP Client component, while TwitObj is my Twitter component. You can see that I'm saving the photo to a directory instead of streaming it. This was merely to check whether it was an issue with streams, but it's probably advisable to used a cache of some sort anyway.
The images download correctly, and the information for the relevant StyleResources in the custom ListBoxItem layout is updated as expected, but only for items that are visible without scrolling. If I scroll down the list, only the Text
of each item is correct, while the other resources which were set at runtime have returned to the way they're designed in the stylebook (i.e. blank text, image, etc).
Am I missing something here? I understand the design intents of Bitmaps were changed in XE3 for the sake of performance, but surely Embarcadero wouldn't have overlooked something like this. Surely it's not expected for us to create each item inside the parent at runtime (and thus dealing with alignments and such) instead of using a stylebook resource, is it?
Any assistance or insight would be greatly appreciated.
FireMonkey can load and unload the style for a control at any moment. It was rather lax with this in FM1, but under FM2, styling elements are removed when a control is not visible and reapplied when it becomes visible again (in order to conserve memory, mainly in preparation for Mobile Studio).
What you need to do is override the ApplyStyle method. In it look up and set data in your style elements. This will probably mean that your control(s) need to cache what will be passed to the style.
Also note that if you are caching references to style elements (i.e. what you get back from FindStyleResource) then these will be freed when the style is unloaded and your pointers will be invalid. If so, you need to override FreeStyle and nil any pointers you may have cached.