鸿蒙页面滑动组件,代码已开源!

暴走的小巨人 2021-08-24 15:04:21 4647

基于安卓平台的页面滑动组件 ViewPagerIndicator,实现了鸿蒙化迁移和重构,代码已开源,目前已经获得了很多人的 Star 和 Fork,欢迎各位下载使用并提出宝贵意见!

开源代码:
https://gitee.com/isrc_ohos/view-pager-indicator

ViewPagerIndicator_ohos 是一个信息展示组件,适用于展示新闻类、购物类等复杂信息。使用传统的页面展示内容时,同种类的信息在同一个页面上展示。

使用 ViewPagerIndicator_ohos 组件展示内容时,一个种类的信息可以在多个页面展示,用户通过滑动屏幕的方式来实现页面切换。

二者的效果对比如图 1 所示:

图 1:ViewPagerIndicator_ohos 组件与传统的页面在展示内容时的区别

组件效果展示

组件应用的主界面中有 3 个按钮,其中,“主页”和“我的”按钮展示的是组件的局部效果,“社区”按钮展示的是组件的整体效果。

此处,我们不再赘述局部效果,直接讲解组件的整体效果,有对其余两个按钮的功能感兴趣的朋友可以下载源码了解。

当用户点击应用底部导航栏区“社区”标签时,组件向用户展示“社区”板块的内容,内容分布在多个页面内。

在应用的顶部有页面指示器,用户可以通过两种方式实现页面的切换效果:

滑动屏幕时,页面随滑动切换,页面指示器始终指示当前正在展示的页面。

点击页面指示器,页面会切换到被选中的指示器所指示的页面。

效果如图 2 所示:

图 2:滑动页面同时指示器显示当前页面功能

Sample 解析

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

①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;
}
}

②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();
//将页面装入ArrayList
pages = new ArrayList();
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 所示:

图 3:Library 部分的工程结构

indicator 文件夹包括 CommunityTabListener、FixedIndicatorView 和 TabListener(在“我的”板块被引用,因此不作详细讲解)。

viewpager 文件夹包括 PagerAdapter 和 ViewPager。接下来将针对上述文件进行具体讲解。

①页面指示器功能实现

(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);
}

②页面管理功能实现

(1)PagerAdapter 功能实现

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

setPages() 方法将已经创建好的页面传入适配器。createPageInContainer() 方法用于在特定的位置添加 Page。

在刚载入 ViewPager 的时候,默认显示第一个页面,页面加载需要调用 createPageInContainer() 方法。

第一个页面显示后,用户可能会立刻滑动屏幕,切换到相邻的页面,为了页面的顺滑切换。

在第一个页面显示的同时,相邻页面也需要调用 createPageInContainer() 方法加载出来。

因此在载入 ViewPager 的时候,createPageInContainer() 方法被调用了两遍。

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

//页面管理适配器
public class PagerAdapter extends PageSliderProvider {
private ArrayList pages;
//创建页面所需元件
public void setPages(ArrayList 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();
}
}

来源:鸿蒙技术社区

声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
红包 93 收藏 评论 打赏
评论
0个
内容存在敏感词
手气红包
    易百纳技术社区暂无数据
相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
暴走的小巨人
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区