「码动四季·开源同行」HarmonyOS应用开发:常见组件3(switch、slider、ListContainer、Picker)
本文介绍了HarmonyOS开发中常用的交互类组件和美化组件的方法。交互类组件包括Switch开关、Slider滑块、ListContainer列表容器、Picker选择器以及DatePicker/TimePicker时间选择器,详细说明了它们的属性设置、事件处理和实际应用场景。美化组件部分讲解了如何通过shape标签自定义组件形状(圆角、边框等),以及使用state-container标签实现不

一、交互类组件
1、Switch组件
实际开发中一般作为某些功能的开关。
一般开关的文字是不显示的。
一般只设置滑块和滑轨的颜色和样式。
- 滑道背景 :ohos:track_element="#FF0000"
- 滑块颜色 :ohos:thumb_element="#07C160"
练习:改变状态弹出吐司
XML文件:
<Switch
ohos:id="$+id:choose"
ohos:height="40vp"
ohos:width="100vp"
ohos:text_state_on="开"
ohos:text_state_off="关"
ohos:text_size="20vp"
/>
Java文件:
public class MainAbilitySlice extends AbilitySlice implements AbsButton.CheckedStateChangedListener {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
//找到开关组件
Switch choose = (Switch) findComponentById(ResourceTable.Id_choose);
//给开关组件绑定事件
//单击事件
//状态改变事件
choose.setCheckedStateChangedListener(this);
}
@Override
public void onActive() {
super.onActive();
}
@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
}
//当开关组件状态发生改变的时候,那么就会调用这个方法
//参数一:表示状态改变的那个开关组件
//参数二:表示组件当前的状态
@Override
public void onCheckedChanged(AbsButton absButton, boolean b) {
if(b){
//ToastUtils.showDialog(this,"开关开启了");
//可以打开某个设置
}else{
//ToastUtils.showDialog(this,"开关关闭了");
//可以关闭某个设置
}
}
}
开发中的switch:
开发中,switch一般是在设置中,作为开关使用的。
开启或者关闭之后,会把设置保存到本地或者上传给服务器进行保存。下一次打开APP的时候就不需要再次设置,使用上一次的设置记录即可。一般情况下,会在本地和服务器都保存一下。程序刚启动的时候,会读取本地的保存的设置,如果没有再访问服务器获取默认设置信息。或者每次修改完本地配置文件的时候,都会对文件进行一个算法加密,将计算出来的结果保存到服务器中,每次打开app的时候对比一下服务器和本地记录的是否一致,如果不一致,证明用户在没有联网的时候重新设置过了,会重新上传文件信息,如果一致就不上传。
2、Slider滑块组件
基本用法:
<Slider
ohos:height="50vp"
ohos:width="300vp"
进度颜色,左边的
ohos:progress_color="#FF0000"
滑块颜色
ohos:thumb_element="#00FF00"
未完成进度颜色
ohos:background_instruct_element="#0000FF"
次一级的进度值
ohos:vice_progress="80"
次一级的进度颜色
ohos:vice_progress_element="#923456"
是否允许用户操作滑块
ohos:enabled="true"
max = "100"
min = "0"
/>

相关事件:
ValueChangedListener(值改变事件)
接口中的方法:
- ①:onProgressUpdated(参数一,参数二,参数三)
当滑块组件中的值改变的时候,调用该方法。
参数一:滑块对象
参数二:当前进度值
参数三:当前滑块组件是否可以调节进度
- ②:onTouchStart
按上滑块的时候触发
- ③:onTouchend
离开滑块的时候触发
代码示例:
xml文件:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:alignment="center"
ohos:orientation="vertical">
<Slider
ohos:id="$+id:slider"
ohos:height="50vp"
ohos:width="300vp"
ohos:background_instruct_element="#0000FF"
ohos:enabled="true"
ohos:progress_color="#FF0000"
ohos:thumb_element="#00FF00"
ohos:vice_progress="80"
ohos:vice_progress_element="#923456"
ohos:max="100"
ohos:min="0"
/>
</DirectionalLayout>
Java文件:
public class MainAbilitySlice extends AbilitySlice implements Slider.ValueChangedListener {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
//找到滑块组件
Slider slider = (Slider) findComponentById(ResourceTable.Id_slider);
//给滑块组件绑定一个事件
//进度值改变事件
slider.setValueChangedListener(this);
}
//当滑块组件中的进度值改变的时候,就会调用这个方法
//参数一:滑块组件对象
//参数二:当前的进度值
//参数三:当前滑块是否可以被滑动
@Override
public void onProgressUpdated(Slider slider, int i, boolean b) {
ToastUtils.showDialog(this,"当前的进度值为:" + i);
}
//当用户用鼠标或者用手指
//按下滑块不松的时候,会调用该方法
@Override
public void onTouchStart(Slider slider) {
ToastUtils.showDialog(this,"按下不松");
}
//松开滑块的时候,会调用该方法。
@Override
public void onTouchEnd(Slider slider) {
ToastUtils.showDialog(this,"松开");
}
}
练习:相亲app
需求1:拖动滑块的同时放大或者缩小图片
需求2:移动图片
xml文件:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:alignment="center"
ohos:orientation="vertical">
<Image
ohos:id="$+id:img"
ohos:height="match_content"
ohos:width="match_content"
ohos:image_src="$media:girl1"/>
<Slider
ohos:id="$+id:slider"
ohos:height="50vp"
ohos:width="300vp"
ohos:background_instruct_element="#0000FF"
ohos:max="100"
ohos:min="0"
/>
</DirectionalLayout>
public class MainAbilitySlice extends AbilitySlice implements Slider.ValueChangedListener,
Component.TouchEventListener {
Image img;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
//业务逻辑
//1.滑动滑块之后,需要放大或者缩小妹子的照片
//2.可以拖动妹子的放大之后的照片
//找到图片组件还有滑块组件
img = (Image) findComponentById(ResourceTable.Id_img);
Slider slider = (Slider) findComponentById(ResourceTable.Id_slider);
//给滑块组件绑定事情
slider.setValueChangedListener(this);
//给图片绑定一个滑动事件(触摸事件)
img.setTouchEventListener(this);
}
//参数一:表示进度值变化的那个滑块组件对象
//参数二:表示当前进度值
//参数三:表示当前滑块是否可以被滑动
@Override
public void onProgressUpdated(Slider slider, int i, boolean b) {
//根据进度值i来放大或者缩小图片即可
if(i == 0){
i = 1;
}
float result = (float) (i * 0.1);
img.setScale(result,result);
}
//因为当我们按下滑块或者松开滑块的时候,暂时不需要做什么事情
//所以,下面的两个方法,在本案例中,暂时用不到
@Override
public void onTouchStart(Slider slider) {
//记录用户看美女的开始时间
}
@Override
public void onTouchEnd(Slider slider) {
}
//x1和y1表示手指按下不松的位置
float x1;
float y1;
float imgX;
float imgY;
//参数一:表示当前操作的组件对象。(图片)
//参数二:动作对象
//返回值:true 可以触发后续操作 false 只能触发第一个操作(按下不松)
@Override
public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
MmiPoint position = touchEvent.getPointerPosition(0);
int action = touchEvent.getAction();
if(action == TouchEvent.PRIMARY_POINT_DOWN){
// 按下不松 获取手指的位置
x1 = position.getX();
y1 = position.getY();
//获取图片的位置
imgX = img.getTranslationX();
imgY = img.getTranslationY();
}else if(action == TouchEvent.POINT_MOVE){
//移动手指
//获取的就是手指当前的位置
float moveX = position.getX();
float moveY = position.getY();
// 拿着手指当前的位置,跟x1和y1相减,就可以得到手指移动的距离
//x和y表示手指分别在x轴和y轴移动了多少距离
float x = moveX - x1;
float y = moveY - y1;
//把图片也移动这么多距离就可以
//是在图片原有位置的基础上,再移动x和y的距离
img.setTranslation(imgX + x , imgY + y);
}else if(action == TouchEvent.PRIMARY_POINT_UP){
//松开手指
//统计用户看美女的结束时间
//得到用户观看美女的总时间
}
return true;
}
}
3、ListContainer
概述:
ListContainer是一个列表容器类组件。在这里的每一行,我们都可以看做是一个item。如下图所示,包裹了所有item的红色的容器,就是ListContainer。
注意细节:
- ① 每一行其实就是一个独立的item。
- ② 在屏幕的上面和下面,还有很多没有展示出来的item。 当我们用手指往上滑动的时候,就可以到下面的item。 当我们用手指往下滑动的时候,就可以到上面的item。 只不过划出屏幕的item会被销毁,而没有划入屏幕的item 还没有创建出来。
- ③ 如果item过多,在内存会有垃圾。这个问题下面学习。

实现步骤:
- 1. 给item去指定一个布局xml文件
- 2. 书写一个javabean类表示item
- 3. 写一个适配器类去管理item
- 4. 将适配器交给ListContainer
代码实现:
子界面中的xml布局
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:alignment="center"
ohos:orientation="vertical">
<ListContainer
ohos:id="$+id:listcontainer"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:layout_alignment="horizontal_center"/>
</DirectionalLayout>
item的xml:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_content"
ohos:width="match_content"
ohos:orientation="horizontal">
<Text
ohos:id="$+id:text"
ohos:height="match_content"
ohos:width="match_content"
ohos:text="00:00"
ohos:text_size="20fp"/>
</DirectionalLayout>
Javabean类:
public class Item {
//记录的值就是赋值给item里面的text
private String text;
public Item() {
}
public Item(String text) {
this.text = text;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
适配器类:
public class ItemProvider extends BaseItemProvider {
//集合
//集合中就装了所有的item的对象。
private ArrayList<Item> list;
private AbilitySlice as;
public ItemProvider(ArrayList<Item> list, AbilitySlice as) {
this.list = list;
this.as = as;
}
public ArrayList<Item> getList() {
return list;
}
public void setList(ArrayList<Item> list) {
this.list = list;
}
public AbilitySlice getAs() {
return as;
}
public void setAs(AbilitySlice as) {
this.as = as;
}
//总数据的个数
//多少个item
@Override
public int getCount() {
return list.size();
}
//i 表示索引
//根据索引返回数据
@Override
public Object getItem(int i) {
if(list != null && i >= 0 && i < list.size()){
return list.get(i);
}
return null;
}
//返回某一项的id
@Override
public long getItemId(int i) {
return i;
}
//结论:
//1.加载一个item,就需要调用一次getComponent方法
//2.虽然索引为13的item还没有在界面中显示出来。
//3.当item划出屏幕的时候,item就会被销毁。
//如果页面再次往下滑动的时候,会再次调用getComponent方法。
//但是ListContainer也会进行预加载。
//返回item中要加载的布局对象
//参数一:当前要加载哪一行item (item的索引)
//参数二:表示要销毁的item的布局对象
//参数三:优化
@Override
public Component getComponent(int i, Component component, ComponentContainer componentContainer) {
DirectionalLayout dl = (DirectionalLayout) LayoutScatter.getInstance(as).parse(ResourceTable.Layout_itemview,
null, false);
}
//获取每一个item里面的数据
Item item = list.get(i);
//把数据加载到布局里面的Text中
Text text = (Text) dl.findComponentById(ResourceTable.Id_itemtext);
text.setText(item.getText());
//当上面的四行代码执行完毕之后,我就获取到了一个有数据的布局对象
//此时我们只要把布局对象dl返回出去就可以了
//其实就是因为在Item当中,最外层的就是这个dl布局对象
return dl;
}
}
AbilitySlice类:
public class MainAbilitySlice extends AbilitySlice {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
//找到ListContainer
ListContainer listContainer = (ListContainer) findComponentById(ResourceTable.Id_listcontainer);
//创建集合并给集合添加数据
ArrayList<Item> datasList = getData();
//创建一个Item的管理员对象(适配器对象)
//并把要展示的所有数据和要加载的页面传递过去
ItemProvider itemProvider = new ItemProvider(datasList,this);
//把适配器交给列表容器组件
listContainer.setItemProvider(itemProvider);
}
//以后这些数据,并不是我们在app中写的。
//都是服务器传递过来的。
public ArrayList<Item> getData(){
//访问服务器获取要展示的数据。
ArrayList<Item> list = new ArrayList<>();
//给集合添加数据
for (int i = 0; i < 100; i++) {
list.add(new Item("item" + i));
}
return list;
}
}
内存优化:
- 1. 加载一个item,getComponent方法就要被调用一次。
- 2. 假设屏幕中最多显示12个item,此时第13个item还没有在界面中显示出来。但是,ListContainer也会进行预加载。
预加载的好处:避免卡顿。
- 3. 当item划出屏幕的时候,就会被销毁。当页面再次往下滑动的时候,会再次调用getComponent方法,加载本地xml文件,创建一个新的item布局对象。当item加载过多,内存中的垃圾就会过多,所以我们要优化。
- 4. 优化的核心:让划出屏幕的item不销毁,而是继续复用
代码示例:
//但是ListContainer也会进行预加载。
//返回item中要加载的布局对象
//参数一:当前要加载哪一行item (item的索引)
//参数二:表示要销毁的item的布局对象
//参数三:优化
@Override
public Component getComponent(int i, Component component, ComponentContainer componentContainer) {
DirectionalLayout dl;
if(component != null){
dl = (DirectionalLayout)component;
}else{
//获取每一个item里面的布局对象
dl = (DirectionalLayout) LayoutScatter.getInstance(as).parse(ResourceTable.Layout_itemview, null, false);
}
//获取每一个item里面的数据
Item item = list.get(i);
//把数据加载到布局里面的Text中
Text text = (Text) dl.findComponentById(ResourceTable.Id_itemtext);
text.setText(item.getText());
//当上面的四行代码执行完毕之后,我就获取到了一个有数据的布局对象
//此时我们只要把布局对象dl返回出去就可以了
//其实就是因为在Item当中,最外层的就是这个dl布局对象
return dl;
}
练习:搭建微信页面
最终效果图:

xml文件:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:alignment="center"
ohos:orientation="vertical">
<ListContainer
ohos:id="$+id:listcontainer"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:layout_alignment="horizontal_center"/>
</DirectionalLayout>
item的xml文件:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_content"
ohos:width="match_content"
ohos:orientation="horizontal">
<Image
ohos:id="$+id:img"
ohos:height="match_content"
ohos:width="match_content"
ohos:image_src="$media:photo"/>
<DirectionalLayout
ohos:height="50vp"
ohos:width="240vp"
ohos:orientation="vertical"
ohos:left_margin="10vp">
<Text
ohos:id="$+id:title"
ohos:height="20vp"
ohos:width="240vp"
ohos:text="标题"
ohos:text_size="20fp"
ohos:top_margin="5vp"
/>
<Text
ohos:id="$+id:itemtext"
ohos:height="15vp"
ohos:width="240vp"
ohos:text="消息"
ohos:text_size="15fp"
ohos:top_margin="5vp"
/>
</DirectionalLayout>
<Text
ohos:id="$+id:time"
ohos:height="match_content"
ohos:width="match_content"
ohos:text="00:00"
ohos:text_size="20fp"/>
</DirectionalLayout>
Javabean类:
public class Item {
//记录的值就是赋值给item里面的text
private int img;
private String title;
private String text;
private String time;
public Item() {
}
public Item(int img, String title, String text, String time) {
this.img = img;
this.title = title;
this.text = text;
this.time = time;
}
public int getImg() {
return img;
}
public void setImg(int img) {
this.img = img;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
}
适配器类:
public class ItemProvider extends BaseItemProvider {
//集合
//集合中就装了所有的item的对象。
private ArrayList<Item> list;
private AbilitySlice as;
public ItemProvider(ArrayList<Item> list, AbilitySlice as) {
this.list = list;
this.as = as;
}
public ArrayList<Item> getList() {
return list;
}
public void setList(ArrayList<Item> list) {
this.list = list;
}
public AbilitySlice getAs() {
return as;
}
public void setAs(AbilitySlice as) {
this.as = as;
}
//总数据的个数
//多少个item
@Override
public int getCount() {
return list.size();
}
//i 表示索引
//根据索引返回数据
@Override
public Object getItem(int i) {
if(list != null && i >= 0 && i < list.size()){
return list.get(i);
}
return null;
}
//返回某一项的id
@Override
public long getItemId(int i) {
return i;
}
//结论:
//1.加载一个item,就需要调用一次getComponent方法
//2.虽然索引为13的item还没有在界面中显示出来。
//3.当item划出屏幕的时候,item就会被销毁。
//如果页面再次往下滑动的时候,会再次调用getComponent方法。
//但是ListContainer也会进行预加载。
//返回item中要加载的布局对象
//参数一:当前要加载哪一行item (item的索引)
//参数二:表示要销毁的item的布局对象
//参数三:优化
@Override
public Component getComponent(int i, Component component, ComponentContainer componentContainer) {
DirectionalLayout dl;
if(component != null){
dl = (DirectionalLayout)component;
}else{
//获取每一个item里面的布局对象
dl = (DirectionalLayout) LayoutScatter.getInstance(as).parse(ResourceTable.Layout_itemview, null, false);
}
//获取每一个item里面的数据
Item item = list.get(i);
//把数据加载到布局里面的Text中
Text text = (Text) dl.findComponentById(ResourceTable.Id_itemtext);
text.setText(item.getText());
//当上面的四行代码执行完毕之后,我就获取到了一个有数据的布局对象
//此时我们只要把布局对象dl返回出去就可以了
//其实就是因为在Item当中,最外层的就是这个dl布局对象
return dl;
}
}
AbilitySlice类:
public class MainAbilitySlice extends AbilitySlice {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
//找到ListContainer
ListContainer listContainer = (ListContainer) findComponentById(ResourceTable.Id_listcontainer);
//创建集合并给集合添加数据
ArrayList<Item> datasList = getData();
//创建一个Item的管理员对象(适配器对象)
//并把要展示的所有数据和要加载的页面传递过去
ItemProvider itemProvider = new ItemProvider(datasList,this);
//把适配器交给列表容器组件
listContainer.setItemProvider(itemProvider);
}
//以后这些数据,并不是我们在app中写的。
//都是服务器传递过来的。
public ArrayList<Item> getData(){
//访问服务器获取要展示的数据。
ArrayList<Item> list = new ArrayList<>();
//给集合添加数据
for (int i = 0; i < 100; i++) {
list.add(new Item(ResourceTable.Media_photo,"标题","item" + i,"00:00"));
}
return list;
}
}
4、Picker
基本用法:
picker是滑动选择器组件。在一些app中选择地址的时候会用到,但是一般是三个picker选择器组合在一起使用。
如图所示:

代码示例:
xml文件:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:alignment="center"
ohos:orientation="vertical">
<Picker
ohos:id="$+id:picker"
ohos:height="match_content"
ohos:width="100vp"
ohos:normal_text_size="20fp"
ohos:selected_text_size="20fp"
ohos:normal_text_color="#21a8fd"
ohos:selected_text_color="#FF0000"
ohos:max_value="6"
ohos:min_value="0"
ohos:value="0"
/>
</DirectionalLayout>
Java文件:
public class MainAbilitySlice extends AbilitySlice {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
//星期一 ~ 星期日
//1.找到滑动选择器Picker的对象
Picker picker = (Picker) findComponentById(ResourceTable.Id_picker);
//把要展示的内容全部放在集合中
ArrayList<String> list = new ArrayList<>();
list.add("星期一");
list.add("星期二");
list.add("星期三");
list.add("星期四");
list.add("星期五");
list.add("星期六");
list.add("星期日");
/*//2.给滑动选择器设置展示的内容
picker.setFormatter(
new Picker.Formatter() {
@Override
public String format(int i) {
//参数i表示当前选择的数字
//返回值就是要展示的内容。
//return i + "";
return list.get(i);
}
}
);*/
//优化
/* picker.setFormatter(
(int i)->{
return list.get(i);
}
);*/
// picker.setFormatter(i->list.get(i));
//还可以用方法引用去优化代码
picker.setFormatter(list::get);
}
}
练习:省市区三级联动
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:alignment="center"
ohos:orientation="horizontal">
<Picker
ohos:id="$+id:province"
ohos:height="match_content"
ohos:width="100vp"
ohos:normal_text_size="20fp"
ohos:selected_text_size="20fp"
ohos:value="0"/>
<Picker
ohos:id="$+id:city"
ohos:height="match_content"
ohos:width="100vp"
ohos:normal_text_size="20fp"
ohos:selected_text_size="20fp"
ohos:left_margin="10vp"
ohos:value="0"/>
<Picker
ohos:id="$+id:district"
ohos:height="match_content"
ohos:width="100vp"
ohos:normal_text_size="20fp"
ohos:selected_text_size="20fp"
ohos:left_margin="10vp"
ohos:value="0"/>
</DirectionalLayout>
public class Province {
//1.表示省份的名字
private String name;
//2.集合,记录省份里面所有城市的名字
private ArrayList<String> list;
public Province() {
}
public Province(String name, ArrayList<String> list) {
this.name = name;
this.list = list;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ArrayList<String> getList() {
return list;
}
public void setList(ArrayList<String> list) {
this.list = list;
}
}
public class MainAbilitySlice extends AbilitySlice implements Picker.ValueChangedListener {
Picker province;
Picker city;
Picker district;
ArrayList<Province> provinceList;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
//1.找到三个滑动选择器组件
province = (Picker) findComponentById(ResourceTable.Id_province);
city = (Picker) findComponentById(ResourceTable.Id_city);
district = (Picker) findComponentById(ResourceTable.Id_district);
//2.创建集合,用来存储,省,市,区的信息。
//省市的联动 和 市区的联动是一样的。
provinceList = getData();
//3.给三个滑动选择器组件设置默认显示数据
//要告诉滑动选择器,最大值展示到多少
province.setMaxValue(provinceList.size() - 1);
//暂时只给前面的省和市进行设置
province.setFormatter(i->provinceList.get(i).getName());
//要告诉滑动选择器,最大值展示到多少
city.setMaxValue(provinceList.get(0).getList().size() - 1);
city.setFormatter(i->provinceList.get(0).getList().get(i));
//给Picker滑动选择器绑定监听
province.setValueChangedListener(this);
}
//参数一:表示当前数据变动的那个滑动选择器对象
//参数二:表示旧值 (原来选中的值)
//参数三:表示新值(现在选中的值)
@Override
public void onValueChanged(Picker picker, int oldValue, int newValue) {
if(picker == province){
//判断当前选择的是哪个省
//选择哪个省,就可以把当前省对应的市设置到第二个滑动选择器中。
//获取到当前省份的对象
Province chooseProvince = provinceList.get(newValue);
//设置城市的滑动选择器
city.setMaxValue(chooseProvince.getList().size() - 1);
city.setFormatter(i->chooseProvince.getList().get(i));
//当前面更换省份的时候,中间的城市需要从第一个开始展示
city.setValue(0);
}
}
//在以后实际工作中
//这些数据,是不需要我们自己在app里面手动书写的
//一般是服务器给我们传递过来的。
public ArrayList<Province> getData(){
//创建一个集合用来存储所有的省份
ArrayList<Province> provinceList = new ArrayList<>();
//创建一个江苏省的集合,用来存储所有的城市
ArrayList<String> jiangSuCitys = new ArrayList<>();
jiangSuCitys.add("南京市");
jiangSuCitys.add("苏州市");
jiangSuCitys.add("无锡市");
jiangSuCitys.add("扬州市");
jiangSuCitys.add("徐州市");
jiangSuCitys.add("泰州市");
ArrayList<String> zheJiangCitys = new ArrayList<>();
zheJiangCitys.add("杭州市");
zheJiangCitys.add("宁波市");
zheJiangCitys.add("温州市");
zheJiangCitys.add("绍兴市");
zheJiangCitys.add("嘉兴市");
zheJiangCitys.add("舟山市");
ArrayList<String> fuJianCitys = new ArrayList<>();
fuJianCitys.add("福州市");
fuJianCitys.add("厦门市");
fuJianCitys.add("泉州市");
fuJianCitys.add("莆田市");
fuJianCitys.add("宁德市");
fuJianCitys.add("龙岩市");
//把省份的对象添加到provinceList集合中
provinceList.add(new Province("江苏省",jiangSuCitys));
provinceList.add(new Province("浙江省",zheJiangCitys));
provinceList.add(new Province("福建省",fuJianCitys));
//把存储所有省份的集合返回即可
return provinceList;
}
}
5 DatePicker和TimePicker
- DatePicker和TimePicker都是时间选择器。
- DatePicker:表示年月日
- TimePicker:表示时分秒
代码示例:
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:alignment="center"
ohos:orientation="vertical">
<DatePicker
ohos:id="$+id:datepicker"
ohos:height="match_content"
ohos:width="300vp"
ohos:normal_text_size="20fp"
ohos:selected_text_size="20fp"/>
<Text
ohos:id="$+id:text"
ohos:height="40vp"
ohos:width="300vp"
ohos:text_size="35fp"/>
<TimePicker
ohos:id="$+id:timepicker"
ohos:height="match_content"
ohos:width="300vp"
ohos:normal_text_size="20fp"
ohos:selected_text_size="20fp"/>
</DirectionalLayout>
public class MainAbilitySlice extends AbilitySlice implements DatePicker.ValueChangedListener {
Text text;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
//1.找到两个组件
DatePicker datePicker = (DatePicker) findComponentById(ResourceTable.Id_datepicker);
text = (Text) findComponentById(ResourceTable.Id_text);
TimePicker timePicker = (TimePicker) findComponentById(ResourceTable.Id_timepicker);
//2.给时间滑动选择器设置事件(监听)
datePicker.setValueChangedListener(this);
timePicker.setTimeChangedListener(new TimePicker.TimeChangedListener() {
@Override
public void onTimeChanged(TimePicker timePicker, int hour, int minutes, int second) {
text.setText("时间为:" + hour + minutes + second);
}
});
}
//每当datePicker里面的值发生改变的时候,系统都会自动的调用下面的方法
//参数一:表示值发生变动的DatePicker
//参数二~参数四:年、月、日
@Override
public void onValueChanged(DatePicker datePicker, int year, int month, int day) {
text.setText(year + "年" + month + "月" + day + "日");
//最简单,最不会出错的字符串和变量的拼接方法:
//先把最终的结果写在字符串中
//把其中有可能发生变化的值用变量替代
//再把变量挪到外面去
}
}
二、美化组件
1、美化组件分类
美化外形
- 组件外形(方形,圆角,胶囊形,圆形)
- 组件边框(颜色,粗细)
- 背景颜色(有色号就行)
- 背景渐变(线形或者辐射形)
美化状态
组件在不同状态时显示不同的样式。
暂时掌握三中状态:
- 默认状态 (所有组件都有默认状态)
- 按下状态 (组件按下不松时的状态)
- 选中状态 (开关组件,多选按钮,单选按钮的开启状态)
2、graphic包中的shape标签:
在graphic包中新建xml,根标签为:shape就可以自定义组件的形状。
根标签:shape
根标签包含一个属性:shape
可以取以下5个值:
- rectangle:长方形
- oval:椭圆
根标签包含五个子标签:
① stroke:绘制边框
属性: 宽度,颜色
② corners:圆角
属性:
- radius半径
- left_top_x、left_top_y 左上
- right_top_x、right_top_y 右上
- left_bottom_x、left_bottom_y 左下
- right_bottom_x、right_bottom_y 右下
③ solid:背景填充
属性:
- color 只能指定一个颜色
- colors 可以指定多个颜色,渐变。
④ bounds:边框
可以单独设置上下左右的边框。
⑤ gradient:渐变
属性:
shader_type:类型 --- radial(辐射) linear(线性)
3、graphic包中的state-container标签:
在graphic包中新建xml,根标签为:state-container就可以在不同状态下美化组件
- 默认状态: component_state_empty
- 按下不松的状态: component_state_pressed
- 打开状态: component_state_checked
细节:
- 1. component_state_empty必须要写在最下面。否则其他状态的设置不起作用。
- 2. element中可以写指定的色号,也可以指定根标签为shape的xml文件。
- 3. element中可以指定固定的图片。
xml文件:
//按下
<item ohos:state="component_state_pressed" ohos:element="#000000"/>
//打开状态
<item ohos:state="component_state_checked" ohos:element="#FF0000"/>
//默认状态:要写在最下面
<item ohos:state="component_state_empty" ohos:element="#21a8f6"/>
</state-container>
4、实际开发中的美化组件
情况一: 美工已经把图片给你做好
这种情况最简单,我们只要在state-container里面指定状态并关联图片即可。
<Button
ohos:height="32vp"
ohos:width="86vp"
ohos:background_element="$graphic:press2"
ohos:text_alignment="center"
ohos:text_size="20fp"
ohos:clickable="true"
/>
<item ohos:state="component_state_pressed" ohos:element="$media:registerpress"/>
<item ohos:state="component_state_empty" ohos:element="$media:register"/>
情况二: 美工没有把图片给你做好。
这种情况稍显复杂,你可以给美工提出需求。如果人家不鸟咱,咱就要自己写。
写法如下:
核心:针对于每一种状态都要写对应的xml文件。
针对于两种状态关联对应的xml文件
<item ohos:state="component_state_pressed" ohos:element="$media:registerpress"/>
<item ohos:state="component_state_empty" ohos:element="$media:register"/>
正常状态:
<corners
ohos:radius="15vp"
/>
<solid
ohos:colors="#21a8fd"
/>
按下不松时的状态:
<corners
ohos:radius="15vp"
/>
<solid
ohos:colors="#0177BE"
/>更多推荐


所有评论(0)