UI 界面方面的细节问题。
UI
padding
是 内边距,margin
是 外边距
像素单位
vp:是针对应用而言的虚拟尺寸(区别于屏幕硬件本身的像素单位)。
vp = ( px * 160) / PPI
,PPI(Pixels per Inch),每英寸有多少个像素点。
代表的分辨率 |
屏幕分辨率 |
换算(px/vp) |
240 * 320 |
120 |
1 vp = 0.75 vp |
320 |
160 |
1 vp = 1 vp |
480 * 800 |
240 |
1 vp = 1.5 vp |
720 * 1280 |
320 |
1 vp = 2 vp |
1920 * 1080 |
480 |
1 vp = 3 vp |
fp:是大小单位,字体大小。
色彩
美学中的三原色:红黄蓝,但是在计算机中,采用光学三原色是:红、绿、蓝 ,用 0 ~ 255
来表示这三个颜色深浅。
- 色彩取值:例如:**#BF2568**,再这值中,BF,是红色,25,是绿色,68,是蓝色。为16进制数字。
- 透明度:在色彩取值中,可以加上透明度:**#00BF2568** ,00,代表全透明,范围是
00 ~ FF
。
- 省略问题:三组全相同则可以省略。如:**#778899**,可省略为 #789,而 #778896,不可省略。
权重
权重越大,占比越大。
细节问题
1 2 3 4 5 6 7
| <Text ... ohos:layout_alignment="right" ohos:right_margin="20vp"/>
|
常用组件
Text
长和宽的默认单位是:像素(px) ,但是可以自己指定单位(vp/px)。
自动换行
开启自动换行
1
| ohos:multiple_line="true"
|
设置最大行数
省略
可选值有以下几种
使用上述选值,需要配置以下属性,表示滚动的次数,值为:limited、数字。
1
| ohos:auto_scrolling_count="unlimited"
|
滚动速度:单位毫秒
1
| ohos:autoscrolling_duration="2000"
|
最后,还需要在Java代码中开启滚动效果(MainAbilityScilice),
1 2 3 4
| public void onClick(Component component) { text.startAutoScrolling(); }
|
- none:同理
- ellipsis_at_middle:同理
- ellipsis_at_start:前面的内容省略
- ellipsis_at_end:同理
1
| ohos:truncation_mode="ellipsis_at_start"
|
时钟组件-Clock
Clock 组件是 Text 组件的子类。
常用属性:
属性名称 |
功能说明 |
time |
设置开始时间(值为毫秒值) 如果写0,表示从1970年1月1日 0:0:0开始计时 该属性不写。默认是从当前时间开始计时 |
time_zoom |
时区 包括: GMT(格林威治标准时间) UTC(世界标准时间) CST(美国、澳大利亚、古巴或中国的标准时间) DST(夏令时)、 PDT(太平洋夏季时间) mode_24_hour 按照24小时显示的格式。值为指定的格式。 mode_24_hour 按照24小时显示的格式。值为指定的格式。 |
mode_24_hour |
按照24小时显示的格式。值为指定的格式。如:yyyy年MM月dd日 HH:mm:ss |
显示12小时制的: |
|
1 2
| ohos:mode_24_hour="false" ohos:mode_12_hour="yyyy年MM月dd日 HH:mm:ss"
|
注:在这里面的 y,M,d等形式,需要查阅 JavaAPI
常见方法:
方法名 |
功能说明 |
setTime(long time) |
传入时间的毫秒值 |
setTime(long time) |
传入时区 |
set24HourModeEnabled(boolean format24Hour) |
参数:false:不按24小时 true:按24小时 默认:true |
基本用法:
1 2 3 4
| <Clock ohos:height="match_content" ohos:width="match_content" ohos:text_size="30fp" />
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public static String dateToTimeStamp(String s) throws ParseException{ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = simpleDateFormat.parse(s); long ts = date.getTime(); String res = String.valueOf(ts); return res; }
public static String timeStampToDate(String s){ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); long lt = new Long(s); Date date = new Date(lt); String res = simpleDateFormat.format(date); return res; }
|
计时器组件-TickTimer
是Text的子类,所以可以使用Text的一些属性。
常见属性
属性名 |
功能说明 |
format |
设置显示的格式 |
count_down |
true倒着计时 false正着计时 |
常见方法
方法名 |
功能说明 |
start() |
启动计时器 |
stop() |
暂停计时器 |
setBaseTime(long base) |
设置基准时间,有bug |
setCountDown(boolean countDown) |
true:倒着计时,false:顺着计时 |
setFormat(String format) |
设置显示格式。默认格式为:分钟::秒钟 |
setTickListener |
计时监听 |
基本用法:
1 2 3 4 5 6 7 8 9 10 11 12
| <TickTimer ohos:id="$+id:my_tt" ohos:height="60vp" ohos:width="250vp" ohos:padding="10vp" ohos:text_size="20fp" ohos:text_color="#ffffff" ohos:background_element="#0000ff" ohos:text_alignment="center" ohos:layout_alignment="horizontal_center" ohos:top_margin="50vp" /> //没有设置时间,默认是从1970年1月1日开始。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| TickTimer tickTimer = (TickTimer)findComponentById(ResourceTable.Id_my_tt);
tickTimer.setFormat("mm:ss");
tickTimer.setTickListener(监听回调);
tickTimer.start();
tickTimer.stop();
Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { }); }},0,1000); timer.cancel();
|
TextField
是Text的子类,用来进行用户输入数据的。
常见属性
属性名称 |
功能说明 |
hint |
提示文字 |
basement |
输入框基线的颜色 |
element_cursor_bubble |
设置提示气泡 |
selection_color |
选中文字的颜色 |
element_selection_left_bubble |
设置选中之后左边的气泡 |
element_selection_right_bubble |
设置选中之后右边的气泡 |
text_input_type |
输入框中的输入类型(pattern_password密文展示) |
案例:
按下按钮查看密码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public class MainAbilitySlice extends AbilitySlice implements Component.TouchEventListener { TextField tf; @Override public void onStart(Intent intent) { super.onStart(intent); super.setUIContent(ResourceTable.Layout_ability_main); tf = (TextField) findComponentById(ResourceTable.Id_text); Button but = (Button) findComponentById(ResourceTable.Id_but); but.setTouchEventListener(this); } @Override public boolean onTouchEvent(Component component, TouchEvent touchEvent) { int action = touchEvent.getAction(); if(action == TouchEvent.PRIMARY_POINT_DOWN){ tf.setTextInputType(InputAttribute.PATTERN_NULL); }else if(action == TouchEvent.PRIMARY_POINT_UP){ tf.setTextInputType(InputAttribute.PATTERN_PASSWORD); } return true; } }
|
响应点击事件
方法一:自己编写类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public void MainAbilitySlice extends AbilitySlice { @Override public void onStart(Intent intent) { button.setClickedListener(new MyListener()); } }
class MyListener implements Component.ClickedListener{ @Override piblic void onClick(Component component) { } }
|
方法二:实现接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class MainAbilitySlice extends AbilitySlice implement Component.ClickedListener{ @Overrride public void onStart(Intent, intent) { button.setClickedListener(this); } @Override piblic void onClick(Component component) { } }
|
方法三:匿名内部类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class MainAbilitySlice extends AbilitySlice { @Overrride public void onStart(Intent, intent) { button.setClickedListener(new Component.ClickListener(){ @Override piblic void onClick(Component component) { } }); } @Override public void onActive() { super.onActive(); } @Override public void onForeground(Intent intent) { super.onForeground(intent); } }
|
方法四:方法引用
1 2 3 4 5 6 7 8 9 10 11
| public class MainAbilitySlice extends AbilitySlice { @Overrride public void onStart(Intent, intent) { button.setClickedListener(this::onClick); } public void onClick(Component component) { } }
|
禁用点击事件
1
| button.setClickable(false);
|
设置位置
1
| button.setTranslation();
|
双击事件
1 2 3 4 5 6 7 8 9 10 11 12
| public class MainAbilitySlice extends AbilitySlice implements Component.DoubleClickedListener { @Override public void onStart(Intent intent) { button.setDoubleClickedListener(this); } @Override public void onDoubleClicked(Component component) { } }
|
长按事件
1 2 3 4 5 6 7 8 9 10 11 12
| public class MainAbilitySlice extends AbilitySlice implements Component.LongClickedListener { @Override public void onStart(Intent intent) { button.setLongClickedListener(this); } @Override public void onLongClicked(Component component) { } }
|
滑动 / 触摸 事件
分为三个事件
- PRIMARY_POINT_DOWN:按下不松开
- POINT_MOVE:滑动
- PRIMARY_POINT_UP:抬起
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public class MainAbilitySlice extends AbilitySlice implements Component.TouchEvenListener { @Override public void onStart(Intent intent) { directionLayout.setTouchEvenListener(this); } float startX = 0; float startY = 0;
@Override public boolean onTouchEvent(Component component, TouchEvent touchEvent) { count++; int action = touchEvent.getAction(); if(action == touchEvent.PRIMARY_POINT_DOWN) { MmiPoint point = touchEvent.getPointerPosition(0); startX = point.getX(); startY = point.getY(); }else if(action == touchEvent.POINT_MOVE) { } else if(action == touchEvent.PRIMARY_POINT_UP) { } return true; } }
|
Checkbox
父类是AbsButton,而AbsButton的父类是Button。
常见属性
属性名称 |
功能说明 |
marked |
多选框的选中状态。true为选中,false为没有选中。 |
check_element |
自定义选择框的样式。样式需要跟marked的值对应。 |
常见方法
方法名称 |
功能说明 |
setChecked |
设置多选框的选中状态。true为选中,false为没有选中。 |
isChecked |
判断多选框的选中状态。true为选中,false为没有选中。 |
setCheckedStateChangedListener |
添加一个状态监听事件 |
基本用法
Image
背景:background_element
内容(前景):image_src
基本用法
1 2 3 4 5
| <Image ohos:height="100vp" ohos:width="100vp" ohos:image_src="$media:all" ohos:background_element="#00ff00"/>
|
裁切缩放
相关方法
方法名 |
功能说明 |
setClipGravity |
设置剪切对齐模式 |
setScaleMode |
当图像和组件的大小不同时,此方法可以缩放或者剪切图像 |
图片剪切显示:
图片缩放显示:
- 代码中:可以用setScaleMode方法
- xml文件中:可以用scale_mode属性
- inside:表示将原图按比例缩放到与Image相同或更小的尺寸,并居中显示。 有可能不会填充组件
- center:表示不缩放,按Image大小显示原图中间部分。
- stretch:表示将原图缩放到与Image大小一致。 拉伸。将组件填充。
- clip_center:表示将原图按比例缩放到与Image相同或更大的尺寸,并居中显示。超过组件的部分被剪 切掉。
- zoom_center:表示原图按照比例缩放到与Image最窄边一致,并居中显示。
- zoom_end:表示原图按照比例缩放到与Image最窄边一致,并靠结束端显示。
- zoom_start:表示原图按照比例缩放到与Image最窄边一致,并靠起始端显示。
注意:一般来讲在设置的时候会跟图片保持一致,否则图片会失真。
1 2 3 4 5 6
| <Image ohos:background_element="#00ff00" 缩放 ohos:scale_mode="zoom_center" 剪切 ohos:clip_alignment="top" />
|
左上角:left|top
单词之间得写在一起。
Dialog
CommonDialog
普通弹窗
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| CommonDialog cd = new CommonDialog(this); cd.setTitleText("系统定位服务已关闭"); cd.setContentText("请打开定位服务,以便司机师傅能够准确接您上车");
cd.setAutoClosable(true);
cd.setButton(0, "设置", new IDialog.ClickedListener() { @Override public void onClick(IDialog iDialog, int i) { } }); cd.setButton(1, "取消", new IDialog.ClickedListener() { @Override public void onClick(IDialog iDialog, int i) { cd.destroy(); } });
cd.show(); }
|
自定义弹窗
- 创建弹窗布局,xml布局文件
- 在Java类中配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| CommonDialog commonDialog= new CommonDialog(this);
cd.setCornerRadius(15);
DirectionalLayout directionalLayout = (DirectionalLayout) LayoutScatter.getInstance(this).parse(ResourceTable.Layout_messagedialog, null, false);
buttom_submit.setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { title.setText("点击了确定按钮"); } });
cancel.setClickedListener(new Component.ClickedListener() { public void onClick(Component component) { cd.destroy(); } });
cd.setContentCustomComponent(directionalLayout);
cd.show();
|
如果需要更复杂的弹框,只要丰富xml文件中的组件即可。
抽取工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class MyDialog { public static void showDialog(Context context,String msg){ CommonDialog cd = new CommonDialog(context); cd.setCornerRadius(15); DirectionalLayout dl = (DirectionalLayout) LayoutScatter.getInstance(context).parse(ResourceTable.Layout_messagedialog, null, false); Text title = (Text) dl.findComponentById(ResourceTable.Id_message); Button submit = (Button) dl.findComponentById(ResourceTable.Id_submit); Button cancel = (Button) dl.findComponentById(ResourceTable.Id_cancel); title.setText(msg);
submit.setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { title.setText("点击了确定按钮"); } });
cancel.setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { cd.destroy(); } });
cd.setContentCustomComponent(dl); cd.show(); } }
|
ToastDialog
吐司弹框。是 CommonDialog
的子类,用法基本相似,但是有自己特性。
也拥有标题,内容和按钮,但是我们只使用按钮。
1 2 3 4
| ToastDialog t = new ToastDialog(this); t.setText("要显示的内容") t.setAlignment(LayoutAlignment.CENTER); t.show();
|
相关设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| ToastDialog toastDialog = new ToastDialog(this);
toastDialog.setSize(DirectionalLayout.LayoutConfig.MATCH_CONTENT, DirectionalLayout.LayoutConfig.MATCH_CONTENT);
toastDialog.setDuration(2000);
toastDialog.setAutoClosable(true);
toastDialog.setAlignment(LayoutAlignment.CENTER);
toastDialog.setText("要显示的内容");
toastDialog.show();
|
自定义布局和抽取工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class MyToastUtils { public static void showDialog(Context context,String msg){ DirectionalLayout dl = (DirectionalLayout) LayoutScatter.getInstance(context).parse(ResourceTable.Layout_mytoast, null, false); ToastDialog td = new ToastDialog(context); td.setSize(DirectionalLayout.LayoutConfig.MATCH_CONTENT, DirectionalLayout.LayoutConfig.MATCH_CONTENT); td.setDuration(2000); td.setAutoClosable(true); td.setAlignment(LayoutAlignment.CENTER); td.setText(msg); td.show(); } }
|
偏移
接上面的代码,如果想换个位置,加上偏移即可。
进度条
ProgressBar
常见属性
属性名称 |
功能说明 |
orientation |
进度条的摆放 horizontal:水平 vertical:垂直 |
progress_color |
进度条颜色 |
progress_width |
进度条粗细 |
progress |
当前的进度值 |
max |
进度最大值 |
min |
进度最小值 |
progress_hint_text |
进度条文字 |
progress_hint_text_size |
进度条文字大小 |
progress_hint_text_color |
进度条文字颜色 |
progress_hint_text_alignment |
进度条文字对齐方式 |
常见方法
方法名 |
功能说明 |
setOrientation(int orientation) |
方向 |
setProgressWidth(int progressWidth) |
进度条的粗细 |
setMaxValue |
最大进度值 |
setMinValue |
最小进度值 |
setProgressValue(int progress) |
当前的进度值 |
setViceProgress(int progress) |
次一级进度值 (看电影时有个进度,电影的提前缓冲也有个进度) |
基本用法
1 2 3 4 5 6 7 8 9
| <ProgressBar ohos:height="50vp" ohos:width="300vp" ohos:progress_width="8vp" ohos:progress_color="#ff00ff" ohos:max="100" ohos:min="0" ohos:progress="20" ohos:top_margin="100vp" />
|
1 2 3 4 5 6 7 8 9
| ProgressBar progressBar = (ProgressBar) findComponentById(ResourceTable.Id_my_pgb); progressBar.setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { ProgressBar pgb = (ProgressBar) component; pgb.setProgressValue(pgb.getProgress()+5); } });
|
RoundProgressBar
是ProgressBar的子类,用法跟ProgressBar一模一样,只是显示的方式不一样。圆形进度条。
基本用法:
1 2 3 4 5 6 7 8 9 10 11
| <RoundProgressBar ohos:height="300vp" ohos:width="300vp" ohos:progress_hint_text="80%" ohos:progress_hint_text_size="50vp" ohos:progress_hint_text_color="#000000" ohos:progress="80" ohos:progress_width="20vp" ohos:progress_color="#FF0000" ohos:max="100" ohos:min="0"/>
|
ListContainer
ListContainer是用来呈现连续、多行数据的组件,包含一系列相同类型的列表项。
三个自有属性
rebound_effect
开启/关闭回弹效果
shader_color
着色器颜色
orientation
列表项排列方向
ListContainer 的使用方法
- 在布局中创建
ListContainer
- 再创建
ListContainer
的子布局
- 创建数据包装类
- 创建
Provider
类,继承自 BaseItemProvider
,重写方法
int getCount()
方法,返回填充的表项个数。
Object getItem(int position)
方法, 返回某一项的id。
Component getComponent(int position, Component covertComponent,ComponentContainer componentContainer)
方法,根据 position
返回对应的界面组件。
- 在Java代码(MainAbilitySlice)中添加 ListContainer 的数据,并适配其数据结构。
- listContainer 在 sampleItemProvider 初始化后修改数据。
示例,前三步略。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package com.felixcjy.mylistdemo;
public class SampleItem { private String name;
public SampleItem(String name) { this.name = name; }
public String getName() { return name; }
public void setName(String name) { this.name = name; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| public class SampleItemProvider extends BaseItemProvider {
private List<SampleItem> list; private AbilitySlice slice;
public SampleItemProvider(List<SampleItem> list, AbilitySlice slice) { this.list = list; this.slice = slice; }
@Override public int getCount() { return list == null ? 0 : list.size(); }
@Override public Object getItem(int position) { if (list != null && position >= 0 && position < list.size()) { return list.get(position); } return null; }
@Override public long getItemId(int position) { return position; }
@Override public Component getComponent(int position, Component convertComponent, ComponentContainer componentContainer) { final Component cpt; if (convertComponent == null) { cpt = LayoutScatter.getInstance(slice).parse(ResourceTable.Layout_item_sample, null, false); } else { cpt = convertComponent; } SampleItem sampleItem = list.get(position); Text text = (Text) cpt.findComponentById(ResourceTable.Id_item_index); text.setText(sampleItem.getName()); return cpt; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| public class MainAbilitySlice extends AbilitySlice { @Override public void onStart(Intent intent) { super.onStart(intent); super.setUIContent(ResourceTable.Layout_ability_main); initListContainer(); }
private void initListContainer() { ListContainer listContainer = (ListContainer) findComponentById(ResourceTable.Id_list_container); List<SampleItem> list = getData(); SampleItemProvider sampleItemProvider = new SampleItemProvider(list, this); listContainer.setItemProvider(sampleItemProvider);
list.add(new SampleItem("Item" + sampleItemProvider.getCount())); listContainer.setBindStateChangedListener(new Component.BindStateChangedListener() { @Override public void onComponentBoundToWindow(Component component) { sampleItemProvider.notifyDataChanged(); }
@Override public void onComponentUnboundFromWindow(Component component) {} });
listContainer.setItemClickedListener((container, component, position, id) -> { SampleItem item = (SampleItem) listContainer.getItemProvider().getItem(position); new ToastDialog(this) .setText("you clicked:" + item.getName()) .setAlignment(LayoutAlignment.CENTER) .show(); });
listContainer.setItemLongClickedListener((container, component, position, id) -> { SampleItem item = (SampleItem) listContainer.getItemProvider().getItem(position); new ToastDialog(this) .setText("you long clicked:" + item.getName()) .setAlignment(LayoutAlignment.CENTER) .show(); return false; }); }
private ArrayList<SampleItem> getData() { ArrayList<SampleItem> list = new ArrayList<>(); for (int i = 0; i <= 8; i++) { list.add(new SampleItem("Item" + i)); } return list; }
@Override public void onActive() { super.onActive(); }
@Override public void onForeground(Intent intent) { super.onForeground(intent); } }
|
美化组件
美化的文件写在 graphic
的包中。
形状美化
xmlns:ohos="http://schemas.huawei.com/res/ohos"
是命名空间。
根标签:属性 shape 的值:
子标签:
- stroke:边框设置
- bounds:边框设置
- top、right、left、bottom:上下左右单独设置。
- gradient:渐变
- shader_tyoe:有三个值
- sweep_gradient:暂时没有效果。
- radial_gradient:辐射渐变,solid中需要使用多个颜色。
- linear_gradient:线性渐变
- soild:背景色
- color:颜色
- colors:多个颜色,需要逗号隔开,
ohos:colors="#009911,#889977"
- corners:设置圆角
- radius:四个角同时设置,同理:left_top_y;left_top_x;left_bottom_y;left_bottom_x;right_bottom_y;right_bottom_x;right_top_y;right_top_x;
1 2 3 4 5 6 7 8
| <shape xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:shape="rectangle"> <stroke ohos:color="#21ABCD" ohos:width="2vp"/>
</shape>
|
状态美化
根标签:state-container
子标签:
- item
- state
- component_state_checked:开启状态
- component_state_pressed:按下不松开的状态
- component_state_empty:默认状态(必须要写在最下面)
- …
- element:可写颜色;可添加图片资源