diff --git a/docs/resources/ui/widgets/composing-widgets/imgs/enable-infinite-list.avif b/docs/resources/ui/widgets/composing-widgets/imgs/enable-infinite-list.avif new file mode 100644 index 00000000..65712061 Binary files /dev/null and b/docs/resources/ui/widgets/composing-widgets/imgs/enable-infinite-list.avif differ diff --git a/docs/resources/ui/widgets/composing-widgets/imgs/gridview-with-vertical-scroll.avif b/docs/resources/ui/widgets/composing-widgets/imgs/gridview-with-vertical-scroll.avif new file mode 100644 index 00000000..b3c70f23 Binary files /dev/null and b/docs/resources/ui/widgets/composing-widgets/imgs/gridview-with-vertical-scroll.avif differ diff --git a/docs/resources/ui/widgets/composing-widgets/imgs/infinite-scroll-behind-the-scene.avif b/docs/resources/ui/widgets/composing-widgets/imgs/infinite-scroll-behind-the-scene.avif new file mode 100644 index 00000000..dda23745 Binary files /dev/null and b/docs/resources/ui/widgets/composing-widgets/imgs/infinite-scroll-behind-the-scene.avif differ diff --git a/docs/resources/ui/widgets/composing-widgets/imgs/pagination-variables.avif b/docs/resources/ui/widgets/composing-widgets/imgs/pagination-variables.avif new file mode 100644 index 00000000..3539b686 Binary files /dev/null and b/docs/resources/ui/widgets/composing-widgets/imgs/pagination-variables.avif differ diff --git a/docs/resources/ui/widgets/composing-widgets/imgs/pull-to-refresh-firestore.avif b/docs/resources/ui/widgets/composing-widgets/imgs/pull-to-refresh-firestore.avif new file mode 100644 index 00000000..7f1d8964 Binary files /dev/null and b/docs/resources/ui/widgets/composing-widgets/imgs/pull-to-refresh-firestore.avif differ diff --git a/docs/resources/ui/widgets/composing-widgets/imgs/scroll-to-action.avif b/docs/resources/ui/widgets/composing-widgets/imgs/scroll-to-action.avif new file mode 100644 index 00000000..45897ed9 Binary files /dev/null and b/docs/resources/ui/widgets/composing-widgets/imgs/scroll-to-action.avif differ diff --git a/docs/resources/ui/widgets/composing-widgets/list-grid.md b/docs/resources/ui/widgets/composing-widgets/list-grid.md index f16118af..5b14f5d5 100644 --- a/docs/resources/ui/widgets/composing-widgets/list-grid.md +++ b/docs/resources/ui/widgets/composing-widgets/list-grid.md @@ -3,136 +3,134 @@ title: Lists & Grids tags: [Layout Elements] sidebar_position: 2 --- -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -In FlutterFlow, `ListView` and `GridView` are versatile widgets designed for displaying lists and grids -of elements, respectively. Both are highly customizable and optimized for dynamic content displays, making them essential for any app that requires scrolling through a collection of items such as images, text, or interactive elements. +In FlutterFlow, `ListView` and `GridView` are versatile widgets designed for displaying lists and grids of elements, respectively. Both are highly customizable and optimized for dynamic content, making them essential for any app that requires scrolling through a collection of items such as images, text, or interactive elements. ## ListView Widget + ListView is a scrollable list of widgets arranged linearly. It is ideal for scenarios where items need to be displayed one after another, either **vertically or horizontally**. -It is particularly useful for long lists that need to be efficient; only the items visible on the -screen are rendered, enhancing performance for lists with a large number of elements. +It is particularly useful for efficiently rendering long lists. Only the items visible on the screen are rendered, enhancing performance for lists with many elements. -You can customize the ListView properties and functionalities, some are as follows: +You can customize the ListView using the following properties: ### Axis -Axis sets the orientation of the ListView. You can select either "Vertical" or - "Horizontal" depending on whether you want the list to scroll vertically or horizontally. +The **Axis** property sets the orientation of the ListView. Select **Vertical** or **Horizontal**, depending on how you want the list to scroll. ![listview-axis.png](../built-in-widgets/imgs/listview-axis.png) -### Spacing +### Spacing -- **Items Spacing:** This defines the space between individual items in the ListView. You can - specify the spacing in pixels. +- **Items Spacing:** Defines the space, in pixels, between individual items in the ListView. :::tip[Items Spacing vs Padding] -Prefer “Items Spacing” set on the parent row or column instead of padding on individual elements. This ensures consistency, especially on non-dynamically generated lists. +For static lists, set **Items Spacing** on the parent row or column instead of adding padding to individual elements. This helps maintain consistent spacing. ::: -- **Apply to Start & End:** When enabled, the item spacing will also be applied to the start and the - end of the ListView, adding a margin at the beginning and end of the list. This effectively adds padding at the start and end of the layout in addition to between the items. +- **Apply to Start & End:** Applies the item spacing to the beginning and end of the ListView, in addition to the spacing between items. -- **Start Spacing and End Spacing:** These properties allow you to set additional spacing at the - start and end of the ListView, respectively. This can be used to create padding around the list items that is separate from the spacing between the items. +- **Start Spacing and End Spacing:** Sets additional spacing at the beginning and end of the ListView independently from the spacing between items. -### Advanced Functionalities +### Advanced Properties {#advanced-functionalities} -- **Shrink Wrap:** When this property is enabled, the ListView will size itself to the total size of - its children, meaning it won’t take more space than necessary. This is useful for lists that do not need to be scrollable because they fit within their constraints. +- **Shrink Wrap:** When enabled, the ListView sizes itself to the combined size of its children, so it does not take up more space than necessary. This is useful for lists whose items fit within the available constraints. -- **Primary:** If set to true, the ListView will act as the primary scrolling view in the context. - This usually affects how the view interacts with other scrolling views and whether it stretches to fill the viewport. [**See more info here**](#primary-property). +- **Primary:** If set to true, the ListView will act as the primary scrolling view in the context. This usually affects how the view interacts with other scrolling views and whether it stretches to fill the viewport. [**See more info here**](#primary-property). -- **Reverse:** In lists, when the reverse property is enabled, it reverses the order in which items appear in the ListView. For a vertical list, this means starting from the bottom and for a horizontal list, starting from the right. +- **Reverse:** When enabled, this property reverses the order in which items appear in the ListView. For a vertical list, items start from the bottom; for a horizontal list, they start from the right. ![listview-reverse.png](../built-in-widgets/imgs/listview-reverse.png) ### Reorderable List -Whether to allow reordering of items in the list. On Web or Desktop this will -add drag handles, but on mobile - the reorder is triggerred by long pressing an item. + +Enable this option to allow users to reorder items in the list. On web and desktop, FlutterFlow adds drag handles. On mobile, users can reorder an item by long-pressing it. :::info[Note] -This will not automatically persist the order of items -in the list, but instead lets you define an action under **"On Reorder**" -action trigger to make any necessary changes yourself. +Reordering does not automatically persist the updated item order. Use the **On Reorder** action trigger to define how the new order should be saved. ::: -:::danger[CONTENTs of a Reorderable List] -**Reorderable ListView** must have dynamic children otherwise enabling this will throw an error. +:::danger[Contents of a Reorderable List] +A **Reorderable ListView** must have dynamic children; otherwise, enabling this option will cause an error. ::: -Here's a quick tutorial to set up your Reorderable ListView: - -#### Using App State variable +Follow these steps to set up a Reorderable ListView: -1. First, create an app state variable with a few items of type String and display them on the -ListView widget. +#### Using an App State Variable -2. Then, select the ListView, head over to the **Properties Panel > ListView Properties**, and -enable -the **Reorderable** property. +1. Create an App State variable containing a few items of type `String`, and display them in the ListView. +2. Select the ListView, go to **Properties Panel > ListView Properties**, and enable **Reorderable**. +3. Open the **Actions** section in the properties panel and then open the **Action Flow Editor**. +4. Select the **On Reorder** action trigger. Actions added under this trigger run after a user repositions an item in the interface. +5. Create a custom action that updates the item's position in the source list. Add three arguments for the list, the **Old Index**, and the **New Index**. You can access the old and new index values from **Set Variable > Reorderable ListView**. +6. Use the following custom code: -3. Select Actions from the properties panel (the right menu), and open the **Action Flow Editor.** - -4. You'll see an **On Reorder** action trigger. Actions under this are triggered when a user - completes repositioning an item in the UI. But, we also need to update the item position in the - actual list as well. To do so, we can create a custom action that will modify the item index in the list. - 1. Create a custom action with three arguments that accept the actual list, old index, and new - index. Tip: You'll get the old and new index from Set Variable menu > Reorderable ListView. - 2. Here's the custom code with explanation - - ``` - // Define a function called reorderItems that returns a Future of a list of strings. -// It takes in a list of strings, an old index, and a new index as parameters. +```jsx +// Define a function called `reorderItems` that returns a Future +// containing a reordered list of strings. Future> reorderItems( -List list, -int oldIndex, -int newIndex, + List list, + int oldIndex, + int newIndex, ) async { -// If the item is being moved to a position further down the list -// (i.e., to a higher index), decrement the newIndex by 1. -// This adjustment is needed because removing an item from its original -// position will shift the indices of all subsequent items. -if (oldIndex < newIndex) { -newIndex -= 1; -} + // If the item is being moved further down the list, adjust the + // destination index because removing the item shifts the indices. + if (oldIndex < newIndex) { + newIndex -= 1; + } -// Remove the item from its original position in the list and store -// it in the 'item' variable. -final item = list.removeAt(oldIndex); + // Remove the item from its original position. + final item = list.removeAt(oldIndex); -// Insert the removed item into its new position in the list. -list.insert(newIndex, item); + // Insert the item at its new position. + list.insert(newIndex, item); -// Return the modified list. -return list; + // Return the updated list. + return list; } ``` -5. The custom action returns the modified list, which you can use to update the actual list using the update app state variable action. - -
+7. Use the list returned by the custom action to update the original list with the **Update App State** action. +
+ +
+

-#### Reordering Items in a Firebase Query +#### Reordering Items in a Firestore Query -If you want to reorder the list items retrieved via Firebase query collection, the steps are almost similar except for the following changes. +To reorder items retrieved from a Firestore collection query, follow the previous steps with these changes. :::danger[Caution] -Reordering items in a Firebase query is only suited for smaller lists. For larger datasets, this method can be inefficient and might lead to performance issues. Additionally, frequent writes and updates to Firebase can increase costs significantly. +Reordering items in a Firestore query is best suited for smaller lists. For larger datasets, this method can be inefficient and might lead to performance issues. Additionally, frequent writes and updates to Firestore can increase costs significantly. ::: -1. Create 'order' field in the collection. -2. Query collection order by 'order' field. -3. Ensure that the Infinite scroll is disabled. -4. Replace the custom action code with the below one: -```dart +1. Create an `order` field in the collection. +2. Order the collection query by the `order` field. +3. Ensure that infinite scroll is disabled. +4. Replace the custom action code with the following code: + +```jsx Future reorderFirebaseItems( List list, int oldIndex, @@ -145,7 +143,7 @@ Future reorderFirebaseItems( // Remove the item from its current position in the list. final PlaylistRecord item = list.removeAt(oldIndex); - + // Insert the item into its new position. list.insert(newIndex, item); @@ -155,63 +153,56 @@ Future reorderFirebaseItems( // Iterate through the list and update the order field for each document in Firestore. for (int i = 0; i < list.length; i++) { final PlaylistRecord doc = list[i]; - // Update the 'order' field of the document with its new index. + // Update the 'order' field of the document with its new index. // This assumes that you have an 'order' field in Firestore where you store the order of the items. batch.update(doc.reference, { 'order': i - }); + }); } // Commit all the batched operations to Firestore. return await batch.commit(); } - - ``` -

-## ListTile widget +## ListTile Widget -The `ListTile` widget is a versatile component designed for displaying rows in a list, commonly -used for menus, drawers, and lists where each row consists of multiple elements aligned horizontally. `ListTile` is particularly useful when you need a standardized row layout that includes elements a main title, a subtitle, and interactive icons at the start or end of the row. It saves time compared to constructing custom row layouts from scratch while ensuring visual consistency. +The `ListTile` widget provides a standardized horizontal row containing elements such as a title, subtitle, and interactive icons at either end. It is commonly used in menus, drawers, and other collections with a consistent item structure. Using ListTile saves time compared to building custom rows while maintaining visual consistency. :::tip[When to Use ListTile Over Custom Components] -ListTile should be used when you require a simple, effective layout with standard elements and interactions. It is ideal for: +Use ListTile when you need a simple layout with standard elements and interactions. It is ideal for: - Lists where items have a uniform structure. - Quick assembly of functional interfaces without needing complex customization. -- Scenarios requiring integrated touch feedback and accessibility features which ListTile - provides by default. +- Scenarios requiring integrated touch feedback and accessibility features, which ListTile provides by default. ::: -You can customize the Title (Text), Subtitle (Text) and Icon properties from the Properties Panel +You can customize the **Title**, **Subtitle**, and **Icon** properties from the properties panel. ![list-tile.png](../built-in-widgets/imgs/list-tile.png) :::info -To learn about how to customize the Text widgets in this component, refer the [**Text widget**](../basic-widgets/text.md). +To learn how to customize the Text widgets in this component, refer to the [**Text widget documentation**](../basic-widgets/text.md). ::: -### Convert into SlidableListTile +### Convert to a SlidableListTile -The ListTile in FlutterFlow offers an additional functionality—it can easily be transformed into a slidable version. This enhanced ListTile allows you to embed actions that users can access by sliding the tile to the left, adding a layer of interactivity and utility to the standard list item. +You can convert a ListTile into a slidable version and add actions that users can reveal by swiping the tile to the left. -Here's how you can enable the Slidable functionality of a ListTile and modify the properties of -the Actions: +The following demo shows how to enable the slidable functionality and configure its actions:
-
- - ## GridView Widget -GridView provides a two-dimensional array of children. It is the widget of choice when you need to display items in a grid pattern, like a photo gallery or a board game layout. -Like [ListView](#listview-widget), GridView only renders the visible items, making it efficient for displaying large collections of elements. GridView supports multiple configurations for column count, spacing, aspect ratio, and scroll directions, offering robust customization options for diverse layout needs. +GridView provides a scrollable grid of widgets. Use it to display items in a grid pattern, such as a photo gallery or board game layout. -![gridview.png](imgs/gridview.png) +Like [ListView](#listview-widget), GridView only renders the visible items, making it efficient for displaying large collections of elements. GridView supports multiple configurations for column count, spacing, child aspect ratio, and scroll direction, offering robust customization options for diverse layout needs. +![gridview.png](imgs/gridview-with-vertical-scroll.avif) -Here's a quick demo to show how to add a GridView widget and modify its properties: +Here's a quick demo showing how to add a GridView widget and modify its properties:
-
+
::: -## Adding infinite scroll +## Adding Infinite Scroll -The infinite scroll automatically loads the new items as you scroll down the list. It works by showing only a limited number of items (e.g., 15, 25) at first and loads subsequent items before the user reaches the end of the list. At the end of the list, a circular progress bar is visible as the new items are loaded. +Infinite scroll automatically loads new items as you scroll down the list. It initially displays a limited number of items, such as 15 or 25, and then loads subsequent items before the user reaches the end. A circular progress indicator appears at the end of the list while new items load.
- -
-

+![enable-infinite-list](imgs/enable-infinite-list.avif) -### Infinite scroll on a list from API call +### Infinite Scroll on a List from an API Call -To add an infinite scroll on the API call, you must have an endpoint that supports pagination with at least one query parameter that accepts a page number like page, offset, etc. +To use infinite scroll with an API call, you need an endpoint that supports pagination through at least one query parameter, such as `page`, `offset`, or `limit`. #### Pagination Variables -When you add the paginated API call in the builder and enable the infinite scroll, we provide you the following pagination variables that you can pass to your API variables. These will be available inside the **Set Variable** menu. +When you add a paginated API call in the builder and enable infinite scroll, FlutterFlow provides the following pagination variables in the **Set Variable** menu. You can pass these values to your API parameters. -![Pagination Variables](../built-in-widgets/imgs/pagination-variable.png) +![pagination-variables](imgs/pagination-variables.avif) -1. **Next Page Index**: You can pass this variable for the query parameter that accepts the page number. The default value is 0 and keeps increasing by one as you scroll down the list until it reaches the end. -2. **#(Number of) Loaded Items**: This equals the number of items returned by the paginated API call. -3. **Last Response**: This is useful if you want to get anything from the last response that might help you retrieve the next set of data. +1. **Next Page Index:** Pass this variable to the query parameter that accepts the page number. Its default value is `0`, and it increases by one as you scroll until the list reaches the end. +2. **# (Number of) Loaded Items:** Contains the number of items returned by the paginated API call. +3. **Last Response:** Provides data from the previous response that you can use to retrieve the next set of results. :::tip -When passing the *Number of Loaded Items* for query parameters like *limit*, *per_page*, *size,* etc., use a *Specific Value,* such as 15,20. +For query parameters such as `limit`, `per_page`, or `size`, set **Number of Loaded Items** to a **Specific Value**, such as `15` or `20`. ::: -Adding infinite scroll includes: - -1. [Add paginated API call](#1-add-paginated-api-call) -2. [Passing pagination variable in API call query](#2-passing-pagination-variable-in-api-call-query) +To configure infinite scroll for an API call, complete these steps: -#### 1. Add paginated API call +#### 1. Add a Paginated API Call -The paginated API is the API that returns the result in chunks. Most of the paginated API requires you to add the query parameters to know how many items to retrieve and from where to start. +A paginated API returns results in chunks. Most paginated APIs use query parameters to determine how many items to retrieve and where to begin. -For example, this API call https://reqres.in/api/users?per_page=20&page=1 requires `per_page` parameter that specifies 20 items to load per page, and `page` parameter tells to start from the first page. This is called page-based pagination. +For example, [`https://reqres.in/api/users?per_page=20&page=1`](https://reqres.in/api/users?per_page=20&page=1) uses the `per_page` parameter to request 20 items and the `page` parameter to request the first page. This is called page-based pagination. -See [how to add the paginated API](../../../control-flow/backend-logic/api/rest-api.md#passing-query-parameters) call by adding query parameters. +See [how to configure query parameters for an API call](../../../control-flow/backend-logic/api/rest-api.md#passing-query-parameters). -#### 2. Passing pagination variable in API call query +#### 2. Pass a Pagination Variable to an API Call -This step includes adding the ListView -> ListTile widget and querying the paginated API call. - -1. First, query and show data from API calls. -2. While querying the API call, pass the query parameter value from the pagination variable. +In this step, add a ListTile inside a ListView and configure the ListView to display data returned by the paginated API. +1. Query the API and display its data. +2. Set the relevant API query parameter using a pagination variable.
-
- - - -## Pull to Refresh on ListView or GridView - -If you've enabled the Single Time Query for a Backend Query in a scrollable widget, it won't refresh the list when items are updated in the backend. To address this, add a pull-to-refresh feature. - -This user interface pattern allows users to manually refresh content by pulling down the content area, such as a list. When pulled down sufficiently and released, the app will refresh, fetching the latest data or updates. - -
- -

- - -To enable pull to refresh: - -1. Select your scrollable widget, such as `ListView`, `GridView`, or `StaggeredView`. -2. Move to the properties panel and select the **Backend Query**. -3. Open the already added query (e.g., Query collection or API call) and make sure the **Single Time Query** is enabled. -4. Switch on the **Enable Pull to Refresh** toggle. This will automatically add the **Refresh Database Request** action on a pull to refresh gesture. - -
- -

- - -## Scroll To [Action] - -Using this action, you scroll the scrollable widget to the beginning or end. -
-

+ +:::info +To enable pull-to-refresh for Firestore documents, first enable **Single Time Query**. + +![enable-infinite-list](imgs/enable-infinite-list.avif) +::: + +## Scroll To [Action] + +Use this action to move a scrollable widget to its beginning or end. + +:::info +Before adding this action, make sure you have a scrollable widget, such as a **ListView**, **StaggeredView**, or **GridView**, with enough items to enable scrolling. +::: + +Follow the steps below to add this action to any widget. + +1. Select the widget, such as a FloatingActionButton, on which you want to add the action. +2. Open **Actions** in the properties panel and click **+ Add Action**. +3. Search for and select the **Scroll To** action under *Widget/UI Interactions*. +4. Under **Scrollable Widget to Control**, select the scrollable widget on your page, such as a ListView. +5. Set **Scroll To** to either **Beginning** or **End**. +6. Specify the **Duration** in milliseconds. For example, `1000 ms = 1 second`. This determines how long the scroll animation takes to complete. + +:::tip +If you expect the list to be long, consider setting a shorter duration. +::: + +![scroll-to-action](imgs/scroll-to-action.avif)