Fudley 9 Posted Tuesday at 02:32 PM (edited) FMX-Android-D12 Scroll TListbox selected item into view What I've tried (where lb is a TListbox and newindex is the new itemindex): 1. newindex := lb.selected.index; lb.scrollby(0.0,lb.itemheight*newindex) 2. oldindex := lb.ItemIndex; rowheight := lb.Selected.Height; lb.ViewportPosition := PointF(0,rowheight*oldindex) ; 3. lb.ScrollToItem(lb.Selected); Neither of these work. Please advise. Much thanks. Edited Tuesday at 02:37 PM by Fudley added scrolltoitem Share this post Link to post
Fudley 9 Posted Thursday at 01:03 PM Here's what Claude (the a.i.) suggested when I asked this question (and #2 does work best on android): ------------------------------ // Solution 1: Using ScrollToItem with proper timing procedure ScrollSelectedItemIntoView_Method1(lb: TListBox); begin if (lb.Selected <> nil) then begin // Use TThread.Queue to ensure the UI is updated before scrolling TThread.Queue(nil, procedure begin lb.ScrollToItem(lb.Selected); end); end; end; // Solution 2: Manual viewport positioning (most reliable) procedure ScrollSelectedItemIntoView_Method2(lb: TListBox); var ItemTop, ItemBottom, ViewportTop, ViewportBottom: Single; NewViewportY: Single; begin if (lb.Selected <> nil) and (lb.Count > 0) then begin // Get the selected item's position ItemTop := lb.Selected.Position.Y; ItemBottom := ItemTop + lb.Selected.Height; // Get current viewport bounds ViewportTop := lb.ViewportPosition.Y; ViewportBottom := ViewportTop + lb.Height; // Calculate new viewport position if needed NewViewportY := ViewportTop; // If item is above viewport, scroll up if ItemTop < ViewportTop then NewViewportY := ItemTop // If item is below viewport, scroll down else if ItemBottom > ViewportBottom then NewViewportY := ItemBottom - lb.Height; // Apply the new viewport position if NewViewportY <> ViewportTop then lb.ViewportPosition := PointF(0, NewViewportY); end; end; // Solution 3: Using item index with proper calculations procedure ScrollSelectedItemIntoView_Method3(lb: TListBox); var ItemIndex: Integer; ItemY: Single; ViewportHeight: Single; begin if (lb.Selected <> nil) then begin ItemIndex := lb.Selected.Index; ViewportHeight := lb.Height; // Calculate the Y position of the item ItemY := ItemIndex * lb.ItemHeight; // Check if item is outside viewport if (ItemY < lb.ViewportPosition.Y) or (ItemY + lb.ItemHeight > lb.ViewportPosition.Y + ViewportHeight) then begin // Center the item in the viewport lb.ViewportPosition := PointF(0, ItemY - (ViewportHeight / 2) + (lb.ItemHeight / 2)); end; end; end; // Solution 4: Enhanced method with smooth scrolling option procedure ScrollSelectedItemIntoView_Method4(lb: TListBox; SmoothScroll: Boolean = False); var ItemRect: TRectF; ViewportRect: TRectF; TargetY: Single; begin if (lb.Selected <> nil) then begin // Get item bounds ItemRect := lb.Selected.BoundsRect; // Get viewport bounds ViewportRect := RectF(0, lb.ViewportPosition.Y, lb.Width, lb.ViewportPosition.Y + lb.Height); // Check if item is fully visible if not ViewportRect.Contains(ItemRect) then begin // Calculate target scroll position if ItemRect.Top < ViewportRect.Top then TargetY := ItemRect.Top else if ItemRect.Bottom > ViewportRect.Bottom then TargetY := ItemRect.Bottom - lb.Height else TargetY := lb.ViewportPosition.Y; // Ensure we don't scroll beyond content bounds TargetY := Max(0, Min(TargetY, lb.ContentBounds.Height - lb.Height)); if SmoothScroll then begin // Smooth scroll using animation lb.AniCalculations.Animation := True; lb.AniCalculations.TouchTracking := []; lb.ViewportPosition := PointF(0, TargetY); end else begin // Immediate scroll lb.ViewportPosition := PointF(0, TargetY); end; end; end; end; // Usage examples: procedure TForm1.Button1Click(Sender: TObject); begin // Select an item programmatically if ListBox1.Count > 5 then begin ListBox1.ItemIndex := 5; // Then scroll it into view using any of the methods above ScrollSelectedItemIntoView_Method2(ListBox1); end; end; // Alternative: Create a helper method in your form procedure TForm1.SelectAndScrollToItem(lb: TListBox; ItemIndex: Integer); begin if (ItemIndex >= 0) and (ItemIndex < lb.Count) then begin lb.ItemIndex := ItemIndex; // Use a small delay to ensure selection is processed TThread.CreateAnonymousThread(procedure begin TThread.Synchronize(nil, procedure begin ScrollSelectedItemIntoView_Method2(lb); end); end).Start; end; end; // For Android-specific optimizations, you might want to disable animations // during scrolling to improve performance: procedure OptimizeForAndroid(lb: TListBox); begin lb.AniCalculations.Animation := False; lb.AniCalculations.TouchTracking := []; end; Key Points: Method 2 is the most reliable - it manually calculates viewport positioning and works consistently across different Android devices. Timing is crucial - Sometimes you need to use TThread.Queue or TThread.Synchronize to ensure the UI has updated before scrolling. Your original attempts failed because: ScrollBy doesn't work well with viewport positioning Direct ViewportPosition assignment needs proper bounds checking ScrollToItem can be unreliable without proper timing Android-specific considerations: Disable animations during programmatic scrolling for better performance Consider the device's screen density and scaling factors Test on different Android versions and screen sizes Recommended approach: Use Method 2 for most cases, or Method 4 if you want smooth scrolling. For Android deployment, consider disabling animations during programmatic scrolling to improve performance. The key difference from your attempts is proper bounds checking and ensuring the viewport position is calculated relative to the actual item positions rather than just multiplying by item height.RetryClaude can make mistakes. Please double-check responses. Share this post Link to post