Tool SwipeCard (B4X Class) — Smooth Drag with Filtered Rotation

SwipeCard (B4X Class) — Smooth Drag with Filtered Rotation​


Email: Aliakrami13751@gmail.com


Platforms: B4A / B4i / B4J (B4X)
Version: 1.0.0


A lightweight, cross-platform swipeable card stack with buttery-smooth dragging and low-pass–filtered rotation. Perfect for Tinder-like UIs, card pickers, or stacked previews. Uses pure B4XView APIs and works in the Designer with helpful properties.



0_ECej87hPFC74RBon (1).gif




Features​


  • Smooth horizontal drag with throttled touch handling
  • Low-pass filtering for position & rotation (natural feel)
  • Configurable fling & snap durations
  • Stack layout with per-card offsets (X/Y) and rounded corners
  • Works with Layouts or existing Panels
  • Simple event model: LeftSwipe, RightSwipe, CenterRelease
  • Runtime setters for thresholds, durations, and stack size

Designer Properties​


Property (Key)TypeDefaultDescription
ThresholdPctFloat0.25Horizontal fraction of width required to trigger a swipe (clamped 0.05–0.9).
SnapDurationInt220Milliseconds to animate back to center when not swiped.
FlingDurationInt180Milliseconds to animate off-screen when swiped.
StackMaxInt3Max number of visible cards in the stack.
StackOffsetXInt (dip)3Horizontal offset between stacked cards.
StackOffsetYInt (dip)6Vertical offset between stacked cards.
CardCornerInt (dip)10Corner radius for each card panel.
CardBGColor0xFFFFFFFFCard background color.




Public API​


Adding Items​


n1:
' Add a layout file as a card (the layout fills the card)
SwipeCard1.AddLayout("CardProduct", "prod-123")

' Wrap an existing Panel (will be moved into the card)
SwipeCard1.AddPanel(SomePanel, "custom-01")

Stack / Threshold / Durations

n2:
SwipeCard1.SetStack(3, 4dip, 8dip)      ' maxVisible, dx, dy
SwipeCard1.SetThresholdPct(0.30)        ' 30% of width
SwipeCard1.SetDurations(220, 180)       ' snapMs, flingMs

Query / Remove / Clear

n3:
Log(SwipeCard1.Count)                   ' total items
Log(SwipeCard1.CurrentItemId)           ' id of the top card (or "")
Dim removed As Boolean = SwipeCard1.RemoveById("prod-123")
SwipeCard1.Clear                         ' removes all cards

Events​


The class raises up to three events (all with one String parameter: the card Id):


  • SwipeCard_LeftSwipe (Id As String)
  • SwipeCard_RightSwipe (Id As String)
  • SwipeCard_CenterRelease (Id As String)

Example:

n4:
Private Sub SwipeCard1_LeftSwipe (Id As String)
    Log($"Left → ${Id}"$)
    ' TODO: Dislike, skip, etc.
End Sub

Private Sub SwipeCard1_RightSwipe (Id As String)
    Log($"Right → ${Id}"$)
    ' TODO: Like, approve, etc.
End Sub

Private Sub SwipeCard1_CenterRelease (Id As String)
    Log($"Release (center) → ${Id}"$)
    ' Optional: snap-back finished
End Sub


Quick Start (B4XPages)​


  1. Add the class file SwipeCard.bas to your project.
  2. In B4XPages Main Page (B4XMainPage):


n5:
Sub Class_Globals
    Private Root As B4XView
    Private Swipe As SwipeCard
End Sub

Public Sub Initialize As Object
    Return Me
End Sub

Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Root.LoadLayout("MainPage")  ' Contains a Panel placeholder: pnlHost
    ' Or build in code:
    Swipe.Initialize(Me, "SwipeCard")
    Root.AddView(Swipe.mBase, 0, 0, Root.Width, Root.Height)

    ' Add cards
    For i = 1 To 5
        Swipe.AddLayout("CardItem", $"item-${i}"$)
    Next

    ' Optional tuning
    Swipe.SetStack(3, 4dip, 8dip)
    Swipe.SetThresholdPct(0.28)
    Swipe.SetDurations(200, 170)
End Sub

Private Sub Root_Resize (Width As Double, Height As Double)
    If Swipe.IsInitialized Then Swipe.mBase.SetLayoutAnimated(0, 0, 0, Width, Height)
End Sub

CardItem.bal tip: Design to fill parent. The class ensures the child view stretches to card bounds.




Usage Patterns​


1) Dynamic Data (e.g., Products, Profiles)​


n6:
For Each rec As Map In DataList
    ' Load same layout for each; bind labels/images inside that layout
    Swipe.AddLayout("CardProfile", rec.Get("id"))
Next

After AddLayout, you can access the child view via:

n7:
' Inside the class, child is Panel.GetView(0). Outside, prefer to bind in layout load events.

2) Removing / Skipping Specific Cards



n8:
If Swipe.RemoveById("custom-01") = False Then Log("Id not found!")


3) Programmatic “Like/Dislike”​


This class focuses on gesture-driven swipes. If you want programmatic swipe, you can either:


  • Trigger the animation by manually setting Panel.Left and calling the internal release logic (extend the class to expose a SwipeLeft/SwipeRight method), or
  • Simulate user flow by removing the top card and calling UpdateStack (simpler but no fling animation).

Example extension (inside class):

n9:
' Public method (optional): fling top programmatically to the right
Public Sub FlingRight
    If Items.Size = 0 Or CurrentIndex > Items.Size - 1 Or isAnimating Then Return
    Dim top As TItem = Items.Get(CurrentIndex)
    isAnimating = True
    top.Panel.SetLayoutAnimated(FlingDuration, mBase.Width + 50dip, top.Panel.Top, top.Panel.Width, top.Panel.Height)
    Sleep(FlingDuration)
    isAnimating = False
    RaiseEvent("RightSwipe", top.Id)
    top.Panel.Visible = False
    top.Panel.RemoveViewFromParent
    Items.RemoveAt(CurrentIndex)
    UpdateStack
End Sub

Performance Notes​


  • Images: Prefer pre-scaled images sized close to card bounds (avoid huge bitmaps on mobile).
  • Animations: Current defaults (FlingDuration=180, SnapDuration=220) feel snappy. Increase slightly on older devices.
  • Touch throttling: throttleMs=8 reduces event flood while maintaining smoothness.
  • Rotation cap: MaxRotation=12 degrees max; adjust if you want flatter/more dramatic tilt.
  • B4A Hardware Acceleration: Usually on by default—keep it enabled for smoother animation.



Compatibility​


  • B4A: Android 5.0+ recommended
  • B4i: iOS 12+ recommended
  • B4J: Works in principle; touch handling depends on your setup (mouse drag maps fine)



Troubleshooting​


Card doesn’t fill the container
Ensure the SwipeCard’s mBase is sized to its parent (use Base_Resize or set anchors in Designer). Your child layout should be “match parent”.


No events firing
Check that your subs match the event names:
<EventName>_LeftSwipe, <EventName>_RightSwipe, <EventName>_CenterRelease.


Laggy drag


  • Avoid heavy work during Touch MOVE.
  • Reduce image sizes or complex nested views in card layouts.
  • Slightly increase throttleMs to ~10–12.

I need vertical swipes
Current version supports horizontal swipes. For vertical, fork and adapt the drag axis (use Y instead of Left, and rotate around X/Z as desired).




Public Methods (Summary)​


  • AddLayout(LayoutFile As String, ItemId As String)
  • AddPanel(PanelToWrap As B4XView, ItemId As String)
  • RemoveById(Id As String) As Boolean
  • Clear
  • Count As Int
  • CurrentItemId As String
  • SetThresholdPct(p As Float)
  • SetDurations(snapMs As Int, flingMs As Int)
  • SetStack(maxVisible As Int, dx As Int, dy As Int)

Events:
<EventName>_LeftSwipe (Id As String)
<EventName>_RightSwipe (Id As String)
<EventName>_CenterRelease (Id As String)




Minimal Demo (Layout + Code)​


Designer:


  • Page layout with a placeholder Panel pnlHost.
  • Add the SwipeCard CustomView or add in code.

Code:


n10:
' In MainPage
Private Swipe As SwipeCard

Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Swipe.Initialize(Me, "SwipeCard")
    Root.AddView(Swipe.mBase, 0, 0, Root.Width, Root.Height)

    For i = 1 To 4
        Swipe.AddLayout("CardSimple", $"id-${i}"$)
    Next
End Sub

Sub SwipeCard_RightSwipe (Id As String)
    Log($"✅ Liked: ${Id}"$)
End Sub

Sub SwipeCard_LeftSwipe (Id As String)
    Log($"❌ Disliked: ${Id}"$)
End Sub

Sub SwipeCard_CenterRelease (Id As String)
    Log($"↩️ Returned: ${Id}"$)
End Sub

Changelog​


1.0.0


  • Initial public release
  • Smooth LPF drag/rotation
  • Stack offsets + rounded cards
  • Designer + runtime configuration







Support / Contact​


Questions, issues, or feature requests:
Email: Aliakrami13751@gmail.com

💖 Donate:

TRX: TZ9TsAv8R5KVrX1eNYRKZrAMUEiWF15fAP
BSC/ETH/POL: 0xF998991c13657aC9F6191b15aB8E56Bf531F8C2C
BTC: bc1q04en95hd5yx8du4c5saaj80pw6rhye7dgy2v75
SOL: 93uvax9FVNb12qz6Bt9zVGy6hq3A2U9WTvmTvqsHWbRX
 

Attachments

  • SwipeCard.bas
    8.6 KB · Views: 8
Top