HarmonyOS 基础之PageSlider使用心得 原创 精华
中软国际AIoT开发者社区
发布于 2021-9-8 17:13
浏览
4收藏
在日常开发中,TabList与PageSlider经常搭配使用。针对这种情况,本文主要介绍TabList+PageSlider的使用方法和一些心得体会。
TabList基础用法
xml属性介绍:
属性 | description 描述 |
---|---|
normal_text_color | 未选中状态颜色 |
selected_text_color | 选中状态颜色 |
orientation | Tab排列方向 |
xml布局:
<TabList
ohos:id="$+id:tab_list"
ohos:height="match_content"
ohos:width="match_content"
ohos:layout_alignment="horizontal_center"
ohos:normal_text_color="$color:color_tab_normal"
ohos:orientation="horizontal"
ohos:selected_text_color="$color:white"
ohos:text_alignment="center"
ohos:text_size="12fp"
ohos:top_margin="$string:space_large"/>
Java Api介绍:
method 方法 | description 描述 |
---|---|
setTabMargin(int margin) | 设置组件中两个选项卡之间的边距 |
setTabLength(int length) | 设置每个选项卡的宽度 |
setTabTextSize(int size) | 设置每个选项卡的字体大小 |
getTabAt(int pos) | 获取TabList.Tab,常用来设置默认选中项 |
addTabSelectedListener(TabList.TabSelectedListener listener) | 选项卡被点击后回调 |
TabList.TabSelectedListener Api介绍:
method 方法 | description 描述 |
---|---|
onReselected(TabList.Tab tab) | 选项卡重新被选中时回调 |
onSelected(TabList.Tab tab) | 选项卡被选中时回调 |
onUnselected(TabList.Tab tab) | 选项卡被取消选中时回调 |
Java代码:
// 从根页面布局的xml文件中获取到TabList
mTabList = (TabList) getComponent().findComponentById(ResourceTable.Id_tab_list);
mTabList.setTabMargin(20);
// 为TabList配置页签项
for (String str : TAB_TITLES) {
TabList.Tab tab = mTabList.new Tab(getContext());
tab.setText(str);
mTabList.addTab(tab);
}
// 设置默认选择的页签项
mTabList.getTabAt(DEFAULT_INDEX).select();
PageSlider基础用法
xml布局:
<PageSlider
ohos:id="$+id:pager_slider"
ohos:height="match_parent"
ohos:width="match_parent"/>
Java Api介绍:
method 方法 | description 描述 |
---|---|
setOrientation(int orientation) | 设置页面滑动方向,可以是Component.HORIZONTAL或Component.VERTICAL |
setSlidingPossible(boolean enable) | 设置页面能否左右滑动,默认true |
setProvider(PageSliderProvider provider) | 为PageSlider设置适配器 |
addPageChangedListener(PageSlider.PageChangedListener listener) | 设置PageSlider页面改变时的监听 |
PageSliderProvider Api介绍:
method 方法 | description 描述 |
---|---|
getCount() | 返回要显示的页面个数 |
createPageInContainer(ComponentContainer container, int position) | 在指定的位置创建页面 |
destroyPageFromContainer(ComponentContainer container, int position, Object object) | 指定的位置页面销毁 |
isPageMatchToObject(Component page, Object object) | 判断组件是否与从 createPageInContainer(ohos.agp.components.ComponentContainer,int) 返回的特定对象相匹配 |
getPageTitle(int position) | 返回指定的位置页面的Title,自定义TabList会用到,用来显示选项卡标签 |
PageSlider.PageChangedListener Api介绍:
method 方法 | description 描述 |
---|---|
onPageChosen(int itemPos) | 页面被选中时回调 |
onPageSlideStateChanged(int state) | 页面状态改变时回调,值可以是 0、1 或 2,分别代表页面处于空闲、拖动或滑动状态 |
onPageSliding(int itemPos, float itemPosOffset, int itemPosOffsetPixels) | 页面滑动时回调 |
Java代码:
mPageViewList.clear();
mPageViewList.add(new RoundRectImageShaperTestPageView(getFractionAbility().getContext()));
mPageViewList.add(new CircleImageShaperTestPageView(getFractionAbility().getContext()));
mPageViewList.add(new ShapeSizeImageShaperTestPageView(getFractionAbility().getContext()));
ViewArrayPagerAdapter adapter = new ViewArrayPagerAdapter(mPageViewList);
mPageSlider.setProvider(adapter);
mPageSlider.addPageChangedListener(new PageChangeListener(mTabList));
完整工程代码:
<?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:orientation="vertical">
<TabList
ohos:id="$+id:tab_list"
ohos:height="match_content"
ohos:width="match_content"
ohos:layout_alignment="horizontal_center"
ohos:normal_text_color="$color:color_tab_normal"
ohos:orientation="horizontal"
ohos:selected_text_color="$color:white"
ohos:text_alignment="center"
ohos:text_size="12fp"
ohos:top_margin="$string:space_large"/>
<PageSlider
ohos:id="$+id:pager_slider"
ohos:height="match_parent"
ohos:width="match_parent"/>
</DirectionalLayout>
public class ImageShaperTestFraction extends Fraction {
private static final int DEFAULT_INDEX = 0;
private static final String[] TAB_TITLES = new String[]{"ROUND_RECT", "CIRCLE", "SHAPE_SIZE"};
private List<Component> mPageViewList = new ArrayList<>();
private TabList mTabList;
private PageSlider mPageSlider;
@Override
protected Component onComponentAttached(LayoutScatter scatter, ComponentContainer container, Intent intent) {
return scatter.parse(ResourceTable.Layout_image_shaper_test_fraction, container, false);
}
@Override
protected void onStart(Intent intent) {
super.onStart(intent);
mTabList = (TabList) getComponent().findComponentById(ResourceTable.Id_tab_list);
mTabList.setTabMargin(20);
for (String str : TAB_TITLES) {
TabList.Tab tab = mTabList.new Tab(getContext());
tab.setText(str);
mTabList.addTab(tab);
}
mPageSlider = (PageSlider) getComponent().findComponentById(ResourceTable.Id_pager_slider);
mPageViewList.clear();
for (String str : TAB_TITLES) {
mPageViewList.add(new TestView(getFractionAbility().getContext()));
}
ViewArrayPagerAdapter adapter = new ViewArrayPagerAdapter(mPageViewList);
mPageSlider.setProvider(adapter);
mPageSlider.addPageChangedListener(new PageChangeListener(mTabList));
mTabList.addTabSelectedListener(new TabSelectListener(mPageSlider));
// 设置默认选择的页签项
mTabList.getTabAt(DEFAULT_INDEX).select();
}
public class TabSelectListener implements TabList.TabSelectedListener {
private PageSlider pageSlider;
public TabSelectListener(PageSlider pageSlider) {
this.pageSlider = pageSlider;
}
@Override
public void onSelected(TabList.Tab tab) {
if (tab == null) {
return;
}
// TabList被点击,设置选中的页面
pageSlider.setCurrentPage(tab.getPosition(), true);
}
@Override
public void onUnselected(TabList.Tab tab) {
}
@Override
public void onReselected(TabList.Tab tab) {
}
}
}
public class ViewArrayPagerAdapter extends PageSliderProvider {
private List<Component> mList;
private String[] mTabTitles;
public ViewArrayPagerAdapter(List<Component> list) {
this.mList = list;
}
public ViewArrayPagerAdapter(List<Component> list, String[] tabTitles) {
this.mList = list;
this.mTabTitles = tabTitles;
}
@Override
public int getCount() {
return mList.size();
}
@Override
public Object createPageInContainer(ComponentContainer componentContainer, int i) {
componentContainer.addComponent(mList.get(i));
return mList.get(i);
}
@Override
public void destroyPageFromContainer(ComponentContainer componentContainer, int i, Object o) {
componentContainer.removeComponent(mList.get(i));
}
@Override
public boolean isPageMatchToObject(Component component, Object o) {
return component == o;
}
@Override
public String getPageTitle(int position) {
if (mTabTitles != null) {
//mTabTitles非空,可以返回选项卡内容
return mTabTitles[position];
}
return super.getPageTitle(position);
}
}
public class PageChangeListener implements PageSlider.PageChangedListener {
private TabList tabList;
public PageChangeListener(TabList tabList) {
this.tabList = tabList;
}
@Override
public void onPageSliding(int i, float v, int i1) {
}
@Override
public void onPageSlideStateChanged(int i) {
}
@Override
public void onPageChosen(int i) {
//页面被选中,修改TabList选项卡片状态
tabList.selectTab(tabList.getTabAt(i));
}
}
public class TestView extends DirectionalLayout {
public TestView(Context context) {
super(context, null);
initView();
}
public void initView() {
//布局初始化
LayoutScatter layoutScatter = LayoutScatter.getInstance(getContext());
Component view = layoutScatter.parse(ResourceTable.Layout_test_view, this, true);
}
}
PageSlider优化
当我们在写自定义控件TestView的时候,习惯性会在构造方法里调用initView()初始化布局
for (String str : TAB_TITLES) {
mPageViewList.add(new TestView(getFractionAbility().getContext()));
}
当数组TAB_TITLES长度很小时,感觉不出有什么问题,但如果长度有上千个,运行就会很卡,因为每new一次都会执行一次initView()
最后将mPageViewList加载到适配器显示出来就会很卡
优化思路
当PageSlider在滑动时,假设滑动到了第3页,那么第1、2、4、5…N页是看不见的,所以我们完全没必要将所有页一次性全加载出来
核心Api:
method 方法 | description 描述 |
---|---|
createPageInContainer(ComponentContainer componentContainer, int position) | 在指定的位置创建页面 |
优化方案
滑到指定页面时,会执行createPageInContainer方法,只需要在该方法里面进行页面布局的初始化即可
构造方法去掉页面布局初始化:
public class TestView extends DirectionalLayout {
public TestView(Context context) {
super(context, null);
//initView(); //注释掉布局初始化
}
public void initView() {
LayoutScatter layoutScatter = LayoutScatter.getInstance(getContext());
Component view = layoutScatter.parse(ResourceTable.Layout_test_view, this, true);
}
}
页面布局初始化调整到createPageInContainer:
@Override
public Object createPageInContainer(ComponentContainer componentContainer, int i) {
TestView testView = (TestView) mList.get(i);
testView.initView(); //核心修改
componentContainer.addComponent(mList.get(i));
return mList.get(i);
}
TabList优化
// 为TabList配置页签项
for (String str : TAB_TITLES) {
TabList.Tab tab = mTabList.new Tab(getContext());
tab.setText(str);
mTabList.addTab(tab);
}
当TAB_TITLES长度在7以上时,选项卡内容超过一屏,这个时候选中了第4页,可以看到第4页前面的选项卡没有自动又滑显示出来:
优化方案
使用自定义的TabList实现选项卡自动滑动效果,直接引用HarmonyOS三方件viewpagerindicator即可:
dependencies {
......
implementation 'io.openharmony.tpc.thirdlib:viewpagerindicator:1.0.0'
}
viewpagerindicator组件TabPageIndicator基础用法
<com.viewpagerindicator.TabPageIndicator
ohos:id="$+id:tab_list"
ohos:height="40vp"
ohos:width="match_parent"/>
ViewArrayPagerAdapter adapter = new ViewArrayPagerAdapter(mPageViewList, TAB_TITLES);
pageSlider.setProvider(adapter);
pageSlider.addPageChangedListener(new PageChangeListener(mTabList));
mTabList.setTabTextSize(AttrHelper.vp2px(12, getFractionAbility().getContext()));
mTabList.setTabMargin(20);
mTabList.setOrientation(Component.HORIZONTAL);
mTabList.setCentralScrollMode(true);
mTabList.setTabTextAlignment(TextAlignment.CENTER);
mTabList.setTabTextColors(getFractionAbility().getContext().getColor(ResourceTable.Color_color_tab_normal),
Color.WHITE.getValue());
mTabList.setSelectedTabIndicatorHeight(0);
mTabList.setViewPager(pageSlider);
mTabList.setFixedMode(false);
// 设置默认选择的页签项
mTabList.selectTab(mTabList.getTabAt(DEFAULE_INDEX));
改用TabPageIndicator实现后,点击Tab能自动滑动,效果图:
左右滑动系统自动回调Api:
method 方法 | description 描述 |
---|---|
onPageChosen(int itemPos) | 页面被选中时回调 |
点点击选项卡,调用setCurrentPage设置选中页:
@Override
public void onSelected(TabList.Tab tab) {
if (tab == null) {
return;
}
if (pageSlider != null) {
pageSlider.setCurrentPage(tab.getPosition());
}
}
两者流程存在差异,导致Canvas绘制的内容会概率性消失,论坛已有类似问题爆出,系统研发暂未给出解决方案,如下:论坛链接
作者:卢振
更多原创内容请关注:开鸿 HarmonyOS 学院
入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。
©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2021-9-10 15:35:31修改
赞
7
收藏 4
回复
相关推荐
很全面的总结,感谢分享。
优化思路好评!