鸿蒙开源组件——仿Chrome浏览器中Tab切换的库
Component component = // ... inflate component
tabSwitcher.setEmptyView(component);
ChromeLikeTabSwitcher
项目介绍
- 项目名称:ChromeLikeTabSwitcher
- 所属系列:openharmony的第三方组件适配移植
- 功能:ChromeLikeTabSwitcher是一个仿Chrome浏览器中Tab切换的库,它提供的标签切换器类似于在Chrome浏览器中使用的标签切换器。
- 项目移植状态:主功能完成
- 调用差异:无
- 开发版本:sdk6,DevEco Studio2.2 beta1
- 基线版本:tag 0.4.6
效果演示
- 主页上下滑动
安装教程
1.在项目根目录下的build.gradle文件中,
allprojects {
repositories {
maven {
url 'https://s01.oss.sonatype.org/content/repositories/snapshots/'
}
}
}
2.在entry模块的build.gradle文件中,
dependencies {
implementation('com.gitee.chinasoft_ohos:ChromeLikeTabSwitcher:0.0.1-SNAPSHOT')
implementation('com.gitee.chinasoft_ohos:ChromeLikeTabSwitcher_materialviewlibrary:0.0.1-SNAPSHOT')
implementation('com.gitee.chinasoft_ohos:ChromeLikeTabSwitcher_java_util:0.0.1-SNAPSHOT')
implementation('com.gitee.chinasoft_ohos:ChromeLikeTabSwitcher_ohos_util:0.0.1-SNAPSHOT')
......
}
在sdk6,DevEco Studio2.2 beta1下项目可直接运行 如无法运行,删除项目.gradle,.idea,build,gradle,build.gradle文件, 并依据自己的版本创建新项目,将新项目的对应文件复制到根目录下
使用说明
库的选项卡切换器实现为自定义视图TabSwitcher。可以通过编程方式声明或通过XML资源将其添加到活动或片段中。以下XML代码显示了如何将视图添加到XML布局资源。通常应通过将属性设置为layout_width和layout_height将标签切换器全屏显示match_parent。此外,该视图提供了各种自定义属性以自定义其外观,这在给定的示例中也可以看到。
<?xml version="1.0" encoding="utf-8"?>
<de.mrapp.tabswitcher.colorUi.widget.ColorDirectionalLayout
ohos:id="$+id:root"
xmlns:ohos="http://schemas.huawei.com/res/ohos"
xmlns:app="http://schemas.huawei.com/apk/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:orientation="vertical"
ohos:theme_prefix="main">
<de.mrapp.tabswitcher.TabSwitcher
ohos:id="$+id:tab_switcher"
ohos:height="match_parent"
ohos:width="match_parent"
app:emptyView="$layout:empty_view"
app:tabIcon="$media:ic_file_outline_18dp"
...
/>
</de.mrapp.tabswitcher.colorUi.widget.ColorDirectionalLayout>
以TabSwitcher编程方式实例化时,可以使用以下Java代码。对于上面示例中显示的所有XML属性,都可以使用相应的setter方法。
TabSwitcher tabSwitcher = new TabSwitcher(context);
tabSwitcher.showAddTabButton(createAddTabButtonListener());
tabSwitcher.setToolbarNavigationIcon(ResourceTable.Media_ic_plus_white_24dp, createAddTabListener());
由a包含的选项卡TabSwitcher由class的实例表示Tab。以下Java代码演示了如何创建新标签并将其添加到标签切换器。通过设置自定义图标,背景颜色,标题颜色等,TabSwitcher可以覆盖特定标签的默认设置(应用于)。所述setParameters-method允许以一个标签相关联Bundle,其可包含关于标签的附加信息。通过实现接口Tab.Callback并Tab使用其addCallback-method在a处注册实例,可以在选项卡的属性已更改时观察到它。
Tab tab = new Tab("Title");
PacMap parameters = new PacMap();
tab.setIcon(ResourceTable.Media_ic_file_outline_18dp);
...
tab.setParameters(parameters);
为了指定选项卡的TabSwitcher
外观,TabSwitcherDecorator
必须重写抽象类,并且必须使用setDecorator
方法将实现类的实例应用于选项卡切换器。这是非常常用的适配器,用于填充一个发展中的范式 ListView
,RecyclerView
等等之类的每一个自定义实现 TabSwitcherDecorator
必须重写 onInflateView
和onShowTab
方法。第一个用于使视图膨胀,应由选项卡使用,后者允许根据当前状态自定义膨胀视图的外观。在 onShowTab
的范围内,装饰器的findComponentById
方法可用于引用视图。它使用内置的视图保持器以获得更好的性能。
如果对不同的选项卡使用不同的视图,则getViewTypeCount
和getViewType
方法也必须被覆盖。第一个返回的是onInflateView
方法放大的不同视图的总数,后一个必须返回一个不同的整数值,该值指定特定选项卡 的视图类型。以下代码说明了如何实现该类TabSwitcherDecorator
。
class Decorator extends TabSwitcherDecorator {
@NonNull
@Override
public View onInflateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup parent, int viewType) {
Component view;
if (viewType == 0) {
LogUtil.loge("=== onInflateView 0");
view = inflater.parse(ResourceTable.Layout_tab_text_view, parent, false);
} else if (viewType == 1) {
LogUtil.loge("=== onInflateView 1");
view = inflater.parse(ResourceTable.Layout_tab_edit_text, parent, false);
} else {
LogUtil.loge("=== onInflateView 2");
view = inflater.parse(ResourceTable.Layout_tab_list_view, parent, false);
}
Toolbar toolbar = (Toolbar) view.findComponentById(ResourceTable.Id_toolbar);
toolbar.inflateMenu(ResourceTable.Layout_tab);
toolbar.setOnMenuItemClickListener(tabSwitcher, createToolbarMenuListener());
TabSwitcher.setupWithToolbar(tabSwitcher, toolbar, createTabSwitcherButtonListener());
return view;
}
@Override
public void onShowTab(@NonNull Context context, @NonNull TabSwitcher tabSwitcher,
@NonNull View view, @NonNull Tab tab, int index, int viewType,
@Nullable Bundle savedInstanceState) {
Text textView = findComponentById(ResourceTable.Id_title);
textView.setText((String) tab.getTitle());
Toolbar toolbar = findComponentById(ResourceTable.Id_toolbar);
toolbar.addMenuClickListener();
toolbar.setVisibility(tabSwitcher.isSwitcherShown() ? Component.HIDE : Component.VISIBLE);
if (toolbar.getMenu() != null) {
String theme_name = getThemeValue("theme_name");
if ("dark".equals(theme_name)) {
toolbar.getMenu().setImageSrc(de.mrapp.tabswitcher.ResourceTable.Media_more_menu_white);
toolbar.setButtonColor(1, Color.WHITE);
} else {
toolbar.getMenu().setImageSrc(de.mrapp.tabswitcher.ResourceTable.Media_more_menu);
toolbar.setButtonColor(0.5f, Color.DKGRAY);
}
}
ColorUiUtil.changeTheme(view, getContext().getTheme());
if (viewType == 1) {
LogUtil.loge("=== onShowTab viewType -> 1");
TextField editText = findComponentById(ResourceTable.Id_edit);
if (savedInstanceState == null) {
editText.setText("");
}
editText.requestFocus();
} else if (viewType == 2 && state != null) {
LogUtil.loge("=== onShowTab viewType -> 2");
ListContainer listView = findComponentById(ResourceTable.Id_list);
state.loadItems(listView);
}
}
@Override
public int getViewTypeCount() {
return 3;
}
@Override
public int getViewType(@NonNull Tab tab, int index) {
Bundle parameters = tab.getParameters();
return parameters != null ? parameters.getInt("view_type") : 0;
}
@Override
public void onSaveInstanceState(@NonNull View view, @NonNull Tab tab, int index,
int viewType, @NonNull Bundle outState) {
// Store the tab's current state in the Bundle outState if necessary
}
}
为了将装饰器应用于TabSwitcher
其 setDecorator
方法,必须如下所示使用。如果未设置装饰器,IllegalStateException
则在视图应可见时将立即引发。
tabSwitcher.setDecorator(new Decorator());
为了观察TabSwitcher
状态,可以实现TabSwitcher
接口TabSwitcherListener
侦听器。该界面提供了以下方法:在将选项卡添加到选项卡切换器或从选项卡切换器中删除时, 或者如果选项卡切换器已隐藏或显示(仅在使用智能手机布局时),则将调用这些方法。TabSwitcherListener
可以使用TabSwitcher
的addListener
方法添加类型的实例。 为了观察,当单击选项卡的关闭按钮时,TabCloseListener
可以相应地使用addTabCloseListener
方法来实现和添加接口。
使用动画
该类 TabSwitcher
提供了添加或删除一个或几个选项卡的各种方法。如果当前显示选项卡切换器,则以动画方式添加或删除选项卡。为了使用自定义动画,Animation
可以将类的实例传递给方法。
滑动动画
使用智能手机布局时,SwipeAnimation
默认情况下使用a来添加或删除选项卡。这会导致标签页水平滑动(或在横向模式下垂直滑动)。通过指定enum的值SwipeAnimation.SwipeDirection
, 可以指定选项卡是否应该向左或向右移动(在横向模式下分别从顶部或底部移动)。以下代码示例说明了如何 SwipeAnimation
使用构建器来创建类的实例。
Animation animation = new SwipeAnimation.Builder().setDuration(2000)
.setInterpolator(new LinearInterpolator()).setDirection(SwipeAnimation.SwipeDirection.LEFT)
.create();
工具栏和菜单
TabSwitcher
库提供的视图允许显示工具栏。默认情况下,工具栏始终处于隐藏状态。为了显示它, showToolbars
必须使用-method。使用智能手机布局时,当前显示选项卡切换器或选项卡切换器不 包含任何选项卡时,将显示工具栏。使用数位板布局时,始终显示两个工具栏-一个在选项卡的左侧 ,另一个在选项卡的右侧。可以使用 getToolbars
方法来引用工具栏。它返回一个数组, 其中包含布局的工具栏。 使用智能手机布局时,Toolbar
数组仅包含一个;使用平板电脑布局时,左一个包含在索引0中, 右一个包含在索引1中。
该类 TabSwitcher
提供了一些方法,可用于设置工具栏的标题,导航图标和菜单。 本 setToolbarTitle
方法允许设置一个标题。使用数位板布局时,标题将应用到左侧工具栏。 所述 setToolbarNavigationIcon
方法允许指定工具栏的导航图标以及点击图标时被调用的监听器。 使用数位板布局时,导航图标将应用于左侧工具栏。为了将菜单添加到 TabSwitcher
的工具栏, inflateToolbarMenu
可以使用-method。除了应该应用的菜单资源的资源ID外,它还允许指定一个侦听器, 当单击菜单项时会通知该侦听器。
为了提供类似于Chrome浏览器中使用的按钮的按钮,该按钮显示了a包含的选项卡总数, TabSwitcher
并允许切换选项卡切换器的可见性,该类 TabSwitcherButton
由库公开。 它实现了一个自定义的 ImageButton
,它实现了接口 TabSwitcherListener
,以使显示的选项 卡数目保持最新。 该按钮的外观由类指定 TabSwitcherDrawable
。如果 TabSwitcherButton
应将用作工具栏菜单的一部分, 则必须将其包含在菜单资源中。具体使用如下所示
TabSwitcherDrawable使用方法:
private void initImage() {
image = new Image(getContext());
Resource resource = convertRes(getContext(), ResourceTable.Media_tab_switcher_drawable_background);
//The drawable, which is used by the image button.
drawable = new TabSwitcherDrawable(getContext(), resource);
image.setImageElement(drawable);
StackLayout.LayoutConfig imageParams = new LayoutConfig(StackLayout.LayoutConfig.MATCH_PARENT, StackLayout.LayoutConfig.MATCH_PARENT);
imageParams.alignment = TextAlignment.CENTER;
addComponent(image, imageParams);
}
TabSwitcherButton使用方法
TabSwitcherButton actionView = new TabSwitcherButton(getContext());
DirectionalLayout.LayoutConfig actionConfig = new LayoutConfig();
int tabHeight = (int) PixelUtil.fp2px(DimensionUtil.parseDimension(getContext().getString(ResourceTable.String_tablet_tab_height)));
actionConfig.height = tabHeight;
actionConfig.width = tabHeight;
addComponent(actionView, actionConfig);
为了将菜单注册 TabSwitcherButton
为的侦听器,可以使用TabSwitcher
静态 setupWithMenu
方法。它会自动为所有的items 注入一个Menu
菜单,将使用的所有项注册 TabSwitcherButton
为 特定的侦听器 TabSwitcher
。在 OnClickListener
当被点击这些按钮中的一个,其可任选被指定, 被调用。以下代码显示了如何将该方法与任意菜单一起使用。
TabSwitcher.setupWithMenu(tabSwitcher, menu, new OnClickListener() { /* ... */ });
If the menu, which is part of the tab switcher itself, should be set up, the following method call can be used.
TabSwitcher.setupWithMenu(tabSwitcher, new OnClickListener() { /* ... */ });
使用主题
默认情况下,图书馆的会使用浅色主题TabSwitcher。但是,该库TabSwitcher
除主题外还带有预定义的深色主题。 下面的屏幕快照显示了深色主题的外观
当TabSwitcher为空时显示一个占位符
该类 TabSwitcher
提供setEmptyView
方法,可用于指定选项卡切换器为空时显示的自定义视图。 通过使用淡入或淡出动画来显示或隐藏指定的视图。可以选择指定这些动画的持续时间。使用 setEmptyView
方法 的第一种可能性是指定该类的实例ohos.agp.components.Component
:
Component component = // ... inflate component
tabSwitcher.setEmptyView(component);
或者,setEmpyView
可以通过指定视图的布局资源ID来使用:
tabSwitcher.setEmptyView(ResourceTable.Id_empty_view);
当标签切换器为空时,显示的占位符视图的示例可以在下面的屏幕快照中看到。
填充
该视图将 TabSwitcher
覆盖 setPadding
该类的方法 View
,以便将填充应用于所有选项卡及其父视图。此行为的主要目的是在使用半透明状态和/或导航栏时应用窗口插图, 如在库的示例应用程序中可以看到的那样。以下代码示例演示如何通过使用活动将窗口插入到选项卡切换器OnApplyWindowInsetsListener
。它应在活动的 onCreate
方法中使用。
tabSwitcher.getComponentTreeObserver().addWindowBoundListener(
new ComponentTreeObserver.WindowBoundListener() {
@Override
public void onWindowBound() {
int left = main_root.getLeft();
int top = main_root.getTop();
int right = main_root.getRight();
int bottom = main_root.getBottom();
float touchableAreaTop = top;
if (tabSwitcher.getLayout() == Layout.TABLET) {
// touchableAreaTop += getResources().getDimensionPixelSize(R.dimen.tablet_tab_container_height);
}
LogUtil.loge("===" + left + ":" + top + ":" + right + ":" + bottom);
int actionBarSize = (int) PixelUtil.fp2px(DimensionUtil.parseDimension(tabSwitcher.getContext().getString(ResourceTable.String_actionBarSize)));
LogUtil.loge("===" + actionBarSize);
RectFloat touchableArea = new RectFloat(left, touchableAreaTop, right, touchableAreaTop + actionBarSize);
tabSwitcher.addDragGesture(
new SwipeGesture.Builder().setTouchableArea(touchableArea).create());
tabSwitcher.addDragGesture(
new PullDownGesture.Builder().setTouchableArea(touchableArea).create());
}
@Override
public void onWindowUnbound() {
}
}
);
测试信息
CodeCheck代码测试无异常
CloudTest代码测试无异常
病毒安全检测通过
当前版本demo功能与原组件基本无差异
版本迭代
- 0.0.1-SNAPSHOT