鸿蒙开源第三方组件——页面滑动组件 ViewPagerIndicator_ohos 原创 精华

朱伟ISRC
发布于 2021-8-20 16:04
浏览
17收藏

 前言

         基于安卓平台的页面滑动组件ViewPagerIndicator(https://github.com/LuckyJayce/ViewPagerIndicator),实现了鸿蒙化迁移和重构,代码已经开源到(https://gitee.com/isrc_ohos/view-pager-indicator),目前已经获得了很多人的Star和Fork,欢迎各位下载使用并提出宝贵意见!

背景

         ViewPagerIndicator_ohos是一个信息展示组件,适用于展示新闻类、购物类等复杂信息。使用传统的页面展示内容时,同种类的信息在同一个页面上展示。使用ViewPagerIndicator_ohos组件展示内容时,一个种类的信息可以在多个页面展示,用户通过滑动屏幕的方式来实现页面切换,二者的效果对比如图1所示。

鸿蒙开源第三方组件——页面滑动组件 ViewPagerIndicator_ohos-鸿蒙开发者社区  图1 ViewPagerIndicator_ohos组件与传统的页面在展示内容时的区别

组件效果展示

       组件应用的主界面中有3个按钮,其中,“主页”和“我的”按钮展示的是组件的局部效果,“社区”按钮展示的是组件的整体效果。此处,我们不再赘述局部效果,直接讲解组件的整体效果,有对其余两个按钮的功能感兴趣的朋友可以下载源码了解。

       当用户点击应用底部导航栏区“社区”标签时,组件向用户展示“社区”板块的内容,内容分布在多个页面内。在应用的顶部有页面指示器,用户可以通过两种方式实现页面的切换效果:1)滑动屏幕时,页面随滑动切换,页面指示器始终指示当前正在展示的页面。2)点击页面指示器,页面会切换到被选中的指示器所指示的页面,效果如图2所示。

鸿蒙开源第三方组件——页面滑动组件 ViewPagerIndicator_ohos-鸿蒙开发者社区   图2 滑动页面同时指示器显示当前页面功能

Sample解析

         Sample部分主要用于构建显示布局,MainAbilitySlice文件负责构建应用主界面布局,CommunityFraction文件负责构建页面和页面指示器布局,CommunityFraction形成的UI以Fraction的形式嵌入到主界面布局中。

1、MainAbilitySlice文件

         MainAbilitySlice文件负责构建组件应用的主界面布局,下面给出布局构建的具体步骤:

         第1步:设置组件应用的布局文件

         组件的主界面布局定义在ability_main.xml中,界面包含三个Button和一个StackLayout,前者表示“主页”、“我的”和“社区”按钮,后者表示内容显示页面。通过setUIContent()方法将ability_main.xml文件设置为组件应用的主界面布局。

super.setUIContent(ResourceTable.Layout_ability_main);

        第2步:按钮的定位

        在MainAbilitySlice文件的OnStart()方法中,通过findComponentById()的方法实现第1步中“社区”按钮的定位。

 //“主页”、“我的”和“社区”按钮
private Button basebtn,mybtn,communitybtn;
......
//定位“社区”按钮      
communitybtn= (Button) findComponentById(ResourceTable.Id_main_community_btn);

         第3步:按钮监听

         给“社区”按钮设置点击事件,点击按钮时,将表示社区内容的CommunityFraction嵌入到第1步的StackLayout中,实现点击“社区”按钮后的显示效果。

   //设置按钮监听
   communitybtn.setClickedListener(this);
   ......
  @Override
    public void onClick(Component component) { //点击事件
        switch (component.getId()){
            ......
            case ResourceTable.Id_main_community_btn:
               displayCommunityFraction(); //将CommunityFraction嵌入主界面布局
                break;
            default:
                break;
        }
    }

  2、CommunityFraction文件

        CommunityFraction类继承自Fraction类,作为整体显示布局的一部分嵌入MainAbility中,不能单独使用。CommunityFraction文件负责构建页面和页面指示器布局,此处使用ViewPager对象管理页面切换,使用TabList创建页面指示器,将ViewPager里的页面与TabList里的Tab按顺序绑定,以实现组件效果展示中描述的效果,下面给出具体的实现步骤。

         第1步:创建CommunityFraction文件的布局

         fraction_community.xml是CommunityFraction文件的布局文件,布局中包含一个ViewPager和一个TabList。通过LayoutScatter类对象的parse()方法将fraction_community.xml形成一个Component 对象,方便后续的步骤使用。

Component component = scatter.parse(ResourceTable.Layout_fraction_community, container, false); 

        第2步:导入相关类并声明对象

        在CommunityFraction文件中导入ViewPager、PagerAdapter类,其中ViewPager类继承自PageSlider类,通过响应屏幕滑动完成页面之间的切换;PagerAdapter类继承自PageSliderProvider类,提供了页面项管理功能。

       导入ohos.agp.components下的所有类,其中包含用于创建页面指示器的TabList类,和用于设置TabList的监听和样式FixedIndicatorView类。

import com.shizhefei.view.indicator.CommunityTabListener;
import com.shizhefei.view.indicator.FixedIndicatorView;
import com.shizhefei.view.viewpager.PagerAdapter;
import com.shizhefei.view.viewpager.ViewPager;
public class CommunityFraction extends Fraction {
    ......
    private ViewPager viewPager;
    private PagerAdapter adapter;
    private Component component ;
    private TabList tabList;
    .....
}

        第3步:创建不同的页面

        因为CommunityFraction类继承自Fraction类,因此需要重写onComponentAttached()方法,当CommunityFraction被添加到主界面布局时,此方法被调用。在onComponentAttached()方法中,用xml的方式创建三个不同的显示页面,分别为“页面1”、“页面2”、“页面3”。   

@Override
protected Component onComponentAttached(LayoutScatter scatter, ComponentContainer container, Intent intent) {
         ......
         DirectionalLayout directionalLayout1 = (DirectionalLayout) scatter.parse(ResourceTable.Layout_page1, null, false); //页面1
         DirectionalLayout directionalLayout2 = (DirectionalLayout) scatter.parse(ResourceTable.Layout_page2, null, false);  //页面2
         DirectionalLayout directionalLayout3 = (DirectionalLayout) scatter.parse(ResourceTable.Layout_page3, null, false);  //页面3
         ......
}

          同时创建一个元素类型为Component的ArrayList(数组列表),将上述创建的三个页面依次添加到ArrayList中。     

        //创建ArrayList
        pages = new ArrayList<Component>();
        //将页面装入ArrayList
        pages = new ArrayList<Component>();
        pages.add(directionalLayout1);
        pages.add(directionalLayout2);
        pages.add(directionalLayout3);

        第4步:创建页面指示器

        首先定义一个String类型的数组,数组的长度决定页面指示器的个数,数组的元素决定页面指示器上的内容。

        然后创建一个TabList 类对象,通过findComponentById()方法定位到fraction_community.xml中的TabList。

        最后使用for循环,将数组里的内容逐个设置为TabList 里各Tab的文本。

private String[] str={"主页1","主页2","主页3"};
......
        this.tabList = tabList;
        if(this.tabList!=null){ 
            for(int i=0;i<str.length;i++){ //页面数量小于之前设定的tab标签数量
                TabList.Tab tab = this.tabList.new Tab(getContext());
                tab.setText(str[i]);
                tabList.addTab(tab);
            }
        }
        //tabList初始化默认选择第一个tab
        this.tabList.selectTabAt(0);

        第5步:ViewPager载入页面

       首先实例化ViewPager类对象,定位到fraction_community.xml里的ViewPager;并实例化PagerAdapter类对象,形成页面管理适配器。然后通过setPages()方法将第3步中包含三个页面的ArrayList传入适配器中。最后将适配器和上述ViewPager对象绑定,即可实现滑动屏幕后多个页面来回切换的效果。

        viewPager = (ViewPager)mcomponent.findComponentById(ResourceTable.Id_pageslider_community); //定位ViewPager
        adapter = new PagerAdapter(); //实例化PagerAdapter类对象
        adapter.setPages(pages); //传入包含三个页面的ArrayList
        viewPager.setProvider(adapter);

        第6步:实现TabList跟随页面切换而变化

        为ViewPager添加页面滑动监听事件,当页面切换时,执行相应操作来实现TabList跟随页面切换而变化的效果。onPageChosen()方法用于设置当页面处于被选中状态时执行的操作,在重写方法该方法时,需传入当前被选中的(正在显示的)页面的编号i,并将tabList中相应编号的Tab设置为选中状态。

viewPager.addPageChangedListener(new PageSlider.PageChangedListener() {
            // 页面滑动转换过程中调用
            .......
            @Override
            public void onPageChosen(int i) {   // i表示页面编号
                        tabList.selectTabAt(i);  // tabIndicator随页面滑动切换而改变
            }
});

        第7步:绑定TabList并使其按固定大小平均排列

        通过CommunityTabListener类的setViewPager()方法能够将ViewPager和TabList绑定;FixedIndicatorView类的setFixedIndicator()方法能够固定TabList中各Tab的尺寸,实现等距离平均排列的效果。   

        FixedIndicatorView fixedIndicatorView = new FixedIndicatorView(str,this.tabList);
        //CommunityTabListener实现了TabList.TabSelectedListener
        CommunityTabListener tabListener=new CommunityTabListener();
        tabListener.setViewPager(viewPager);
        //设置TabList 监听
        fixedIndicatorView.setTabListListener(tabListener);
        //设置TabList UI风格
        fixedIndicatorView.setIndicatorStyle(TabList.INDICATOR_BOTTOM_LINE);
        //设置TabList的各Tab的长度固定且相等
        fixedIndicatorView.setFixedIndicator(true);

Library解析

        ViewPagerIndicator_ohos组件的关键功能包括ViewPager页面切换和TabList页面指示器切换。Library按照上述两个功能划分为两个文件:indicator文件、viewpager文件,如图3所示。

       indicator文件夹包括CommunityTabListener、FixedIndicatorView、和TabListener(在“我的”板块被引用,因此不作详细讲解);viewpager文件夹包括PagerAdapter和ViewPager。接下来将针对上述文件进行具体讲解。

鸿蒙开源第三方组件——页面滑动组件 ViewPagerIndicator_ohos-鸿蒙开发者社区 图 3 Library部分的工程结构

1、页面指示器功能实现

       (1) CommunityTabListener功能实现

         页面指示器中的各Tab标签中设有监听,点击不同的Tab可以切换至不同的页面,具体效果可参考图2。

       上述功能具体由CommunityTabListener类来完成,该类实现了TabList类的TabSelectedListener接口。在此接口中,主要重写三个函数:onSelected()、onUnSelected()、和onReselected(),分别负责设置当页面上tab被选中、未被选中、以及被释放时的行为。此处设置:当Tab被选中时,页面切换到Tab指示的页面。

public class CommunityTabListener implements TabList.TabSelectedListener {
private ViewPager mviewPager;
    @Override
    //页面指示器的某个Tab被选中时调用该方法
    public void onSelected(TabList.Tab tab) {
        int i = tab.getPosition();//获取当前Tab的位置
        if(i>=0){//当前tab位置大于0
            mviewPager.setCurrentPage(i);// 页面切换到Tab指示的页面
        }
   }

   @Override
   //页面没有被选中时
    public void onUnselected(TabList.Tab tab) {
    }

   @Override
   //页面重新被选中时
    public void onReselected(TabList.Tab tab) {
}

    //ViewPager 传入
    public void setViewPager(ViewPager viewPager) {
       this.mviewPager = viewPager; 
    }
}

      (2) FixdIndicatorView功能实现

        FixedIndicatorView类用于设置TabList监听事件和UI样式。其中,setTabListListener()方法用来设置指示器的监听;setFixedIndicator()方法用来固定TabList中各Tab的尺寸和位置,实现个Tab大小相等且平均排列分布的效果。

//设置页面指示器的监听
public void setTabListListener(TabList.TabSelectedListener tabSelectedListener){
        tabList.addTabSelectedListener(tabSelectedListener);
}

//设置页面指示器的UI风格
    public void setIndicatorStyle(int style){
        this.tabList.setIndicatorType(style);
}

//设置页面指示器的Tab尺寸固定且相等
    public void setFixedIndicator(boolean b){
        tabList.setFixedMode(b);
 }

2、页面管理功能实现

       (1)PagerAdapter 功能实现

          页面管理适配器由PagerAdapter类来完成,其主要用于和上述ViewPager类对象绑定,可实现滑动屏幕时多个页面切换,提供了页面项管理功能。

         setPages()方法将已经创建好的页面传入适配器。

         createPageInContainer()方法用于在特定的位置添加Page。在刚载入ViewPager的时候,默认显示第一个页面,页面加载需要调用createPageInContainer()方法。第一个页面显示后,用户可能会立刻滑动屏幕,切换到相邻的页面,为了页面的顺滑切换,在第一个页面显示的同时,相邻页面也需要调用createPageInContainer()方法加载出来,因此在载入ViewPager的时候,createPageInContainer()方法被调用了两遍。

        destroyPageFromContainer()方法用于销毁某个特定的界面。ViewPager会同时缓存3个页面,当我们创建的显示页面多于3个时,需要在ViewPager中销毁多余页面,防止程序崩溃。

//页面管理适配器
public class PagerAdapter extends PageSliderProvider {
    private ArrayList<Component> pages;
    //创建页面所需元件
    public void setPages(ArrayList<Component> pages) {
        this.pages = pages;
    }
    @Override
    //获取页面数量及大小
    public int getCount() {
        return pages.size();
    }
    @Override
    //特定位置创建页面
    public Object createPageInContainer(ComponentContainer componentContainer, int i) {
        componentContainer.addComponent(pages.get(i));
        return pages.get(i);
    }
    @Override
    //删除特定页面
    public void destroyPageFromContainer(ComponentContainer componentContainer, int i, Object o) {
        componentContainer.removeComponent(pages.get(i));
    }
    //判定是否为同一张Page
    @Override
    public boolean isPageMatchToObject(Component component, Object o) {
        return component==o;
    }
}

      (2)ViewPager 功能实现

        滑动页面功能由ViewPager类来完成,该类继承自PageSlider,其主要用于通过响应屏幕滑动完成页面之间的切换,类中预留了三个接口:slideLock()、setCanSlide()、isCanScroll(),用户可以在开发其他功能时调用此接口。isCanScroll()方法判断页面是否可以滑动,slideLock()方法设置页面不可滑动,setCanSlide()方法设置页面可以滑动。

//接口预留
public class ViewPager extends PageSlider {
   ......
    //设置页面不可以滑动
    public void slideLock() {
        this.setSlidingPossible(false);
    }
    //设置页面可以滑动
    public void setCanSlide() {
       this.setSlidingPossible(true);
    }
    //判断页面是否可以滑动
    public boolean isCanScroll() {
        return getSlidingPossible();
    }
}

 

项目贡献人

徐泽鑫 郑森文 朱伟 陈美汝 张馨心 李珂

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2021-8-20 16:26:09修改
20
收藏 17
回复
举报
23条回复
按时间正序
/
按时间倒序
上海至金黄色
上海至金黄色

2楼!

回复
2021-8-20 16:19:24
陈美汝ISRC
陈美汝ISRC

等来了朱老师的分享!

1
回复
2021-8-20 16:22:44
爱停留
爱停留

好耶!每周五都在等着朱伟老师的文章学习!

回复
2021-8-20 16:26:03
朱伟ISRC
朱伟ISRC 回复了 爱停留
好耶!每周五都在等着朱伟老师的文章学习!

谢谢支持!

回复
2021-8-20 16:26:58
D1124
D1124

太强了

回复
2021-8-20 16:27:29
朱伟ISRC
朱伟ISRC 回复了 陈美汝ISRC
等来了朱老师的分享!

mua~

1
回复
2021-8-20 16:27:31
朱伟ISRC
朱伟ISRC 回复了 上海至金黄色
2楼!

严谨!

1
回复
2021-8-20 16:27:48
wx5ffd018cae88e
wx5ffd018cae88e

这个可以试试用,感觉不错哦

1
回复
2021-8-20 17:11:57
朱伟ISRC
朱伟ISRC 回复了 wx5ffd018cae88e
这个可以试试用,感觉不错哦

谢谢支持!

回复
2021-8-20 17:56:50
爱吃土豆丝的打工人
爱吃土豆丝的打工人

学习学习~

1
回复
2021-8-22 17:51:47
朱伟ISRC
朱伟ISRC 回复了 爱吃土豆丝的打工人
学习学习~

共同学习!

1
回复
2021-8-23 09:05:03
Junfeng0613
Junfeng0613

很实用的组件,终于不用重复造轮子了

回复
2021-8-26 16:34:53
鱼儿会飞啦啦啦
鱼儿会飞啦啦啦

小姐姐依然优秀,文章非常棒棒哒

回复
2021-8-26 16:37:47
大白兔的耳朵
大白兔的耳朵

支持支持,

回复
2021-8-26 16:39:12
朱伟ISRC
朱伟ISRC 回复了 Junfeng0613
很实用的组件,终于不用重复造轮子了

谢谢支持!

1
回复
2021-8-26 16:40:39
朱伟ISRC
朱伟ISRC 回复了 鱼儿会飞啦啦啦
小姐姐依然优秀,文章非常棒棒哒

么么~

1
回复
2021-8-26 16:40:49
朱伟ISRC
朱伟ISRC 回复了 大白兔的耳朵
支持支持,

谢谢!

1
回复
2021-8-26 16:41:02
麒麟Berlin
麒麟Berlin

前几天才移植的这个库,感觉你这功能差很多哦

回复
2021-8-28 14:13:56
朱伟ISRC
朱伟ISRC 回复了 麒麟Berlin
前几天才移植的这个库,感觉你这功能差很多哦

请问你的组件开源了吗?我想去膜拜一下!

回复
2021-8-29 22:53:46
麒麟Berlin
麒麟Berlin 回复了 朱伟ISRC
请问你的组件开源了吗?我想去膜拜一下!

审核中。。。

1
回复
2021-8-30 15:04:10
回复
    相关推荐