Scroller

v0.0.10

v0.0.10StableMobStatelessApache-2.0
Installation mix mishka.ui.gen.mob scroller
Source View Source

The Mob Scroller in Mishka Chelekom is a horizontal rail with previous and next arrows for iOS and Android screens built with Mob. It is the native port of the headless Scroller.

Overview of the Mob Scroller component for iOS and Android

The rail is the Mob Scroll Area, Mob's native scroll view, which already has momentum and a scrollbar. Scroller adds a pair of arrow buttons under it, aligned to the right. Put the rail's items in a Row and pass them as children.

The arrows need a screen to work. Moving a live widget is a side effect that the screen performs, and a render function cannot express it. So Scroller renders the rail and the arrows, and sends on_prev and on_next to the screen. The handlers call nudge/3, which reads the rail's current offset and drives the native scroll view to a new one.

The offset lives in the native widget, so there is nothing to assign and nothing re-renders. Give Scroller an id so nudge/3 can find the rail. An arrow without a handler renders disabled.

Generate the scroller component

Run this from your Mob app's root to add the component to lib/<app>/components/:

bash
mix mishka.ui.gen.mob scroller

The generator registers the <Scroller> tag so you can use it in ~MOB markup. It also generates the Action Icon and Scroll Area components that Scroller uses. The examples on this page use the mishka_ prefix of the showcase app (--module-prefix mishka_), so the tag is <MishkaScroller>. Without a prefix the tag is <Scroller>.

Scroller with previous and next arrows

The arrows move the rail, so a user can press one instead of swiping. height sets the rail height.

Scrolling is a side effect on a live widget, so the handlers assign nothing and nudge/3 does the work. It scrolls by 80 percent of the visible width by default, which leaves a sliver of the previous tile on screen.

Scroller with previous and next arrows

Scroller card with a rail of three tiles, white, near black and white, above two small arrow buttons and the line Arrow taps: 0
A horizontal rail of gray and violet tiles shifted left with arrows at its ends and the line Arrow taps: 1.

Left: the example as it loads. Right: after a tap. The arrows move the rail, so you do not have to swipe.

elixir
<MishkaScroller id="gallery" on_prev={:back} on_next={:fwd} height={76}>
  {[rail()]}
</MishkaScroller>

# Scrolling is a side effect on a live widget, so there is no assign to
# set and nothing re-renders — nudge/3 reads the rail's current offset
# and drives the native scroll view to a new one.
def handle_info({:tap, :fwd}, socket) do
  MishkaScroller.nudge("gallery", :next)
  {:noreply, socket}
end

def handle_info({:tap, :back}, socket) do
  MishkaScroller.nudge("gallery", :prev)
  {:noreply, socket}
end

Props

PropTypeDefaultDescription
idstringnilRegisters the scroller so it can be addressed. The arrows get the test tags <id>-prev and <id>-next.
on_prev, on_nextevent tagNoneSent as {:tap, tag} from the arrows.
controlsbooleantrueWhether to show the arrows. Only false hides them.
heightnumbernilRail height.
spacenumber8Gap between the rail and the arrows.

nudge/3

nudge(id, direction, opts) scrolls the rail with that id one step. direction is :prev or :next. The :step option sets the distance and defaults to 80 percent of the visible width. It returns :ok, :unsupported when the platform has no scroll function, or {:error, reason} when no rail is registered under id.

Events

Your screen receives {:tap, tag} in handle_info/2 from each arrow, with the tag you set in on_prev or on_next.

elixir
def handle_info({:tap, :fwd}, socket) do
  MishkaScroller.nudge("gallery", :next)
  {:noreply, socket}
end

def handle_info({:tap, :back}, socket) do
  MishkaScroller.nudge("gallery", :prev)
  {:noreply, socket}
end

Differences from the web component

These parts of the headless Scroller are not ported:

  • scroll_by. Use the :step option of nudge/3 instead, because the pixel step belongs to the screen's scroll call.
  • prev_label and next_label, the aria labels of the arrows.
  • The *_class attributes.