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