HarmonyOS 自定义UI之Component属性值获取 原创 精华

发布于 2021-9-22 17:10
浏览
6收藏

作者:刘清华

当系统自带的Component不能满足我们项目UI需求时,就需要自定义Component,这时就不可避免的会使用自定义属性,鸿蒙自定义属性不需要预先定义<自定义属性/>标签。而是直接在布局中使用这个自定义属性,在使用的时候只需要在根布局上加上下面这个命名空间

<DirectionalLayout
    ... 
    xmlns:app="http://schemas.huawei.com/apk/res/ohos"
    ... 
    >

自定义属性

鸿蒙自定义属性值通过attrSet.getAttr(name).get().getXXX()API获得,能够读取一些基本数据类型的数据,但是有一些值无法直接读取比如ResourceId、StringArray等,导致使用非常不方便,因此写了这个属性值获取工具类 ,方便开发者获取各种不同类型的属性值。
自定义的Component: 包含高度尺寸、字体大小、字体、字符串数组、布局id、背景图片属性。

  <cn.carbswang.ohos.attrtool.CustomComponent
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:background_element="#cccccc"
        app:itemHeight="55vp"
        app:itemTextFont="myfont.ttf"
        app:itemTextFontSiz="15fp"
        app:itemArray="$strarray:hour"
        app:itemLayout="$layout:ability_two"
        app:itemBackground="$color:red" />

获取自定义属性值

自定义的CustomComponent

/**
 * 自定义Component
 *
 * @since 2021-08-24
 */
public class CustomComponent extends Component {
    public CustomComponent(Context context, AttrSet attrSet) {
        super(context, attrSet);
        init(context, attrSet);
    }
    /**
     * 初始化 属性
     * @param context 上下文
     * @param attrSet 属性集
     */
    private void init(Context context, AttrSet attrSet) {
        int itemHeight = AttrTool.getDimension(attrSet, "itemHeight", AttrTool.vp2px(context, 50));
        Font itemTextFont = AttrTool.getFont(context, attrSet, "itemTextFont");
        int itemTextFontSiz = AttrTool.getDimension(attrSet, "itemTextFontSiz", AttrTool.fp2px(context, 15));
        String[] itemArray = AttrTool.getStringArray(context, attrSet, "itemArray");
        int itemLayout = AttrTool.getResourceId(attrSet, "itemLayout", 0);
        Element itemBackground = AttrTool.getElement(attrSet, "itemBackground");
        System.out.println("itemHeight: " + itemHeight);
        if (itemTextFont != null) {
            System.out.println("itemTextFont: " + itemTextFont);
        }
        System.out.println("itemTextFontSiz: " + itemTextFontSiz);
        if (itemArray != null) {
            System.out.println("itemArray: " + Arrays.toString(itemArray));
        }
        System.out.println("itemLayout: " + itemLayout);
        System.out.println("itemBackground: " + itemBackground);

    }

打印输出如下:

08-24 16:54:29.382 11212-11212/cn.carbswang.ohos.attrtool I System.out:  itemHeight: 165
08-24 16:54:29.382 11212-11212/cn.carbswang.ohos.attrtool I System.out:  itemTextFont: ohos.agp.text.Font@3a276dc
08-24 16:54:29.382 11212-11212/cn.carbswang.ohos.attrtool I System.out:  itemTextFontSiz: 45
08-24 16:54:29.382 11212-11212/cn.carbswang.ohos.attrtool I System.out:  itemArray: [12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
08-24 16:54:29.382 11212-11212/cn.carbswang.ohos.attrtool I System.out:  itemLayout: 16777227
08-24 16:54:29.382 11212-11212/cn.carbswang.ohos.attrtool I System.out:  itemBackground: ohos.agp.components.element.ShapeElement@68bd3e5

ResourceId属性值获取

鸿蒙attrSet.getAttr(name).get()并没有对应的API用于获取布局id,需要先获取String值:$layout:16777227,分号的后面代表布局id,我们只要截取分号后的字符串就行。

    /**
     * 获取资源Id
     *
     * @param attrSet 属性集
     * @param name 属性name
     * @param defValue 默认值
     * @return 返回资源Id
     */
    public static int getResourceId(AttrSet attrSet, String name, int defValue) {
        if (!attrSet.getAttr(name).isPresent()) {
            return defValue;
        }
        String value = attrSet.getAttr(name).get().getStringValue();
        if (value.startsWith("$layout")) {
            try {
                return Integer.parseInt(value.substring(value.indexOf(":") + 1));
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
        }
        return defValue;
    }

StringArray属性值获取

鸿蒙attrSet.getAttr(name).get()也没有对应的API用于获取StringArray字符串数组,需要先获取String值:$strarray:hour,分号的后面代表资源名称,我们只要截取这个再拼接Strarray_+hour
再通过类加载器得到ResourceTable资源类,里面有所有资源id。再反射得到Strarray_+hour资源id,有了资源id就可以得到字符串数组了。

 /**
     * 获取字符串数组
     *
     * @param context 上下文
     * @param attrSet 属性集
     * @param name 属性name
     * @return 返回字符串数组
     */
    public static String[] getStringArray(Context context, AttrSet attrSet, String name) {
        String str = getString(attrSet, name, "");
        if (str.startsWith("$strarray:")) {
            try {
                String name2 = str.split(":")[1];
                Class<?> aClass = context.getClassloader().loadClass(context.getBundleName() + ".ResourceTable");
                Field field = aClass.getField("Strarray_" + name2);
                if (field != null) {
                    int id = field.getInt("Strarray_" + name2);
                    return context.getResourceManager().getElement(id).getStringArray();
                }
            } catch (NoSuchFieldException | IllegalAccessException | NotExistException | WrongTypeException | IOException | ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

鸿蒙自定义字体获取

首先字体文件放在resources/rawfile/xxx.ttf 路径下,再通过new Font.Builder(file).build()构建字体文件,就可以用于Text控件了。

    /**
      * 获取字体
      *
      * @param context 上下文
      * @param attrSet 属性集
      * @param name 属性name
      * @return 返回Font
      */
     public static Font getFont(Context context, AttrSet attrSet, String name) {
         String fileName = getString(attrSet, name, "");
         return getFontFromRawFile(context, fileName);
     }
 
     /**
      * 从resources/rawfile 读取字体文件
      *
      * @param context 上下文
      * @param fileName 字体文件名称
      * @return Font
      */
     public static Font getFontFromRawFile(Context context, String fileName) {
         String path = "resources/rawfile/" + fileName;
         ResourceManager resManager = context.getResourceManager();
         RawFileEntry rawFileEntry = resManager.getRawFileEntry(path);
         Resource resource = null;
         try {
             resource = rawFileEntry.openRawFile();
         } catch (IOException e) {
             e.printStackTrace();
         }
         if (resource != null) {
             File file = new File(context.getCacheDir(), fileName);
             OutputStream outputStream = null;
             try {
                 outputStream = new FileOutputStream(file);
                 int index;
                 byte[] bytes = new byte[1024];
                 while ((index = resource.read(bytes)) != -1) {
                     outputStream.write(bytes, 0, index);
                     outputStream.flush();
                 }
             } catch (IOException e) {
                 e.printStackTrace();
             } finally {
                 try {
                     resource.close();
                     if (outputStream != null) {
                         outputStream.close();
                     }
                 } catch (IOException e) {
                     e.printStackTrace();
                 }
             }
             Font.Builder builder = new Font.Builder(file);
             return builder.build();
         }
         return null;
     }

Element属性值获取

鸿蒙的Element根据不同的资源实例化成不同的子对象,颜色值被实例化成ShapeElement,图片资源被实例化成PixelMapElement。

  /**
     * 获取Element
     *
     * @param attrSet 属性集
     * @param name 属性name
     * @return 返回Element
     */
    public static Element getElement(AttrSet attrSet, String name) {
        if (attrSet.getAttr(name).isPresent()) {
            return attrSet.getAttr(name).get().getElement();
        }
        return null;
    }

更多原创内容请关注:开鸿 HarmonyOS 学院

入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
5
收藏 6
回复
举报
回复
添加资源
添加资源将有机会获得更多曝光,你也可以直接关联已上传资源 去关联
    相关推荐