NativeScript UI组件 #

组件概述 #

NativeScript 提供了丰富的原生 UI 组件,这些组件直接映射到 iOS 和 Android 的原生控件。

text
┌─────────────────────────────────────────────────────────────┐
│                    UI 组件分类                               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  基础组件                                                    │
│  ├── Label          文本显示                                │
│  ├── Button         按钮                                    │
│  ├── Image          图片                                    │
│  └── HtmlView       HTML 内容                               │
│                                                             │
│  表单组件                                                    │
│  ├── TextField      单行输入                                │
│  ├── TextView       多行输入                                │
│  ├── Switch         开关                                    │
│  ├── Slider         滑块                                    │
│  ├── CheckBox       复选框                                  │
│  └── DatePicker     日期选择                                │
│                                                             │
│  导航组件                                                    │
│  ├── ActionBar      操作栏                                  │
│  ├── TabView        标签页                                  │
│  └── BottomNavigation 底部导航                              │
│                                                             │
│  数据组件                                                    │
│  ├── ListView       列表视图                                │
│  ├── Repeater      重复器                                   │
│  └── WebView        网页视图                                │
│                                                             │
└─────────────────────────────────────────────────────────────┘

基础组件 #

Label #

文本显示组件:

xml
<Label text="Hello World" 
       textWrap="true" 
       textAlignment="center" />

常用属性

属性 类型 说明
text string 文本内容
textWrap boolean 是否换行
textAlignment string 对齐方式: left/center/right
fontSize number 字体大小
fontWeight string 字体粗细: normal/bold
color Color 文本颜色
maxLines number 最大行数

富文本

xml
<Label textWrap="true">
    <FormattedString>
        <Span text="Hello " fontSize="16" color="#333" />
        <Span text="World" fontSize="20" fontWeight="bold" color="#3498db" />
        <Span text="!" fontSize="16" color="#333" />
    </FormattedString>
</Label>

Button #

按钮组件:

xml
<Button text="Click Me" 
        tap="onTap" 
        class="btn btn-primary" />

常用属性

属性 类型 说明
text string 按钮文本
tap function 点击事件
isEnabled boolean 是否可用
borderRadius number 圆角半径
borderWidth number 边框宽度

按钮样式

css
.btn {
    padding: 12 24;
    border-radius: 8;
    font-size: 16;
    min-width: 100;
}

.btn-primary {
    background-color: #3498db;
    color: white;
}

.btn-secondary {
    background-color: #95a5a6;
    color: white;
}

.btn-danger {
    background-color: #e74c3c;
    color: white;
}

.btn-outline {
    background-color: transparent;
    border-color: #3498db;
    border-width: 2;
    color: #3498db;
}

Image #

图片组件:

xml
<!-- 本地图片 -->
<Image src="~/assets/images/logo.png" 
       stretch="aspectFit" 
       width="100" 
       height="100" />

<!-- 网络图片 -->
<Image src="https://example.com/image.jpg" 
       stretch="aspectFill" 
       loadMode="async" />

<!-- 图标字体 -->
<Image src="font://&#xf015;" 
       class="fas" 
       fontSize="32" />

stretch 属性

说明
none 原始大小
aspectFit 保持比例适应
aspectFill 保持比例填充
fill 拉伸填充

图片加载事件

xml
<Image src="{{ imageUrl }}" 
       loaded="onImageLoaded" 
       loadError="onImageError" />
typescript
export function onImageLoaded(args: EventData) {
    console.log('Image loaded');
}

export function onImageError(args: EventData) {
    console.log('Image load failed');
}

HtmlView #

显示 HTML 内容:

xml
<HtmlView html="<h1>Title</h1><p>Paragraph</p>" />

表单组件 #

TextField #

单行文本输入:

xml
<TextField hint="Enter your name" 
           text="{{ name }}" 
           keyboardType="name" 
           returnKeyType="done" 
           autocorrect="false" 
           autocapitalizationType="words" />

常用属性

属性 类型 说明
text string 输入内容
hint string 占位文本
keyboardType string 键盘类型
returnKeyType string 返回键类型
maxLength number 最大长度
secure boolean 密码输入
editable boolean 是否可编辑

键盘类型

说明
text 默认文本
number 数字
phone 电话
email 邮箱
url 网址
name 姓名
password 密码

事件处理

xml
<TextField text="{{ email }}" 
           textChange="onTextChange" 
           returnPress="onReturnPress" 
           focus="onFocus" 
           blur="onBlur" />

TextView #

多行文本输入:

xml
<TextView hint="Enter your message" 
          text="{{ message }}" 
          editable="true" 
          textWrap="true" 
          maxLength="500" />

Switch #

开关组件:

xml
<GridLayout columns="*, auto" rows="auto">
    <Label text="Enable notifications" col="0" />
    <Switch checked="{{ isEnabled }}" 
            checkedChange="onCheckedChange" 
            col="1" />
</GridLayout>
typescript
export function onCheckedChange(args) {
    const switchControl = args.object as Switch;
    console.log('Checked:', switchControl.checked);
}

Slider #

滑块组件:

xml
<StackLayout>
    <Label text="Volume: {{ volume }}" />
    <Slider minValue="0" 
            maxValue="100" 
            value="{{ volume }}" 
            valueChange="onVolumeChange" />
</StackLayout>

CheckBox #

复选框(需要插件):

bash
npm install @nativescript/checkbox
xml
<CheckBox checked="{{ isChecked }}" 
          text="Remember me" 
          checkedChange="onCheckedChange" />

DatePicker #

日期选择器:

xml
<DatePicker year="2024" 
            month="1" 
            day="1" 
            date="{{ selectedDate }}" 
            dateChange="onDateChange" />

TimePicker #

时间选择器:

xml
<TimePicker hour="12" 
            minute="0" 
            time="{{ selectedTime }}" 
            timeChange="onTimeChange" />

Picker #

下拉选择器:

xml
<Picker items="{{ items }}" 
        selectedIndex="{{ selectedIndex }}" 
        selectedValue="{{ selectedValue }}" 
        selectedIndexChanged="onSelectedIndexChanged" />
typescript
export class ViewModel extends Observable {
    items = ['Option 1', 'Option 2', 'Option 3'];
    selectedIndex = 0;
    selectedValue = 'Option 1';
}

导航组件 #

ActionBar #

顶部操作栏:

xml
<Page>
    <ActionBar title="My App">
        <!-- 导航按钮 -->
        <NavigationButton icon="res://back" 
                          tap="onBack" 
                          android.visibility="collapsed" />
        
        <!-- 操作按钮 -->
        <ActionItem text="Edit" 
                    icon="res://edit" 
                    tap="onEdit" 
                    android.position="actionBar" 
                    ios.position="right" />
        
        <!-- 溢出菜单 -->
        <ActionItem text="Settings" 
                    tap="onSettings" 
                    android.position="popup" />
    </ActionBar>
    
    <GridLayout>
        <!-- 页面内容 -->
    </GridLayout>
</Page>

自定义 ActionBar

xml
<ActionBar class="action-bar">
    <GridLayout columns="auto, *, auto">
        <Button text="Menu" col="0" tap="onMenu" />
        <Label text="Custom Title" col="1" class="title" />
        <Button text="Search" col="2" tap="onSearch" />
    </GridLayout>
</ActionBar>

TabView #

标签页导航:

xml
<TabView selectedIndex="{{ selectedIndex }}" 
         tabTextColor="#999" 
         selectedTabTextColor="#3498db" 
         tabBackgroundColor="#f5f5f5">
    
    <TabView.items>
        <TabViewItem title="Home" iconSource="res://home">
            <TabViewItem.view>
                <GridLayout>
                    <Label text="Home Page" />
                </GridLayout>
            </TabViewItem.view>
        </TabViewItem>
        
        <TabViewItem title="Search" iconSource="res://search">
            <TabViewItem.view>
                <GridLayout>
                    <Label text="Search Page" />
                </GridLayout>
            </TabViewItem.view>
        </TabViewItem>
        
        <TabViewItem title="Profile" iconSource="res://user">
            <TabViewItem.view>
                <GridLayout>
                    <Label text="Profile Page" />
                </GridLayout>
            </TabViewItem.view>
        </TabViewItem>
    </TabView.items>
    
</TabView>

BottomNavigation #

底部导航(Material Design):

xml
<BottomNavigation>
    <BottomNavigation.items>
        
        <TabStripItem title="Home">
            <TabStripItem.iconSource>
                <FontIconSource icon="home" fontSize="24" />
            </TabStripItem.iconSource>
        </TabStripItem>
        
        <TabStripItem title="Search">
            <TabStripItem.iconSource>
                <FontIconSource icon="search" fontSize="24" />
            </TabStripItem.iconSource>
        </TabStripItem>
        
        <TabStripItem title="Profile">
            <TabStripItem.iconSource>
                <FontIconSource icon="user" fontSize="24" />
            </TabStripItem.iconSource>
        </TabStripItem>
        
    </BottomNavigation.items>
    
    <BottomNavigation.content>
        <GridLayout>
            <Label text="{{ currentTab }}" />
        </GridLayout>
    </BottomNavigation.content>
    
</BottomNavigation>

数据组件 #

ListView #

高性能列表视图:

xml
<ListView items="{{ items }}" 
          itemTap="onItemTap" 
          loadMoreItems="onLoadMore" 
          separatorColor="#e0e0e0">
    <ListView.itemTemplate>
        <GridLayout columns="auto, *, auto" rows="auto, auto" class="item">
            <Image src="{{ avatar }}" 
                   row="0" col="0" rowSpan="2" 
                   width="50" height="50" 
                   borderRadius="25" />
            <Label text="{{ name }}" 
                   row="0" col="1" class="name" />
            <Label text="{{ message }}" 
                   row="1" col="1" class="message" textWrap="true" />
            <Label text="{{ time }}" 
                   row="0" col="2" class="time" />
        </GridLayout>
    </ListView.itemTemplate>
</ListView>

无限滚动

typescript
export class ViewModel extends Observable {
    items = new ObservableArray();
    page = 1;
    
    onLoadMore() {
        this.page++;
        this.loadItems();
    }
    
    async loadItems() {
        const newItems = await fetchItems(this.page);
        this.items.push(...newItems);
    }
}

下拉刷新

xml
<ListView items="{{ items }}" 
          refresh="{{ isRefreshing }}" 
          refreshList="onRefresh">
    <!-- ... -->
</ListView>
typescript
export function onRefresh(args) {
    const listView = args.object as ListView;
    
    // 刷新数据
    refreshData().then(() => {
        listView.refreshing = false;
    });
}

Repeater #

简单重复器:

xml
<Repeater items="{{ items }}">
    <Repeater.itemTemplate>
        <Label text="{{ title }}" class="item" />
    </Repeater.itemTemplate>
</Repeater>

WebView #

网页视图:

xml
<WebView src="https://example.com" 
         loaded="onLoaded" 
         loadStarted="onLoadStarted" 
         loadFinished="onLoadFinished" />
typescript
export function onLoadFinished(args) {
    const webView = args.object as WebView;
    console.log('URL:', webView.url);
}

对话框组件 #

Alert #

typescript
import { Dialogs } from '@nativescript/core';

Dialogs.alert({
    title: 'Alert',
    message: 'This is an alert',
    okButtonText: 'OK'
});

Confirm #

typescript
const result = await Dialogs.confirm({
    title: 'Confirm',
    message: 'Are you sure?',
    okButtonText: 'Yes',
    cancelButtonText: 'No'
});

if (result) {
    console.log('Confirmed');
}

Prompt #

typescript
const result = await Dialogs.prompt({
    title: 'Input',
    message: 'Enter your name:',
    okButtonText: 'OK',
    cancelButtonText: 'Cancel',
    inputType: 'text'
});

if (result.result) {
    console.log('Input:', result.text);
}

Action #

typescript
const result = await Dialogs.action({
    title: 'Choose',
    message: 'Select an option:',
    cancelButtonText: 'Cancel',
    actions: ['Option 1', 'Option 2', 'Option 3']
});

console.log('Selected:', result);

最佳实践 #

组件复用 #

xml
<!-- components/user-card.xml -->
<GridLayout columns="auto, *" class="user-card">
    <Image src="{{ avatar }}" col="0" width="50" height="50" />
    <StackLayout col="1">
        <Label text="{{ name }}" class="name" />
        <Label text="{{ email }}" class="email" />
    </StackLayout>
</GridLayout>
xml
<!-- 使用组件 -->
<user-card user="{{ currentUser }}" />

性能优化 #

typescript
// 使用 itemLoading 优化 ListView
export function onItemLoading(args: ItemEventData) {
    const view = args.view;
    const item = args.bindingContext;
    
    // 复用视图,避免重复创建
    if (!view) {
        view = createItemView();
    }
    
    // 更新数据
    updateView(view, item);
}

下一步 #

现在你已经了解了 UI 组件,接下来学习 布局系统,掌握如何组织界面布局!

最后更新:2026-03-29