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页前面的选项卡没有自动又滑显示出来:
HarmonyOS 基础之PageSlider使用心得-鸿蒙开发者社区

优化方案

使用自定义的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能自动滑动,效果图:
HarmonyOS 基础之PageSlider使用心得-鸿蒙开发者社区

左右滑动系统自动回调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
回复
举报
2条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

很全面的总结,感谢分享。

回复
2021-9-9 10:03:15
Anzia
Anzia

优化思路好评!

回复
2021-9-9 10:51:23
回复
    相关推荐