「构建UI模板库-HarmonyOS组件再包装」»» 详细总结来了~ 原创 精华

Tuer白晓明
发布于 2021-7-2 14:57
浏览
4收藏

一、公开课内容总结


如果你在互联网企业或者即将进入互联网企业,或多或少你都接触过以下组件库。
「构建UI模板库-HarmonyOS组件再包装」»» 详细总结来了~-鸿蒙开发者社区
既然HarmonyOS已经有了7大类400多种组件,我们为什么还要构建组件库呢?

使用“WWH”来解决问题,最终都可以得到你想要的。本次直播我也使用“WWH”来阐述为何要进行组件化。“WWH”即Why(为什么?)、What(是什么?这里指解决哪些痛点)、How(怎么做?代码干货)。

  • 为什么:并不是因为“懒”才构建组件库,如果App中使用多个相同的样式组件,需要修改的时候,所有使用的地方都需要修改,这样无形中增加了负担,同时也会出现纰漏。组件库的构建能够有效的解决这类问题,达到一处修改,多处共同修改的目的。
  • 是什么:将具有共用性、可裁剪的HarmonyOS组件进行再次封装,这些封装的组件构成组件库。组件库降低了维护出现问题的几率,能够使产品迭代迅速、体验一致、开发更高效、代码更简洁。
  • 怎么做:我将以实际的案例带大家一步一步构建组件库中的IMIcon(图标组件)和UI模板库中的自定义标题栏(IMTitleBar)。

1、构建核心组件库(IMIcon)

「构建UI模板库-HarmonyOS组件再包装」»» 详细总结来了~-鸿蒙开发者社区
上图是我构建的三种类型的组件,一按钮组件、二图标组件、三输入框组件。这里以图标组件为例,其他可==参考代码仓中的代码==。

构建一个HarmonyOS库分为三步:
1、创建Module,指定为HarmonyOS Library(选中项目右键New—>Module…)
2、使用Gradle构建Har包(右侧gradle选项卡中ohos:debug下packageDebugHar)
3、主项目引入Har包(在build.gradle中dependencies添加implementation project(“:coptlib”) )

先不着急的写代码,先完成以上三步曲,然后再进行下一步。

/**
 * 在java目录下创建IMIcon类,继承Text基础组件,实现三个构造器
 * 将初始化写到第三个构造器中,其他两个构造器调用第三个构造器(默认直接调用第二个构造器)
 */
public class IMIcon extends Text {
    public IMIcon(Context context) {
        this(context, null);
    }

    public IMIcon(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
    }

    public IMIcon(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        setTypeFace(context);
        initIMIcon(attrSet);
    }

    private void initIMIcon(AttrSet attrSet) {
	//设置文本内容对齐方式
        setTextAlignment(TextAlignment.CENTER);
	//设置文本内容大小
        if (attrSet.getAttr("icon_size").isPresent()) {
            setTextSize(attrSet.getAttr("icon_size").get().getIntegerValue(), TextSizeType.FP);
        } else {
            setTextSize(Constant.DEFAULT_ICON_WIDTH_HEIGHT, TextSizeType.FP);
        }
	//设置显示文本内容
        if (attrSet.getAttr("icon").isPresent()) {
            String icon = attrSet.getAttr("icon").get().getStringValue();
            setText(IMButtonIconType.valueOf(icon).getStyle());
        } else {
            //IMButtonIconType.ANGLE_LEFT需要我们根据fontawesome提供的矢量图中的Unicode编码进行转化
		//具体参考代码仓中的IMButtonIconType枚举类
		setText(IMButtonIconType.ANGLE_LEFT.getStyle());
        }
    }
    /**
     * 设置字体显示样式 - font awesome
     * @param context
     */
    private void setTypeFace(Context context) {
        String typeFace = "fontawesome-webfont.ttf";

        File file = new File(context.getCodeCacheDir(), typeFace);

        OutputStream outputStream = null;
        ResourceManager resManager = context.getResourceManager();
	//在resources/rawfile目录下创建fonts目录,并拷贝下载的fontawesome字体文件
	//这里读取字体文件
        RawFileEntry rawFileEntry = resManager.getRawFileEntry("resources/rawfile/fonts/" + typeFace);

        Resource resource = null;

        try {
		//打开字体文件,使用流的方式读取
            resource = rawFileEntry.openRawFile();
            outputStream = new FileOutputStream(file);
            int index;
            byte[] bytes = new byte[1024];
            if (resource != null) {
                while ((index = resource.read(bytes)) != -1) {
                    outputStream.write(bytes, 0, index);
                    outputStream.flush();
                }
		//设置当前组件的文本样式
                Font font = new Font.Builder(file).build();
                setFont(font);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                resource.close();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
<!--
	在头部加上我们的自定义属性规则
	使用自定义规则设置属性值
-->
<com.itming.ui.coptlib.core.IMIcon
	ohos:margin="10fp"
	ohos:height="64fp"
	ohos:width="64fp"
	ohos:text_color="#088888"
	itming:icon="USER"
	itming:icon_size="36"/>

然后运行程序,查看效果。

2、自定义标题栏(IMCustomTitleBar)

「构建UI模板库-HarmonyOS组件再包装」»» 详细总结来了~-鸿蒙开发者社区
上图是自定义标题栏实例,可以看到图标按钮是设置了可见性的。UI模板库与组件库不同之处在于,UI模板库是以核心组件为基础,各个元素整合后的产物。

构建一个HarmonyOS库分为三步:
1、创建Module,指定为HarmonyOS Library(选中项目右键New—>Module…)
2、使用Gradle构建Har包(右侧gradle选项卡中ohos:debug下packageDebugHar)
3、主项目引入Har包(在build.gradle中dependencies添加implementation project(“:uilib”) )

先不着急的写代码,先完成以上三步曲,然后再进行下一步。

/**
 * <p>自定义标题栏</p>
 * <ol>
 *     <li>左侧返回按钮</li>
 *
 *     <li>中间标题内容</li>
 *
 *     <li>
 *          <p>右侧图标按钮组</p>
 *          <ol>
 *              <li>右侧搜索按钮</li>
 *              <li>右侧多选按钮组</li>
 *          </ol>
 *     </li>
 * </ol>
 * @author itming
 * @date 2021-06-26
 */
public class IMCustomTitleBar extends DependentLayout {
    public IMCustomTitleBar(Context context) {
        this(context, null);
    }

    public IMCustomTitleBar(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
    }

    public IMCustomTitleBar(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        initImCustomTitleBar(context, attrSet);
    }

    /**
     * 初始化标题栏
     * @param attrSet
     */
    private void initImCustomTitleBar(Context context, AttrSet attrSet) {
        //动态加载Layout
        Component component = LayoutScatter.getInstance(context)
                .parse(ResourceTable.Layout_layout_title, null, false);

        //子组件
        IMIconButton backBtn = (IMIconButton) component.findComponentById(ResourceTable.Id_back_btn);
        Text titleBarContent = (Text) component.findComponentById(ResourceTable.Id_page_title);
        DirectionalLayout groupBtn = (DirectionalLayout) component.findComponentById(ResourceTable.Id_group_btn);
        IMIconButton searchBtn = (IMIconButton) groupBtn.findComponentById(ResourceTable.Id_search_btn);
        IMIconButton selectBtn = (IMIconButton) groupBtn.findComponentById(ResourceTable.Id_plus_btn);
        //添加layout到父组件
        addComponent(component);

        //设置标题栏背景色
        if (attrSet.getAttr("bar_bg").isPresent()) {
            component.setBackground(attrSet.getAttr("bar_bg").get().getElement());
        } else {
            component.setBackground(getBackgroundElement());
        }

        /**
         * 设置标题栏内容
         */
        if (attrSet.getAttr("bar_content").isPresent()) {
            titleBarContent.setText(attrSet.getAttr("bar_content").get().getStringValue());
        } else {
            titleBarContent.setText("");
        }

        //设置标题栏内容字体大小
        if (attrSet.getAttr("bar_content_size").isPresent()) {
            titleBarContent.setTextSize(attrSet.getAttr("bar_content_size").get().getIntegerValue(), Text.TextSizeType.FP);
        } else {
            titleBarContent.setTextSize(Constant.DEFAULT_BAR_CONTENT_SIZE, Text.TextSizeType.FP);
        }

        //设置标题内容字体颜色
        if (attrSet.getAttr("bar_content_color").isPresent()) {
            titleBarContent.setTextColor(attrSet.getAttr("bar_content_color")
                    .get().getColorValue());
        } else {
            if (attrSet.getAttr("bar_bg").isPresent()) {
                titleBarContent.setTextColor(Color.WHITE);
            } else {
                titleBarContent.setTextColor(Color.BLACK);
            }
        }

        //设置是否显示返回按钮
        if (attrSet.getAttr("bar_back_btn").isPresent()) {
            if (attrSet.getAttr("bar_back_btn").get().getBoolValue()) {
                backBtn.setVisibility(VISIBLE);
            } else {
                backBtn.setVisibility(INVISIBLE);
            }
        } else {
            backBtn.setVisibility(INVISIBLE);
        }

        //设置返回按钮颜色
        if (attrSet.getAttr("bar_back_btn_color").isPresent()) {
            backBtn.setTextColor(attrSet.getAttr("bar_back_btn_color")
                    .get().getColorValue());
        } else {
            if (attrSet.getAttr("bar_bg").isPresent()) {
                backBtn.setTextColor(Color.WHITE);
            } else {
                backBtn.setTextColor(Color.BLACK);
            }
        }

        //设置右边按钮组可见值(其中之一可见,即容器可见)
        if (attrSet.getAttr("bar_search_btn").isPresent()
                || attrSet.getAttr("bar_select_btn").isPresent()) {
            if (attrSet.getAttr("bar_search_btn").isPresent()) {
                if (attrSet.getAttr("bar_search_btn").get().getBoolValue()) {
                    searchBtn.setVisibility(VISIBLE);
                } else {
                    searchBtn.setVisibility(HIDE);
                }
            } else {
                selectBtn.setWidth(MATCH_PARENT);
                searchBtn.setVisibility(HIDE);
            }
            if (attrSet.getAttr("bar_select_btn").isPresent()) {
                if (attrSet.getAttr("bar_select_btn").get().getBoolValue()) {
                    selectBtn.setVisibility(VISIBLE);
                } else {
                    selectBtn.setVisibility(HIDE);
                }
            } else {
                searchBtn.setWidth(MATCH_PARENT);
                selectBtn.setVisibility(HIDE);
            }
            groupBtn.setVisibility(VISIBLE);
        } else {
            groupBtn.setVisibility(HIDE);
        }

        //设置右侧按钮颜色
        if (attrSet.getAttr("bar_search_btn_color").isPresent()) {
            searchBtn.setTextColor(attrSet.getAttr("bar_search_btn_color")
                    .get().getColorValue());
        } else {
            if (attrSet.getAttr("bar_bg").isPresent()) {
                searchBtn.setTextColor(Color.WHITE);
            } else {
                searchBtn.setTextColor(Color.BLACK);
            }
        }
        if (attrSet.getAttr("bar_select_btn_color").isPresent()) {
            selectBtn.setTextColor(attrSet.getAttr("bar_select_btn_color")
                    .get().getColorValue());
        } else {
            if (attrSet.getAttr("bar_bg").isPresent()) {
                selectBtn.setTextColor(Color.WHITE);
            } else {
                selectBtn.setTextColor(Color.BLACK);
            }
        }
    }
}
<!--布局文件-->
<DependentLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    xmlns:itming="http://schemas.huawei.com/res/ohos-auto"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:background_element="#088888"
    ohos:alignment="vertical_center">

    <com.itming.ui.coptlib.core.IMIconButton
        ohos:id="$+id:back_btn"
        ohos:height="match_parent"
        ohos:width="48vp"
        ohos:text_color="#F2F2F2"
        itming:icon="ANGLE_LEFT"
        itming:icon_size="36"
        ohos:align_parent_left="true"/>

    <Text
        ohos:id="$+id:page_title"
        ohos:height="match_parent"
        ohos:width="match_content"
        ohos:text="Page title"
        ohos:text_size="24fp"
        ohos:text_color="#FFFFFF"
        ohos:center_in_parent="true"/>

    <DirectionalLayout
        ohos:id="$+id:group_btn"
        ohos:height="match_parent"
        ohos:width="96vp"
        ohos:orientation="horizontal"
        ohos:align_parent_right="true">
        <com.itming.ui.coptlib.core.IMIconButton
            ohos:id="$+id:search_btn"
            ohos:height="match_parent"
            ohos:width="48vp"
            ohos:text_color="#F2F2F2"
            itming:icon="DEFAULT_SEARCH"
            itming:icon_size="24"/>

        <com.itming.ui.coptlib.core.IMIconButton
            ohos:id="$+id:plus_btn"
            ohos:height="match_parent"
            ohos:width="48vp"
            ohos:text_color="#F2F2F2"
            itming:icon="PLUS_SQUARE"
            itming:icon_size="24"/>
    </DirectionalLayout>
</DependentLayout>
<!--
	在头部加上我们的自定义属性规则
	使用自定义规则设置属性值
-->
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    xmlns:itming="http://schemas.huawei.com/res/ohos-auto"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:alignment="center"
    ohos:orientation="vertical">

    <com.itming.ui.uilib.bar.IMCustomTitleBar
        ohos:height="54vp"
        ohos:width="match_parent"
        itming:bar_bg="#FFE95757"
        itming:bar_content="仅内容标题栏"
        itming:bar_content_size="18"/>

    <com.itming.ui.uilib.bar.IMCustomTitleBar
        ohos:id="$+id:custom_title_bar"
        ohos:top_margin="20vp"
        ohos:height="54vp"
        ohos:width="match_parent"
        itming:bar_bg="#FFE95757"
        itming:bar_content="带返回图标标题栏"
        itming:bar_content_size="18"
        itming:bar_back_btn="true"/>

    <com.itming.ui.uilib.bar.IMCustomTitleBar
        ohos:top_margin="20vp"
        ohos:height="54vp"
        ohos:width="match_parent"
        itming:bar_bg="#FFE95757"
        itming:bar_content="带返回+搜索标题栏"
        itming:bar_content_size="18"
        itming:bar_back_btn="true"
        itming:bar_search_btn="true"/>

    <com.itming.ui.uilib.bar.IMCustomTitleBar
        ohos:top_margin="20vp"
        ohos:height="54vp"
        ohos:width="match_parent"
        itming:bar_bg="#FFE95757"
        itming:bar_content="带返回+多选标题栏"
        itming:bar_content_size="18"
        itming:bar_back_btn="true"
        itming:bar_select_btn="true"/>

    <com.itming.ui.uilib.bar.IMCustomTitleBar
        ohos:top_margin="20vp"
        ohos:height="54vp"
        ohos:width="match_parent"
        itming:bar_bg="#FFE95757"
        itming:bar_content="带返回+搜索+多选标题栏"
        itming:bar_content_size="16"
        itming:bar_back_btn="true"
        itming:bar_search_btn="true"
        itming:bar_select_btn="true"/>

    <Text
        ohos:height="match_parent"
        ohos:width="match_parent"
        ohos:background_element="#EFEFEF"
        ohos:text_alignment="center"
        ohos:text="这是一个自定义标题"
        ohos:text_size="14fp"/>
</DirectionalLayout>

运行程序查看效果。

3、沉浸式登录(IMCustomLogin)

「构建UI模板库-HarmonyOS组件再包装」»» 详细总结来了~-鸿蒙开发者社区
登录功能是最常见的功能,社交类的先登录后使用,咨询类的先使用后登录。两者区别在于是不是需要关闭按钮。有一个应用两种都有,可以不登录就查看部分功能,使用特定功能需要登录,那么启动程序先到登录界面,登录界面具有跳过能力。点击特定功能判断是否登录,若没有登录,则弹出登录页面,不想登录,点击关闭即可。本实例代码抽取两种情况,通过关闭按钮的可见性控制登录页面的使用情况。==代码参见代码仓。==

4、在线教育中服务卡片思考

服务卡片是HarmonyOS的一大亮点,在线教育中我所关注的是所学课程是否更新(目前以短信或者通知形式呈现)、所学课程到第几节次、关注领域是否上架新课程、我的学习记录等。只有课程在更新后以短信或者通知形式推送给我,其他的我只能进入App中查看。如果使用服务卡片,我将把这些卡片放置在桌面上,能够使我一目了然的知道自己想要的信息。这部分的思考,后续会以代码的形式提交到代码仓中。

二、代码仓


»»»» 公开课用到的代码都在这里!!! ««««

PS:如果你有好的建议,也可以和我交流,在持续的提交中也许就会有你的成果。

三、公开课直播回放地址

»»»» 公开课直播回放地址 ««««
「构建UI模板库-HarmonyOS组件再包装」»» 详细总结来了~-鸿蒙开发者社区

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2021-7-2 15:06:12修改
6
收藏 4
回复
举报
2条回复
按时间正序
/
按时间倒序
Whyalone
Whyalone

给白老师点赞!

回复
2021-7-2 20:28:33
charjedu
charjedu

点赞!

回复
2021-7-2 21:53:10
回复
    相关推荐