返回博客首页
← 所有文章

深入探讨 NativeScript UI 的 ListView

2017 年 1 月 24 日 — 作者:Rob Lauer

让我们面对现实,开发者,创造引人入胜的用户体验是件难事。当网络还处于起步阶段时,我们可以用<marquee>标签让用户惊叹,但如今,我们的客户更加挑剔和苛刻。他们想要一款不仅实用,而且沉浸式且美观的应用程序。

无论您是为 Web、移动还是桌面构建应用程序,您都知道Telerik UI 工具可以助您一臂之力。从 Kendo UI 到 UI for Xamarin,再到 UI for ASP.NET,以及 UI for WPF,我们的工具可以满足几乎所有的开发需求。

这就是NativeScript UI如此令人兴奋的原因。借助 NativeScript UI,我们秉承 Telerik 的传统,提供易于使用的组件,让开发者体验其易用性带来的喜悦,同时,让最终用户体验其引人入胜的功能带来的愉悦。

这是我们“NativeScript UI 周”系列文章的第一篇,我们将深入探讨每个组件。今天我们将重点介绍ListView,很快我们还将发布针对我们产品中每个组件的深度文章

什么是 NativeScript UI?

NativeScript UI 是一套适用于使用 NativeScript 框架编写的原生跨平台移动应用程序的高级 UI 组件。我们的目标是通过提供预构建的、随时可用的、易于在您的应用程序中实现(以及易于根据您的应用程序外观和风格进行样式设置)的组件,简化 NativeScript 应用程序开发。

让我们开始学习有关 ListView 组件的所有知识。

ListView(也称为 RadListView)

ListView 组件(代码中称为 RadListView)使您可以自定义数据列表。这听起来很基础,但它提供的功能和显示选项非常多样。例如,使用 RadListView 的 Grid 布局和一些 CSS 样式,您可以轻松创建如下所示的 UI

radlistview overview

借助 RadListView,您可以为列表项添加动画效果,使用不同的布局,并利用多种手势,例如滑动以执行、按压/拖动以重新排序、下拉以刷新以及按压以选择。

安装 NativeScript UI 的 ListView

导航到您的 NativeScript 项目目录,并使用以下命令安装 NativeScript UI ListView(无需手动下载)

tns plugin add nativescript-ui-listview

RadListView 入门

请注意,此处演示的所有代码都可以在此 GitHub 存储库中找到。如需更多代码示例,请查看官方NativeScript UI 示例存储库

插件安装好了吗?太好了!现在我们需要在我们要使用 RadListView 的页面的根目录添加一个 XML 命名空间。如果您对“XML 命名空间”感到害怕,请不要担心。您只需要向根<Page>元素添加一个属性,如下所示

<Page xmlns:lv="nativescript-ui-listview"> 

最后,我们需要将 RadListView 组件添加到我们的 XML 标记中,如下所示

<Page xmlns:lv="nativescript-ui-listview">
<lv:RadListView> </lv:RadListView> </Page>

我们完成了!好吧,还没完全完成。这个简单的示例实际上还没有任何事情。让我们添加一些数据,以便我们可以开始玩转那些酷炫的功能!

项目模板

ListView 的核心是数据。我们在 RadListView 中格式化数据显示的方式是使用ItemTemplate。让我们向现有的 RadListView 添加一个简单的ItemTemplate

<Page xmlns="http://schemas.nativescript.org/tns.xsd" xmlns:lv="nativescript-ui-listview" loaded="pageLoaded">

    <ActionBar title="RadListView Demo" class="action-bar" />

    <lv:RadListView id="listview" class="list-group"> 
        <lv:RadListView.listViewLayout>
            <lv:ListViewLinearLayout scrollDirection="Vertical"/>
        </lv:RadListView.listViewLayout>
        <lv:RadListView.itemTemplate>
            <StackLayout class="list-group-item">
                <Label text="{{ itemName }}" class="list-group-item-heading" />
                <Label text="{{ itemDesc }}" textWrap="true" class="list-group-item-text" />
            </StackLayout>
        </lv:RadListView.itemTemplate>
    </lv:RadListView>

</Page>

我的天!我刚向您扔了一堆代码,对吧?幸运的是,它并没有看起来那么复杂

  • 我们将pageLoaded函数与loaded页面事件关联(见下文)。
  • 我们添加了一个ActionBar,以便在我们的视图中显示标题。
  • 我们添加了一个listViewLayout,以指定项目布局(见下文)。
  • 我们添加了 CSS 类用于样式设置。
  • 我们添加了一个StackLayout,将我们的Labels叠加在一起。

就是这样!

现在对于我们的代码隐藏 JavaScript 文件,我们需要用一些数据填充此视图

var view = require("ui/core/view");

exports.pageLoaded = function(args) {
    var items = [];
    items.push(
        {
            itemName: "Arcade Fire",
            itemDesc: "Funeral"
        },
        {
            itemName: "Bon Iver",
            itemDesc: "For Emma, Forever Ago"
        },
        {
            itemName: "Daft Punk",
            itemDesc: "Random Access Memories"
        },
        {
            itemName: "Elbow",
            itemDesc: "Build a Rocket Boys!"
        }
    )
    var page = args.object;
    var listview = view.getViewById(page, "listview");
    listview.items = items;
}

正在寻找 Angular 代码示例?请查看我们的完整的 Angular 文档

我们的pageLoaded函数简单地获取一个项目数组,并将该数组与我们的 RadListView 关联。其结果是

simple radlistview

请注意,您看到的样式来自 NativeScript 中包含的核心浅色主题,以及使用NativeScript 主题构建器进行的一些自定义设置。

但这仅仅是个开始。让我们看看如何扩展 RadListView。

项目布局

通常,当我们想到 ListView 时,我们会想到一个简单的垂直项目列表。但是,当我们想使用不同类型的布局(甚至是非线性的布局)时该怎么办?RadListView 提供了一些不同的项目布局选项(全部都是原生的,并且针对跨平台使用进行了优化)。

  • 线性(ListViewLinearLayout) - 具有垂直或水平方向的传统列表。
  • 网格(ListViewGridLayout) - 使用它按列和行排列项目。
  • 交错(ListViewStaggeredLayout) - 网格的扩展:项目根据其大小进行定位,而不是以均匀的网格状表格进行定位。

线性布局(ListViewLinearLayout)非常容易实现(这是我们上面使用的布局)

<lv:RadListView.listViewLayout>
    <lv:ListViewLinearLayout scrollDirection="Vertical" />
</lv:RadListView.listViewLayout>

同样,要实现网格或交错布局,只需替换为ListViewGridLayoutListViewStaggeredLayout,如下所示

<lv:RadListView.ListViewLayout>
    <lv:ListViewGridLayout scrollDirection="Vertical" itemHeight="100" spanCount="2"/>
</lv:RadListView.ListViewLayout>

…这将产生如下所示的显示效果

grid listview

请注意,itemHeight属性仅适用于网格布局,因为交错布局的行具有动态大小。这里还要注意的是spanCount属性。它决定了网格或交错布局中有多少列。

使用 ObservableArray 和图像进行优化

接下来的部分将深入探讨 RadListView 的核心 - 动画和对各种手势的支持。为了展示它们,我们将切换到使用ObservableArray,而不是我们到目前为止一直使用的基本数组。

很简单。

旧的出去,新的进来 - 这是我们使用 ObservableArray 的新的代码隐藏 JavaScript 文件

var Observable = require("data/observable").Observable;
var ObservableArray = require("data/observable-array").ObservableArray;

var page;
var items = new ObservableArray([]);
var pageData = new Observable();

exports.pageLoaded = function(args) {
    page = args.object;
    page.bindingContext = pageData;

    items.push(
        {
            itemName: "Arcade Fire",
            itemDesc: "Funeral",
            itemImage: "~/images/arcade-fire.png"
        },
        {
            itemName: "Bon Iver",
            itemDesc: "For Emma, Forever Ago",
            itemImage: "~/images/bon-iver.png"
        },
        {
            itemName: "Daft Punk",
            itemDesc: "Random Access Memories",
            itemImage: "~/images/daft-punk.png"
        },
        {
            itemName: "Elbow",
            itemDesc: "Build a Rocket Boys!",
            itemImage: "~/images/elbow.png"
        }
    )

    pageData.set("items", items);
};

发生了什么变化?变化不大。我们的数组现在是可观察的,我们还添加了一个itemImage属性,用于为我们所有列表项显示缩略图图像。

为了支持此缩略图显示,我们还需要对 XML 标记进行一些调整

<lv:RadListView items="{{ items }}" class="list-group"> 
    <lv:RadListView.listViewLayout>
        <lv:ListViewLinearLayout scrollDirection="Vertical"/>
    </lv:RadListView.listViewLayout>
    <lv:RadListView.itemTemplate>
        <GridLayout class="list-group-item" rows="auto" columns="auto, *">
            <Image row="0" col="0" src="{{ itemImage }}" class="thumb img-rounded" />
            <StackLayout row="0" col="1" >
                <Label text="{{ itemName }}" class="list-group-item-heading" />
                <Label text="{{ itemDesc }}" class="list-group-item-text" />
            </StackLayout>
        </GridLayout>
    </lv:RadListView.itemTemplate>
</lv:RadListView>

在这种情况下,我们添加了一个GridLayout,以便我们可以在标签旁边对齐图像,如下所示

radlistview with images

动画

当项目添加到(或从)列表中时,执行某种动画以向用户提供正在进行的操作的视觉提示是一个好主意。借助 RadListView,您可以从四个不同的动画选项中进行选择

  • 默认(平台默认动画)
  • 淡入淡出
  • 缩放
  • 滑动

让我们尝试使用 RadListView 来体验一些动画效果!

首先,让我们通过在pageData.set("items", items);之后立即添加以下代码片段来欺骗系统

setTimeout(function() {
    items.push(
            {
                itemName: "LCD Soundsystem",
                itemDesc: "This is Happening",
                itemImage: "~/images/lcd-soundsystem.png"
            }
    );
}, 2000);

两秒钟后,另一个项目将被推送到我们的数组中。

接下来,我们将为ListViewLinearLayout设置itemInsertAnimation属性,如下所示

<lv:ListViewLinearLayout scrollDirection="Vertical" itemInsertAnimation="Slide" />

其结果是我们的项目会自动滑动进来(两秒钟后)。只需将“Slide”替换为“Fade”、“Scale”或“Default”中的一个,即可查看其他动画效果!

listview add item with slide

正如Burke Holland所说,“这很酷”。但我们真正想看到的是一些我们可以应用于我们应用程序的完整手势和操作。

手势操作

啊,手势!任何引人入胜的移动应用程序的关键是与人们使用的原生手势集成。

让我们看看一些您可能想要利用的更常见的手势操作

谁没有在某个时候使用过下拉刷新?没有人,就是这样!实现下拉刷新很简单,您只需向标记中添加两个属性

<lv:RadListView id="listview" items="{{ items }}" class="list-group" pullToRefresh="true" 
pullToRefreshInitiated="pullToRefreshInitiated">

首先,我们将pullToRefresh设置为true,然后我们将pullToRefreshInitiated函数添加到pullToRefreshInitiated事件中。

以下就是该pullToRefreshInitiated函数(您可以将其粘贴到代码隐藏 JavaScript 文件的末尾)

exports.pullToRefreshInitiated = function() {
    setTimeout(function() {
        items.push(
                {
                    itemName: "LCD Soundsystem",
                    itemDesc: "This is Happening",
                    itemImage: "~/images/lcd-soundsystem.png"
                }
        );
        page.getViewById("listview").notifyPullToRefreshFinished();
    }, 2000);
};

与上面一样,我们正在欺骗系统,以便在下拉刷新期间两秒钟后向我们的数组中添加一个项目。在现实世界中,此函数将调用远程 API 以获取更多数据。

ios pull-to-refresh android pull-to-refresh

滑动操作是为您的应用程序添加特定于移动设备的 UI 的另一种好方法。您的列表中的每个项目都可以被滑动,以显示一个或多个功能。

让我们看看如何在 RadListView 中设置一个简单的滑动操作

<lv:RadListView id="listview" items="{{ items }}" class="list-group" swipeActions="true">

我们将swipeActions属性设置为 true,然后向 RadListView 添加一个itemSwipeTemplate,它告诉应用程序当您向左或向右滑动列表项时您想要看到哪些新控件。

此代码可以放在您 XML 标记中的结束</lv:RadListView>标签之前

<lv:RadListView.itemSwipeTemplate>
    <GridLayout columns="auto, *, auto">
        <StackLayout col="0" class="save-btn" tap="onLeftSwipe" orientation="horizontal">
            <Label text="Save" verticalAlignment="center" horizontalAlignment="center"/>
        </StackLayout>
        <StackLayout col="2" class="delete-btn" tap="onRightSwipe" orientation="horizontal">
            <Label text="Delete" verticalAlignment="center" horizontalAlignment="center" />
        </StackLayout>
    </GridLayout>
</lv:RadListView.itemSwipeTemplate>

itemSwipeTemplate使我们能够指定列表项的视图,它将在滑动操作发生时显示。

ios swipe android swipe

现在,要使这些滑动操作真正起作用,您需要实现一个特定的滑动操作,您可以在我们的文档中找到相关说明。我们的文档将向您展示如何在完全滑动(滑动以执行)或滑动加点按(点按以执行)时执行操作。

还有什么吗?

哦,我们只是触及了皮毛!RadListView 提供了无数方法来自定义您的 NativeScript ListViews。花点时间阅读文档,您将找到今天无法涵盖的示例和代码片段。