鸿蒙开源组件——仿Chrome浏览器中Tab切换的库

jacksky
发布于 2021-8-11 11:11
浏览
0收藏
Component component = // ... inflate component
tabSwitcher.setEmptyView(component); 

ChromeLikeTabSwitcher

项目介绍

  • 项目名称:ChromeLikeTabSwitcher
  • 所属系列:openharmony的第三方组件适配移植
  • 功能:ChromeLikeTabSwitcher是一个仿Chrome浏览器中Tab切换的库,它提供的标签切换器类似于在Chrome浏览器中使用的标签切换器。
  • 项目移植状态:主功能完成
  • 调用差异:无
  • 开发版本:sdk6,DevEco Studio2.2 beta1
  • 基线版本:tag 0.4.6

效果演示

  • 主页上下滑动鸿蒙开源组件——仿Chrome浏览器中Tab切换的库-鸿蒙开发者社区鸿蒙开源组件——仿Chrome浏览器中Tab切换的库-鸿蒙开发者社区

鸿蒙开源组件——仿Chrome浏览器中Tab切换的库-鸿蒙开发者社区

安装教程

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方法将实现类的实例应用于选项卡切换器。这是非常常用的适配器,用于填充一个发展中的范式 ListViewRecyclerView等等之类的每一个自定义实现 TabSwitcherDecorator必须重写 onInflateViewonShowTab方法。第一个用于使视图膨胀,应由选项卡使用,后者允许根据当前状态自定义膨胀视图的外观。在 onShowTab的范围内,装饰器的findComponentById方法可用于引用视图。它使用内置的视图保持器以获得更好的性能。

如果对不同的选项卡使用不同的视图,则getViewTypeCountgetViewType方法也必须被覆盖。第一个返回的是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 可以使用TabSwitcheraddListener方法添加类型的实例。 为了观察,当单击选项卡的关闭按钮时,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();

 

鸿蒙开源组件——仿Chrome浏览器中Tab切换的库-鸿蒙开发者社区

 

工具栏和菜单

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除主题外还带有预定义的深色主题。 下面的屏幕快照显示了深色主题的外观鸿蒙开源组件——仿Chrome浏览器中Tab切换的库-鸿蒙开发者社区

当TabSwitcher为空时显示一个占位符

该类 TabSwitcher 提供setEmptyView 方法,可用于指定选项卡切换器为空时显示的自定义视图。 通过使用淡入或淡出动画来显示或隐藏指定的视图。可以选择指定这些动画的持续时间。使用 setEmptyView 方法 的第一种可能性是指定该类的实例ohos.agp.components.Component

Component component = // ... inflate component
tabSwitcher.setEmptyView(component); 

或者,setEmpyView可以通过指定视图的布局资源ID来使用:

tabSwitcher.setEmptyView(ResourceTable.Id_empty_view); 

当标签切换器为空时,显示的占位符视图的示例可以在下面的屏幕快照中看到。

鸿蒙开源组件——仿Chrome浏览器中Tab切换的库-鸿蒙开发者社区

填充

该视图将 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

ChromeLikeTabSwitcher-master.zip 3.41M 12次下载
已于2021-8-11 11:11:15修改
收藏
回复
举报
回复
    相关推荐