HarmonyOS Codelab挑战赛记录

【挑战主题】1、模块-Java 布局

1 下载DevEco Studio

1.1 启动选择中国后下载SDK,默认在user目录

在这里插入图片描述

2下载Codelab起步应用

  • 获取Codelab起步应用ComponentCodelab,可从gitee源码或github源码下载
  • 打开HUAWEI DevEco Studio,点击File > Open选择步骤1中下载的ComponentCodelab
  • 点击Build > Build App(s)/Hap(s)>Build Debug Hap(s)构建hap包
  • 点击Run> Run ‘entry’运行hap包,可看到运行效果如下:

在这里插入图片描述

3. 体验TabList和Tab组件

Tablist可以实现多个页签栏的切换,Tab为某个页签。子页签通常放在内容区上方,展示不同的分类。页签名称应该简洁明了,清晰描述分类的内容。TabList和Tab组件的使用方法详见常用组件开发指导。

编写布局文件
在src/main/resources/base/layout目录下新建布局文件tab_list.xml,此布局文件中主要使用Tablist组件,并设置其样式。

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:width="match_parent"
    ohos:height="match_parent"
    ohos:top_margin="15vp"
    ohos:orientation="vertical">
    <TabList
        ohos:id="$+id:tab_list"
        ohos:top_margin="10vp"
        ohos:tab_margin="24vp"
        ohos:tab_length="140vp"
        ohos:text_size="20fp"
        ohos:height="36vp"
        ohos:width="match_parent"
        ohos:layout_alignment="center"
        ohos:orientation="horizontal"
        ohos:text_alignment="center"
        ohos:normal_text_color="#999999"
        ohos:selected_text_color="#afaafa"
        ohos:selected_tab_indicator_color="#afaafa"
        ohos:selected_tab_indicator_height="2vp"/>
    <Text
        ohos:id="$+id:tab_content"
        ohos:width="match_parent"
        ohos:height="match_parent"
        ohos:text_alignment="center"
        ohos:background_element="#70dbdb"
        ohos:text_color="#2e2e2e"
        ohos:text_size="16fp"/>
</DirectionalLayout>

编写AbilitySlice文件
在src/main/java/com/huawei/codelab/slice目录下新建TabListSlice.java文件,继承AbilitySlice。
定义成员变量,加载布局:

package com.huawei.codelab.slice;

import com.huawei.codelab.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.TabList;
import ohos.agp.components.Text;

public class TabListSlice  extends AbilitySlice {
    private TabList tabList;
    private Text tabContent;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_tab_list);
        initComponent();
        addTabSelectedListener();
    }

    private void initComponent() {
        tabContent = (Text) findComponentById(ResourceTable.Id_tab_content);
        tabList = (TabList) findComponentById(ResourceTable.Id_tab_list);
        initTab();
    }

    private void initTab() {
        if (tabList.getTabCount() == 0) {
            tabList.addTab(createTab("Image"));
            tabList.addTab(createTab("Video"));
            tabList.addTab(createTab("Audio"));
            tabList.setFixedMode(true);
            tabList.getTabAt(0).select();
            tabContent.setText("Select the " + tabList.getTabAt(0).getText());
        }
    }

    private TabList.Tab createTab(String text) {
        TabList.Tab tab = tabList.new Tab(this);
        tab.setText(text);
        tab.setMinWidth(64);
        tab.setPadding(12, 0, 12, 0);
        return tab;
    }

    private void addTabSelectedListener() {
        tabList.addTabSelectedListener(new TabList.TabSelectedListener() {
            @Override
            public void onSelected(TabList.Tab tab) {
                tabContent.setText("Select the " + tab.getText());
            }

            @Override
            public void onUnselected(TabList.Tab tab) {
            }

            @Override
            public void onReselected(TabList.Tab tab) {
            }
        });
    }
}

关联主页跳转
在src/main/java/com/huawei/codelab/slice/MainAbilitySlice.java的onClick方法中增加关联跳转


    @Override
    public void onClick(Component component) {
        String className = "";
        switch (component.getId()) {
            case ResourceTable.Id_tab_list:
                className = "com.huawei.codelab.slice.TabListSlice";
                break;
            default:
                break;
        }
        abilitySliceJump(className);
    }

在这里插入图片描述

4. 体验ListContainer组件

ListContainer是用来呈现连续、多行数据的组件,包含一系列相同类型的列表项。ListContainer组件的使用方法详见常用组件开发指导。在本章节,我们将利用ListContainer组件编写一个新闻首页界面,上方的新闻类别和中间的新闻列表都将使用ListContainer组件来实现。

在src/main/resources/base/layout目录下新建布局文件news_list_layout.xml作为新闻列表主界面,并设置其样式

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:orientation="vertical">
    <ListContainer
        ohos:id="$+id:selector_list"
        ohos:height="36vp"
        ohos:width="match_parent"
        ohos:top_padding="8vp"
        ohos:orientation="horizontal"/>
    <Component
        ohos:height="1vp"
        ohos:width="match_parent"
        ohos:background_element="#70dbdb"/>
    <ListContainer
        ohos:id="$+id:news_container"
        ohos:height="match_parent"
        ohos:width="match_parent"/>
</DirectionalLayout>

在src/main/resources/base/layout目录下新建布局文件item_news_type_layout.xml作为上方的新闻类别的item详情布局。

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="40vp"
    ohos:width="match_content">
    <Text
        ohos:id="$+id:news_type_text"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:text_alignment="center"
        ohos:left_padding="20vp"
        ohos:right_padding="20vp"
        ohos:text_color="#55000000"
        ohos:text_size="16fp"/>
</DirectionalLayout>

在src/main/resources/base/layout目录下新建布局文件item_news_layout.xml作为中间的新闻列表的item详情布局。

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="110vp"
    ohos:width="match_parent"
    ohos:orientation="vertical">
    <DirectionalLayout
        ohos:height="109vp"
        ohos:width="match_parent"
        ohos:orientation="horizontal"
        ohos:padding="10vp">
        <Text
            ohos:id="$+id:item_news_title"
            ohos:height="match_content"
            ohos:width="0vp"
            ohos:max_text_lines="3"
            ohos:multiple_lines="true"
            ohos:right_padding="20vp"
            ohos:text_size="18vp"
            ohos:weight="2"/>
        <Image
            ohos:id="$+id:item_news_image"
            ohos:height="match_content"
            ohos:width="0vp"
            ohos:image_src="$media:news_image"
            ohos:weight="1"/>
    </DirectionalLayout>
    <Component
        ohos:height="1vp"
        ohos:width="match_parent"
        ohos:background_element="#70dbdb"/>
</DirectionalLayout>

在src/main/java/com/huawei/codelab/provider目录下新建NewsTypeProvider.java文件,构造新闻类别的Provider。

package com.huawei.codelab.provider;

import com.huawei.codelab.ResourceTable;
import ohos.agp.components.*;
import ohos.app.Context;

import java.util.Optional;

public class NewsTypeProvider extends BaseItemProvider {
    private String[] newsTypeList;
    private Context context;

    public NewsTypeProvider(String[] listBasicInfo, Context context) {
        this.newsTypeList = listBasicInfo;
        this.context = context;
    }

    @Override
    public int getCount() {
        return newsTypeList == null ? 0 : newsTypeList.length;
    }

    @Override
    public Object getItem(int position) {
        return Optional.of(this.newsTypeList[position]);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public Component getComponent(int position, Component componentP, ComponentContainer componentContainer) {
        ViewHolder viewHolder = null;
        Component component = componentP;
        if (component == null) {
            component = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_item_news_type_layout, null, false);
            viewHolder = new ViewHolder();
            Component componentText = component.findComponentById(ResourceTable.Id_news_type_text);
            if (componentText instanceof Text) {
                viewHolder.title = (Text) componentText;
            }
            component.setTag(viewHolder);
        } else {
            if (component.getTag() instanceof ViewHolder) {
                viewHolder = (ViewHolder) component.getTag();
            }
        }
        if (viewHolder != null) {
            viewHolder.title.setText(newsTypeList[position]);
        }
        return component;
    }

    private static class ViewHolder {
        Text title;
    }
}

在src/main/java/com/huawei/codelab/provider目录下新建NewsListProvider.java文件,构造新闻列表的Provider。

package com.huawei.codelab.provider;

import com.huawei.codelab.ResourceTable;
import com.huawei.codelab.slice.ListContainerSlice;
import ohos.agp.components.*;
import ohos.app.Context;

import java.util.List;
import java.util.Optional;

public class NewsListProvider extends BaseItemProvider {
    private List<ListContainerSlice.NewsInfo> newsInfoList;
    private Context context;

    public NewsListProvider(List<ListContainerSlice.NewsInfo> listBasicInfo, Context context) {
        this.newsInfoList = listBasicInfo;
        this.context = context;
    }

    @Override
    public int getCount() {
        return newsInfoList == null ? 0 : newsInfoList.size();
    }

    @Override
    public Object getItem(int position) {
        return Optional.of(this.newsInfoList.get(position));
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public Component getComponent(int position, Component componentP, ComponentContainer componentContainer) {
        ViewHolder viewHolder = null;
        Component component = componentP;
        if (component == null) {
            component = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_item_news_layout, null, false);
            viewHolder = new ViewHolder();
            Component componentTitle = component.findComponentById(ResourceTable.Id_item_news_title);
            Component componentImage = component.findComponentById(ResourceTable.Id_item_news_image);
            if (componentTitle instanceof Text) {
                viewHolder.title = (Text) componentTitle;
            }
            if (componentImage instanceof Image) {
                viewHolder.image = (Image) componentImage;
            }
            component.setTag(viewHolder);
        } else {
            if (component.getTag() instanceof ViewHolder) {
                viewHolder = (ViewHolder) component.getTag();
            }
        }
        if (viewHolder != null) {
            viewHolder.title.setText(newsInfoList.get(position).getTitle());
            viewHolder.image.setScaleMode(Image.ScaleMode.STRETCH);
        }
        return component;
    }

    private static class ViewHolder {
        Text title;
        Image image;
    }
}

编写AbilitySlice文件
在src/main/java/com/huawei/codelab/slice目录下新建ListContainerSlice.java文件,继承AbilitySlice。
定义成员变量,加载布局:

package com.huawei.codelab.slice;

import com.huawei.codelab.ResourceTable;


import com.huawei.codelab.provider.NewsListProvider;
import com.huawei.codelab.provider.NewsTypeProvider;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Component;
import ohos.agp.components.ListContainer;
import ohos.agp.components.Text;
import ohos.agp.utils.Color;

import java.util.ArrayList;
import java.util.List;

public class ListContainerSlice extends AbilitySlice {

    private static final float FOCUS_TEXT_SIZE = 1.2f;
    private static final float UNFOCUS_TEXT_SIZE = 1.0f;
    private Text selectText;
    private ListContainer newsListContainer;
    private ListContainer selectorListContainer;
    private List<NewsInfo> totalNews;
    private List<NewsInfo> selectNews;
    private NewsTypeProvider newsTypeProvider;
    private NewsListProvider newsListProvider;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_news_list_layout);
        initView();
        initProvider();
        setListContainer();
        initListener();
    }
    private void initView() {
        selectorListContainer = (ListContainer) findComponentById(ResourceTable.Id_selector_list);
        newsListContainer = (ListContainer) findComponentById(ResourceTable.Id_news_container);
    }

    public class NewsInfo {
        private String title;
        private String type;

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }
    }

    private void initProvider() {
        String[] listNames = new String[]{"All", "Health", "Finance", "Technology", "Sport", "Internet", "Game"};
        newsTypeProvider = new NewsTypeProvider(listNames, this);
        newsTypeProvider.notifyDataChanged();

        String[] newsTypes = new String[]{"Health", "Finance", "Finance", "Technology", "Sport", "Health", "Internet", "Game", "Game", "Internet"};
        String[] newsTitles = new String[]{
                "Best Enterprise Wi-Fi Network Award of the Wireless Broadband Alliance 2020",
                "Openness and Cooperation Facilitate Industry Upgrade",
                "High-voltage super-fast charging is an inevitable trend",
                "Ten Future Trends of Digital Energy",
                "Ascend Helps Industry, Learning, and Research Promote AI Industry Development in the National AI Contest",
                "Enterprise data centers are moving towards autonomous driving network",
                "One optical fiber lights up a green smart room",
                "Trust technology, embrace openness, and share the world prosperity brought by technology",
                "Intelligent Twins Won the Leading Technology Achievement Award at the 7th World Internet Conference",
                "Maximizing the Value of Wireless Networks and Ushering in the Golden Decade of 5G"
        };
        totalNews = new ArrayList<>();
        selectNews = new ArrayList<>();
        for (int i = 0; i < newsTypes.length; i++) {
            NewsInfo newsInfo = new NewsInfo();
            newsInfo.setTitle(newsTitles[i]);
            newsInfo.setType(newsTypes[i]);
            totalNews.add(newsInfo);
        }
        selectNews.addAll(totalNews);
        newsListProvider = new NewsListProvider(selectNews, this);
        newsListProvider.notifyDataChanged();
    }

    private void  setListContainer() {
        selectorListContainer.setItemProvider(newsTypeProvider);
        newsListContainer.setItemProvider(newsListProvider);
    }

    private void initListener() {
        selectorListContainer.setItemClickedListener((listContainer, component, position, listener) -> {
            setCategorizationFocus(false);
            Component newsTypeText = component.findComponentById(ResourceTable.Id_news_type_text);
            if (newsTypeText instanceof Text) {
                selectText = (Text) newsTypeText;
            }
            setCategorizationFocus(true);
            selectNews.clear();
            if (position == 0) {
                selectNews.addAll(totalNews);
            } else {
                String newsType = selectText.getText();
                for (NewsInfo newsData : totalNews) {
                    if (newsType.equals(newsData.getType())) {
                        selectNews.add(newsData);
                    }
                }
            }
            updateListView();
        });
        selectorListContainer.setSelected(true);
        selectorListContainer.setSelectedItemIndex(0);
    }

    private void setCategorizationFocus(boolean isFocus) {
        if (selectText == null) {
            return;
        }
        if (isFocus) {
            selectText.setTextColor(new Color(Color.getIntColor("#afaafa")));
            selectText.setScaleX(FOCUS_TEXT_SIZE);
            selectText.setScaleY(FOCUS_TEXT_SIZE);
        } else {
            selectText.setTextColor(new Color(Color.getIntColor("#999999")));
            selectText.setScaleX(UNFOCUS_TEXT_SIZE);
            selectText.setScaleY(UNFOCUS_TEXT_SIZE);
        }
    }

    private void updateListView() {
        newsListProvider.notifyDataChanged();
        newsListContainer.invalidate();
        newsListContainer.scrollToCenter(0);
    }
}

在这里插入图片描述

5. 体验RadioContainer组件

RadioContainer是RadioButton的容器,在其包裹下的RadioButton保证只有一个被选项。RadioContainer组件的使用方法详见常用组件开发指导。在本章节,我们将利用RadioContainer组件编写一道单选题。

编写布局文件
在src/main/resources/base/layout目录下新建布局文件radio_container.xml。

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:alignment="horizontal_center"
    ohos:orientation="vertical"
    ohos:left_padding="32vp">
    <Text
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:top_margin="32vp"
        ohos:text="Question:Which of the following options belong to fruit?"
        ohos:text_size="20fp"
        ohos:layout_alignment="left"
        ohos:multiple_lines="true"/>
    <DirectionalLayout
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:orientation="horizontal"
        ohos:top_margin="8vp">
        <Text
            ohos:height="match_content"
            ohos:width="match_content"
            ohos:text="Your Answer:"
            ohos:text_size="20fp"/>
        <Text
            ohos:id="$+id:answer"
            ohos:height="match_content"
            ohos:width="match_content"
            ohos:text_size="20fp"
            ohos:left_margin="18vp"
            ohos:text="[]"
            ohos:text_color="#FF3333"/>
    </DirectionalLayout>
    <RadioContainer
        ohos:id="$+id:radio_container"
        ohos:height="match_content"
        ohos:width="200vp"
        ohos:layout_alignment="left"
        ohos:orientation="vertical"
        ohos:top_margin="16vp"
        ohos:left_margin="4vp">
        <RadioButton
            ohos:id="$+id:radio_button_1"
            ohos:height="40vp"
            ohos:width="match_content"
            ohos:text="A.Apple"
            ohos:text_size="20fp"
            ohos:text_color_on="#FF3333"/>
        <RadioButton
            ohos:id="$+id:radio_button_2"
            ohos:height="40vp"
            ohos:width="match_content"
            ohos:text="B.Potato"
            ohos:text_size="20fp"
            ohos:text_color_on="#FF3333"/>
        <RadioButton
            ohos:id="$+id:radio_button_3"
            ohos:height="40vp"
            ohos:width="match_content"
            ohos:text="C.Pumpkin"
            ohos:text_size="20fp"
            ohos:text_color_on="#FF3333"/>
        <RadioButton
            ohos:id="$+id:radio_button_4"
            ohos:height="40vp"
            ohos:width="match_content"
            ohos:text="D.Vegetables"
            ohos:text_size="20fp"
            ohos:text_color_on="#FF3333"/>
    </RadioContainer>
</DirectionalLayout>

编写AbilitySlice文件
在src/main/java/com/huawei/codelab/slice目录下新建RadioContainerSlice.java文件,继承AbilitySlice。
加载布局:

package com.huawei.codelab.slice;

import com.huawei.codelab.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.colors.RgbPalette;
import ohos.agp.components.ComponentState;
import ohos.agp.components.RadioButton;
import ohos.agp.components.RadioContainer;
import ohos.agp.components.Text;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.components.element.StateElement;

public class RadioContainerSlice extends AbilitySlice {

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_radio_container);
        initComponent();
    }

    private StateElement getStateElement() {
        ShapeElement elementButtonOn = new ShapeElement();
        elementButtonOn.setRgbColor(RgbPalette.RED);
        elementButtonOn.setShape(ShapeElement.OVAL);

        ShapeElement elementButtonOff = new ShapeElement();
        elementButtonOff.setRgbColor(RgbPalette.DARK_GRAY);
        elementButtonOff.setShape(ShapeElement.OVAL);

        StateElement checkElement = new StateElement();
        checkElement.addState(new int[]{ComponentState.COMPONENT_STATE_CHECKED}, elementButtonOn);
        checkElement.addState(new int[]{ComponentState.COMPONENT_STATE_EMPTY}, elementButtonOff);
        return checkElement;
    }

    private void initComponent() {
        Text answer = (Text) findComponentById(ResourceTable.Id_answer);
        RadioContainer container = (RadioContainer)findComponentById(ResourceTable.Id_radio_container);
        int count = container.getChildCount();
        for (int i = 0; i < count; i++) {
            ((RadioButton) container.getComponentAt(i)).setButtonElement(getStateElement());
        }
        container.setMarkChangedListener((radioContainer1, index) -> {
            answer.setText(String.format("[%c]", (char)('A'+index)));
        });
    }
}

点击Run> Run ‘entry’运行hap包,进入到程序主页,点击主页的RadioContainer即可看到单选题页面,点击不同的选项,单选结果将同步刷新。效果如下所示:
在这里插入图片描述

6. 体验Checkbox组件

Checkbox可以实现选中和取消选中的功能。Checkbox组件的使用方法详见常用组件开发指导。在本章节,我们将利用Checkbox组件编写一道多选题。

编写布局文件
在src/main/resources/base/layout目录下新建布局文件checkbox.xml。

<?xml version="1.0" encoding="utf-8"?> 
<DirectionalLayout 
    xmlns:ohos="http://schemas.huawei.com/res/ohos" 
    ohos:height="match_parent" 
    ohos:width="match_parent" 
    ohos:orientation="vertical" 
    ohos:left_padding="32vp"> 
    <Text 
        ohos:height="match_content" 
        ohos:width="match_parent" 
        ohos:top_margin="32vp" 
        ohos:text="Question:Which of the following are fruits?" 
        ohos:text_size="20fp" 
        ohos:layout_alignment="left" 
        ohos:multiple_lines="true"/> 
    <DirectionalLayout 
        ohos:height="match_content" 
        ohos:width="match_parent" 
        ohos:orientation="horizontal" 
        ohos:top_margin="8vp"> 
        <Text 
            ohos:height="match_content" 
            ohos:width="match_content" 
            ohos:text="Your Answer:" 
            ohos:text_size="20fp"/> 
        <Text 
            ohos:id="$+id:text_answer" 
            ohos:height="match_content" 
            ohos:width="match_content" 
            ohos:text_size="20fp" 
            ohos:left_margin="18vp" 
            ohos:text="[]" 
            ohos:text_color="#FF3333"/> 
    </DirectionalLayout> 
    <Checkbox 
        ohos:id="$+id:checkbox_1" 
        ohos:top_margin="20vp" 
        ohos:height="match_content" 
        ohos:width="match_content" 
        ohos:text="A Apples" 
        ohos:text_size="20fp" 
        ohos:text_color_on="#FF3333" 
        ohos:text_color_off="#000000"/> 
    <Checkbox 
        ohos:id="$+id:checkbox_2" 
        ohos:top_margin="20vp" 
        ohos:height="match_content" 
        ohos:width="match_content" 
        ohos:text="B Bananas" 
        ohos:text_size="20fp" 
        ohos:text_color_on="#FF3333" 
        ohos:text_color_off="#000000"/> 
    <Checkbox 
        ohos:id="$+id:checkbox_3" 
        ohos:top_margin="20vp" 
        ohos:height="match_content" 
        ohos:width="match_content" 
        ohos:text="C Strawberries" 
        ohos:text_size="20fp" 
        ohos:text_color_on="#FF3333" 
        ohos:text_color_off="#000000" /> 
    <Checkbox 
        ohos:id="$+id:checkbox_4" 
        ohos:top_margin="20vp" 
        ohos:height="match_content" 
        ohos:width="match_content" 
        ohos:text="D Potatoes" 
        ohos:text_size="20fp" 
        ohos:text_color_on="#FF3333" 
        ohos:text_color_off="black" /> 
</DirectionalLayout>

编写AbilitySlice文件
在src/main/java/com/huawei/codelab/slice目录下新建CheckboxSlice.java文件,继承AbilitySlice。
定义成员变量,加载布局:

package com.huawei.codelab.slice;

import com.huawei.codelab.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.colors.RgbPalette;
import ohos.agp.components.Checkbox;
import ohos.agp.components.ComponentState;
import ohos.agp.components.Text;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.components.element.StateElement;

import java.util.HashSet;
import java.util.Set;

public class CheckboxSlice extends AbilitySlice {

    private Text answer;
    private Set<String> selectedSet = new HashSet<>();

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_checkbox);
        answer = (Text) findComponentById(ResourceTable.Id_text_answer);
        initCheckbox();
    }
    private void initCheckbox() {
        Checkbox checkbox1 = (Checkbox) findComponentById(ResourceTable.Id_checkbox_1);
        checkbox1.setButtonElement(getStateElement());
        setCheckedStateChangedListener(checkbox1, "A");
        if (checkbox1.isChecked()) {
            selectedSet.add("A");
        }

        Checkbox checkbox2 = (Checkbox) findComponentById(ResourceTable.Id_checkbox_2);
        checkbox2.setButtonElement(getStateElement());
        setCheckedStateChangedListener(checkbox2, "B");
        if (checkbox2.isChecked()) {
            selectedSet.add("B");
        }

        Checkbox checkbox3 = (Checkbox) findComponentById(ResourceTable.Id_checkbox_3);
        checkbox3.setButtonElement(getStateElement());
        setCheckedStateChangedListener(checkbox3, "C");
        if (checkbox3.isChecked()) {
            selectedSet.add("C");
        }

        Checkbox checkbox4 = (Checkbox) findComponentById(ResourceTable.Id_checkbox_4);
        checkbox4.setButtonElement(getStateElement());
        setCheckedStateChangedListener(checkbox4, "D");
        if (checkbox4.isChecked()) {
            selectedSet.add("D");
        }
    }
    private StateElement getStateElement() {
        ShapeElement elementButtonOn = new ShapeElement();
        elementButtonOn.setRgbColor(RgbPalette.RED);
        elementButtonOn.setShape(ShapeElement.OVAL);

        ShapeElement elementButtonOff = new ShapeElement();
        elementButtonOff.setRgbColor(RgbPalette.WHITE);
        elementButtonOff.setShape(ShapeElement.OVAL);

        StateElement checkElement = new StateElement();
        checkElement.addState(new int[]{ComponentState.COMPONENT_STATE_CHECKED}, elementButtonOn);
        checkElement.addState(new int[]{ComponentState.COMPONENT_STATE_EMPTY}, elementButtonOff);
        return checkElement;
    }

    private void setCheckedStateChangedListener(Checkbox checkbox, String CheckValue) {
        checkbox.setCheckedStateChangedListener((view, state) -> {
            if (state) {
                selectedSet.add(CheckValue);
            }else {
                selectedSet.remove(CheckValue);
            }
            showAnswer();
        });
    }

    private void showAnswer() {
        String select = selectedSet.toString();
        answer.setText(select);
    }
}

运行程序
点击Run> Run ‘entry’运行hap包,进入到程序主页,点击主页的Checkbox即可看到多选题页面,点击不同的选项,多选结果将同步刷新。效果如下所示:
在这里插入图片描述

7. 体验DatePicker组件

DatePicker主要供用户选择日期。DatePicker组件的使用方法详见常用组件开发指导。在本章节,我们将利用DatePicker组件编写一个日期选择小程序。

编写布局文件
在src/main/resources/base/layout目录下新建布局文件data_picker.xml。

<?xml version="1.0" encoding="utf-8"?> 
<DirectionalLayout 
    xmlns:ohos="http://schemas.huawei.com/res/ohos" 
    ohos:width="match_parent" 
    ohos:height="match_parent" 
    ohos:orientation="vertical"> 
    <DatePicker 
        ohos:id="$+id:date_pick" 
        ohos:height="150vp" 
        ohos:width="300vp" 
        ohos:background_element="#EDEDED" 
        ohos:top_margin="13vp" 
        ohos:layout_alignment="horizontal_center" 
        ohos:selected_normal_text_margin_ratio="6" 
        ohos:selected_text_size="16vp" 
        ohos:selected_text_color="#0000FF" 
        ohos:operated_text_color="#0000FF" 
        ohos:normal_text_size="13vp" 
        ohos:top_line_element="#9370DB" 
        ohos:bottom_line_element="#9370DB" 
        ohos:shader_color="#00CED1"> 
    </DatePicker> 
    <DirectionalLayout 
        ohos:width="match_content" 
        ohos:height="35vp" 
        ohos:top_margin="13vp" 
        ohos:layout_alignment="horizontal_center" 
        ohos:orientation="horizontal"> 
        <Text 
            ohos:width="match_content" 
            ohos:height="match_parent" 
            ohos:text_size="15vp" 
            ohos:padding="4vp" 
            ohos:text="Currently selected date:  "/> 
        <Text 
            ohos:id="$+id:text_date" 
            ohos:height="match_content" 
            ohos:width="100vp" 
            ohos:background_element="$graphic:button_element" 
            ohos:hint="date" 
            ohos:left_margin="13vp" 
            ohos:padding="4vp" 
            ohos:text_size="15vp"> 
        </Text> 
    </DirectionalLayout> 
</DirectionalLayout>

编写AbilitySlice文件
在src/main/java/com/huawei/codelab/slice目录下新建DatePickerSlice.java文件,继承AbilitySlice。
定义成员变量,加载布局:

package com.huawei.codelab.slice;

import com.huawei.codelab.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.DatePicker;
import ohos.agp.components.Text;

public class DatePickerSlice extends AbilitySlice {

    private DatePicker datePicker;
    private Text textDate;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_data_picker);
        initComponent();
        initDate();
        setValueChangedListener();

    }
    private void initComponent() {
        datePicker = (DatePicker) findComponentById(ResourceTable.Id_date_pick);
        textDate = (Text) findComponentById(ResourceTable.Id_text_date);
    }

    private void initDate() {
        int day = datePicker.getDayOfMonth();
        int month = datePicker.getMonth();
        int year = datePicker.getYear();
        textDate.setText(String.format("%02d/%02d/%4d", day, month, year));
    }
    private void setValueChangedListener(){
        datePicker.setValueChangedListener(
                new DatePicker.ValueChangedListener() {
                    @Override
                    public void onValueChanged(DatePicker picker, int year, int monthOfYear, int dayOfMonth) {
                        textDate.setText(String.format("%02d/%02d/%4d", dayOfMonth, monthOfYear, year));
                    }
                }
        );
    }
}

运行程序
点击Run> Run ‘entry’运行hap包,进入到程序主页,点击主页的DatePicker即可看到日期选择页面,默认显示当前日期;滑动年/月/日,下面显示的日期将同步刷新。效果如下所示:
在这里插入图片描述

8. 体验DirectionalLayout布局

DirectionalLayout是Java UI中的一种重要组件布局,用于将一组组件(Component)按照水平或者垂直方向排布,能够方便地对齐布局内的组件。DirectionalLayout布局的使用方法详见常用布局开发指导。在此章节,我们将利用DirectionalLayout布局编写一个中秋灯谜列表。

编写布局文件
在src/main/resources/base/layout目录下新建布局文件directional_layout.xml。

<?xml version="1.0" encoding="utf-8"?> 
<DirectionalLayout 
    xmlns:ohos="http://schemas.huawei.com/res/ohos" 
    ohos:width="match_parent" 
    ohos:height="match_parent" 
    ohos:top_margin="13fp" 
    ohos:orientation="vertical"> 
    <Text 
        ohos:width="match_content" 
        ohos:height="match_content" 
        ohos:text="Lantern riddles of Mid Autumn Festival" 
        ohos:text_alignment="center" 
        ohos:multiple_lines="true" 
        ohos:layout_alignment="center" 
        ohos:top_margin="20vp" 
        ohos:text_size="23vp"/> 
    <Text 
        ohos:width="match_parent" 
        ohos:height="match_content" 
        ohos:text="1.what man cannot live in a house?" 
        ohos:multiple_lines="true" 
        ohos:left_margin="20vp" 
        ohos:top_margin="20vp" 
        ohos:text_size="18vp"/> 
    <Text 
        ohos:width="match_parent" 
        ohos:height="match_content" 
        ohos:text="2.What never asks questions but gets a lot of answers?" 
        ohos:multiple_lines="true" 
        ohos:left_margin="20vp" 
        ohos:top_margin="20vp" 
        ohos:text_size="18vp"/> 
    <Text 
        ohos:width="match_parent" 
        ohos:height="match_content" 
        ohos:text="3.A mouse has a large pocket.What is it?" 
        ohos:multiple_lines="true" 
        ohos:left_margin="20vp" 
        ohos:top_margin="20vp" 
        ohos:text_size="18vp"/> 
    <Text 
        ohos:width="match_parent" 
        ohos:height="match_content" 
        ohos:text="4.What can hear you without ears and can answer you without a mouth?" 
        ohos:multiple_lines="true" 
        ohos:left_margin="20vp" 
        ohos:top_margin="20vp" 
        ohos:text_size="18vp"/> 
    <Text 
        ohos:width="match_parent" 
        ohos:height="match_content" 
        ohos:text="5.What is higher without a head than with a head?" 
        ohos:multiple_lines="true" 
        ohos:left_margin="20vp" 
        ohos:top_margin="20vp" 
        ohos:text_size="18vp"/> 
    <Text 
        ohos:width="match_parent" 
        ohos:height="match_content" 
        ohos:text="6.What is dark but made by light?" 
        ohos:multiple_lines="true" 
        ohos:left_margin="20vp" 
        ohos:top_margin="20vp" 
        ohos:text_size="18vp"/> 
    <Text 
        ohos:width="match_parent" 
        ohos:height="match_content" 
        ohos:text="7.What person tried to make you smile most of the time?" 
        ohos:multiple_lines="true" 
        ohos:left_margin="20vp" 
        ohos:top_margin="20vp" 
        ohos:text_size="18vp"/> 
    <Text 
        ohos:width="match_parent" 
        ohos:height="match_content" 
        ohos:text="8.You have it.You read it.There're some pictures in it?" 
        ohos:multiple_lines="true" 
        ohos:left_margin="20vp" 
        ohos:top_margin="20vp" 
        ohos:text_size="18vp"/> 
    <Text 
        ohos:width="match_parent" 
        ohos:height="match_content" 
        ohos:text="9.What animal has a head like a cat, eyes like a cat, a tail like a cat, but isn't a cat? " 
        ohos:multiple_lines="true" 
        ohos:left_margin="20vp" 
        ohos:top_margin="20vp" 
        ohos:text_size="18vp"/> 
    <Text 
        ohos:width="match_parent" 
        ohos:height="match_content" 
        ohos:text="10.What has hands but no feet, a face but no eyes, tells but not talk?" 
        ohos:multiple_lines="true" 
        ohos:left_margin="20vp" 
        ohos:top_margin="20vp" 
        ohos:text_size="18vp"/> 
</DirectionalLayout>

编写AbilitySlice文件
在src/main/java/com/huawei/codelab/slice目录下新建DirectionalLayoutSlice.java文件,继承AbilitySlice。
加载布局:

package com.huawei.codelab.slice;

import com.huawei.codelab.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;

public class DirectionalLayoutSlice extends AbilitySlice {

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_directional_layout);
    }
}

运行程序
点击Run> Run ‘entry’运行hap包,进入到程序主页,点击主页的DirectionalLayout即可看到中秋灯谜页面。效果如下所示:

在这里插入图片描述

9. 体验DependentLayout布局

DependentLayout是Java UI系统里的一种常见布局。与DirectionalLayout相比,拥有更多的排布方式,每个组件可以指定相对于其他同级元素的位置,或者指定相对于父组件的位置。DependentLayout布局的使用方法可详见常用布局开发指导。在本章节,我们将利用DirectionalLayout和DependentLayout布局编写一个新闻详情页面。

编写布局文件
在src/main/resources/base/layout目录下新建布局文件dependent_layout.xml。

<?xml version="1.0" encoding="utf-8"?> 
<DependentLayout 
    xmlns:ohos="http://schemas.huawei.com/res/ohos" 
    ohos:id="$+id:parent_layout" 
    ohos:height="match_parent" 
    ohos:width="match_parent"> 
    <ScrollView 
        ohos:height="match_parent" 
        ohos:width="match_parent"> 
        <DirectionalLayout 
            ohos:height="match_content" 
            ohos:width="match_parent" 
            ohos:bottom_padding="70vp" 
            ohos:orientation="vertical"> 
            <DirectionalLayout 
                ohos:height="match_content" 
                ohos:width="match_parent" 
                ohos:alignment="vertical_center" 
                ohos:orientation="horizontal" 
                ohos:background_element="#FFFFFF"> 
                <Text 
                    ohos:id="$+id:title_icon" 
                    ohos:height="match_content" 
                    ohos:width="match_content" 
                    ohos:text="NewsDemo" 
                    ohos:left_margin="20vp" 
                    ohos:text_size="20fp" 
                    ohos:weight="1"/> 
                <Text 
                    ohos:id="$+id:read_num" 
                    ohos:height="match_content" 
                    ohos:width="match_content" 
                    ohos:right_margin="10vp" 
                    ohos:text="reads:10" 
                    ohos:text_size="10fp"/> 
                <Text 
                    ohos:id="$+id:likes_num" 
                    ohos:height="match_content" 
                    ohos:width="match_content" 
                    ohos:right_margin="20vp" 
                    ohos:text="likes:9" 
                    ohos:text_size="10fp"/> 
            </DirectionalLayout> 
            <Text 
                ohos:id="$+id:title_text" 
                ohos:height="match_content" 
                ohos:width="match_parent" 
                ohos:left_margin="20vp" 
                ohos:max_text_lines="4" 
                ohos:multiple_lines="true" 
                ohos:right_margin="20vp" 
                ohos:text="Ten Future Trends of Digital Energy" 
                ohos:text_color="#000000" 
                ohos:text_size="18fp" 
                ohos:top_margin="10vp"/> 
            <Text 
                ohos:id="$+id:title_content" 
                ohos:height="match_content" 
                ohos:width="match_parent" 
                ohos:left_margin="20vp" 
                ohos:multiple_lines="true" 
                ohos:right_margin="20vp" 
                ohos:text="Energy digitalization is an inevitable trend. Innovative integration of digital and energy technologies enables end-to-end visual, manageable, and controllable intelligent management of energy infrastructure, improving energy efficiency." 
                ohos:text_alignment="center_horizontal" 
                ohos:text_color="#708090" 
                ohos:text_size="16fp" 
                ohos:top_margin="5vp"/> 
            <DirectionalLayout 
                ohos:height="match_content" 
                ohos:width="match_parent" 
                ohos:orientation="horizontal"> 
                <Image 
                    ohos:id="$+id:image_content1" 
                    ohos:height="100vp" 
                    ohos:width="0vp" 
                    ohos:image_src="$media:news_image_left" 
                    ohos:layout_alignment="center" 
                    ohos:left_margin="20vp" 
                    ohos:right_margin="2vp" 
                    ohos:top_margin="10vp" 
                    ohos:weight="1"/> 
                <Image 
                    ohos:id="$+id:image_content2" 
                    ohos:height="100vp" 
                    ohos:width="0vp" 
                    ohos:image_src="$media:news_image" 
                    ohos:layout_alignment="center" 
                    ohos:left_margin="10vp" 
                    ohos:right_margin="2vp" 
                    ohos:top_margin="10vp" 
                    ohos:weight="1"/> 
                <Image 
                    ohos:id="$+id:image_content3" 
                    ohos:height="100vp" 
                    ohos:width="0vp" 
                    ohos:image_src="$media:news_image_right" 
                    ohos:layout_alignment="center" 
                    ohos:left_margin="2vp" 
                    ohos:right_margin="20vp" 
                    ohos:top_margin="10vp" 
                    ohos:weight="1"/> 
            </DirectionalLayout> 
        </DirectionalLayout> 
    </ScrollView> 
    <Component 
        ohos:height="0.5vp" 
        ohos:width="match_parent" 
        ohos:above="$+id:bottom_layout" 
        ohos:background_element="#EAEAEC"/> 
    <DirectionalLayout 
        ohos:id="$+id:bottom_layout" 
        ohos:height="50vp" 
        ohos:width="match_parent" 
        ohos:align_parent_bottom="true" 
        ohos:alignment="vertical_center" 
        ohos:background_element="#ffffff" 
        ohos:left_padding="20vp" 
        ohos:orientation="horizontal" 
        ohos:right_padding="20vp"> 
        <TextField 
            ohos:height="30vp" 
            ohos:width="160vp" 
            ohos:background_element="$graphic:corner_bg_comment" 
            ohos:hint="Enter a comment." 
            ohos:left_padding="5vp" 
            ohos:right_padding="10vp" 
            ohos:text_alignment="vertical_center" 
            ohos:text_size="15vp"/> 
        <Image 
            ohos:height="20vp" 
            ohos:width="20vp" 
            ohos:scale_mode="stretch" 
            ohos:image_src="$media:message_icon" 
            ohos:left_margin="20vp"/> 
        <Image 
            ohos:height="20vp" 
            ohos:width="20vp" 
            ohos:scale_mode="stretch" 
            ohos:image_src="$media:collect_icon" 
            ohos:left_margin="20vp"/> 
        <Image 
            ohos:height="20vp" 
            ohos:width="20vp" 
            ohos:scale_mode="stretch" 
            ohos:image_src="$media:like_icon" 
            ohos:left_margin="20vp"/> 
        <Image 
            ohos:height="20vp" 
            ohos:width="20vp" 
            ohos:scale_mode="stretch" 
            ohos:image_src="$media:share_icon" 
            ohos:left_margin="20vp"/> 
    </DirectionalLayout> 
</DependentLayout>

编写AbilitySlice文件
在src/main/java/com/huawei/codelab/slice目录下新建DependentLayoutSlice.java文件,继承AbilitySlice。
加载布局:

package com.huawei.codelab.slice;

import com.huawei.codelab.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;

public class DependentLayoutSlice extends AbilitySlice {

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_dependent_layout);
    }
}

运行程序
点击Run> Run ‘entry’运行hap包,进入到程序主页,点击主页的DependentLayout即可看到新闻详情页面,效果如下所示:

在这里插入图片描述

10. 体验StackLayout布局

StackLayout直接在屏幕上开辟出一块空白的区域,添加到这个布局中的视图都是以层叠的方式显示,而它会把这些视图默认放到这块区域的左上角,第一个添加到布局中的视图显示在最底层,最后一个被放在最顶层。上一层的视图会覆盖下一层的视图。StackLayout布局的使用方法详见常用布局开发指导。

编写布局文件
在src/main/resources/base/layout目录下新建布局文件stack_layout.xml。

<?xml version="1.0" encoding="utf-8"?> 
<StackLayout 
    xmlns:ohos="http://schemas.huawei.com/res/ohos" 
    ohos:id="$+id:stack_layout" 
    ohos:height="match_parent" 
    ohos:width="match_parent"> 
    <Text 
        ohos:id="$+id:text_blue" 
        ohos:text_alignment="bottom|horizontal_center" 
        ohos:text_size="24fp" 
        ohos:text="Layer1" 
        ohos:height="400vp" 
        ohos:width="match_parent" 
        ohos:background_element="#70dbdb" /> 
    <Text 
        ohos:id="$+id:text_light_purple" 
        ohos:text_alignment="bottom|horizontal_center" 
        ohos:text_size="24fp" 
        ohos:text="Layer2" 
        ohos:height="300vp" 
        ohos:width="300vp" 
        ohos:background_element="#EED2EE" /> 
    <Text 
        ohos:id="$+id:text_green" 
        ohos:text_alignment="center" 
        ohos:text_size="24fp" 
        ohos:text="Layer3" 
        ohos:height="200vp" 
        ohos:width="200vp" 
        ohos:background_element="#B4EEB4" /> 
</StackLayout>

编写AbilitySlice文件
在src/main/java/com/huawei/codelab/slice目录下新建StackLayoutSlice.java文件,继承AbilitySlice。
加载布局:

package com.huawei.codelab.slice;

import com.huawei.codelab.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;

public class StackLayoutSlice extends AbilitySlice {

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_stack_layout);
    }
}

运行程序
点击Run> Run ‘entry’运行hap包,进入到程序主页,点击主页的StackLayout即可看到页面效果如下:
在这里插入图片描述

11. 体验TableLayout布局

TableLayout使用表格的方式划分子组件。TableLayout布局的使用方法详见常用组件开发指导。在本章节,我们将利用TableLayout布局编写一个拨号盘。

编写布局文件
在src/main/resources/base/layout目录下新建布局文件table_layout.xml。

<?xml version="1.0" encoding="utf-8"?> 
<DirectionalLayout 
    xmlns:ohos="http://schemas.huawei.com/res/ohos" 
    ohos:width="match_parent" 
    ohos:height="match_parent" 
    ohos:background_element="#EDEDED" 
    ohos:layout_alignment="center" 
    ohos:orientation="vertical"> 
    <Text 
        ohos:id="$+id:info" 
        ohos:width="match_content" 
        ohos:height="30vp" 
        ohos:text_size="20fp" 
        ohos:top_margin="20vp" 
        ohos:text="" 
        ohos:text_alignment="center" 
        ohos:layout_alignment="horizontal_center"/> 
    <TableLayout 
        ohos:id="$+id:table" 
        ohos:width="700" 
        ohos:height="match_content" 
        ohos:orientation="horizontal" 
        ohos:layout_alignment="horizontal_center" 
        ohos:top_margin="10" 
        ohos:column_count="3"> 
        <Button 
            ohos:width="50vp" 
            ohos:height="50vp" 
            ohos:text_size="15fp" 
            ohos:left_margin="20vp" 
            ohos:top_margin="15vp" 
            ohos:background_element="$graphic:circle_button_element" 
            ohos:text="1" 
            ohos:text_alignment="center"/> 
        <Button 
            ohos:width="50vp" 
            ohos:height="50vp" 
            ohos:text_size="15fp" 
            ohos:left_margin="20vp" 
            ohos:top_margin="15vp" 
            ohos:background_element="$graphic:circle_button_element" 
            ohos:text="2" 
            ohos:text_alignment="center"/> 
        <Button 
            ohos:width="50vp" 
            ohos:height="50vp" 
            ohos:text_size="15fp" 
            ohos:left_margin="20vp" 
            ohos:top_margin="15vp" 
            ohos:background_element="$graphic:circle_button_element" 
            ohos:text="3" 
            ohos:text_alignment="center"/> 
        <Button 
            ohos:width="50vp" 
            ohos:height="50vp" 
            ohos:text_size="15fp" 
            ohos:left_margin="20vp" 
            ohos:top_margin="15vp" 
            ohos:background_element="$graphic:circle_button_element" 
            ohos:text="4" 
            ohos:text_alignment="center"/> 
        <Button 
            ohos:width="50vp" 
            ohos:height="50vp" 
            ohos:text_size="15fp" 
            ohos:left_margin="20vp" 
            ohos:top_margin="15vp" 
            ohos:background_element="$graphic:circle_button_element" 
            ohos:text="5" 
            ohos:text_alignment="center"/> 
        <Button 
            ohos:width="50vp" 
            ohos:height="50vp" 
            ohos:text_size="15fp" 
            ohos:left_margin="20vp" 
            ohos:top_margin="15vp" 
            ohos:background_element="$graphic:circle_button_element" 
            ohos:text="6" 
            ohos:text_alignment="center"/> 
        <Button 
            ohos:width="50vp" 
            ohos:height="50vp" 
            ohos:text_size="15fp" 
            ohos:left_margin="20vp" 
            ohos:top_margin="15vp" 
            ohos:background_element="$graphic:circle_button_element" 
            ohos:text="7" 
            ohos:text_alignment="center"/> 
        <Button 
            ohos:width="50vp" 
            ohos:height="50vp" 
            ohos:text_size="15fp" 
            ohos:left_margin="20vp" 
            ohos:top_margin="15vp" 
            ohos:background_element="$graphic:circle_button_element" 
            ohos:text="8" 
            ohos:text_alignment="center"/> 
        <Button 
            ohos:width="50vp" 
            ohos:height="50vp" 
            ohos:text_size="15fp" 
            ohos:left_margin="20vp" 
            ohos:top_margin="15vp" 
            ohos:background_element="$graphic:circle_button_element" 
            ohos:text="9" 
            ohos:text_alignment="center"/> 
        <Button 
            ohos:width="50vp" 
            ohos:height="50vp" 
            ohos:text_size="15fp" 
            ohos:left_margin="20vp" 
            ohos:top_margin="15vp" 
            ohos:background_element="$graphic:circle_button_element" 
            ohos:text="*" 
            ohos:text_alignment="center"/> 
        <Button 
            ohos:width="50vp" 
            ohos:height="50vp" 
            ohos:text_size="15fp" 
            ohos:left_margin="20vp" 
            ohos:top_margin="15vp" 
            ohos:background_element="$graphic:circle_button_element" 
            ohos:text="0" 
            ohos:text_alignment="center"/> 
        <Button 
            ohos:width="50vp" 
            ohos:height="50vp" 
            ohos:text_size="15fp" 
            ohos:left_margin="20vp" 
            ohos:top_margin="15vp" 
            ohos:background_element="$graphic:circle_button_element" 
            ohos:text="#" 
            ohos:text_alignment="center"/> 
    </TableLayout> 
    <DirectionalLayout 
        ohos:width="match_content" 
        ohos:height="match_content" 
        ohos:top_margin="20vp" 
        ohos:layout_alignment="horizontal_center" 
        ohos:orientation="horizontal"> 
        <Button 
            ohos:id="$+id:call" 
            ohos:width="60vp" 
            ohos:height="35vp" 
            ohos:text_size="15fp" 
            ohos:text="CALL" 
            ohos:background_element="$graphic:button_element" 
            ohos:text_alignment="center"/> 
        <Button 
            ohos:id="$+id:clear" 
            ohos:width="60vp" 
            ohos:height="35vp" 
            ohos:text_size="15fp" 
            ohos:text="CLEAR" 
            ohos:background_element="$graphic:button_element" 
            ohos:left_margin="10vp" 
            ohos:text_alignment="center"/> 
    </DirectionalLayout> 
</DirectionalLayout>

编写AbilitySlice文件
在src/main/java/com/huawei/codelab/slice目录下新建TableLayoutSlice.java文件,继承AbilitySlice。
定义成员变量,加载布局:

package com.huawei.codelab.slice;

import com.huawei.codelab.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.TableLayout;
import ohos.agp.components.Text;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.window.dialog.ToastDialog;

public class TableLayoutSlice extends AbilitySlice {

    private Text info;
    private Button call;
    private Button clear;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_table_layout);
        initComponent();
        setClickedListener();
    }

    private void initComponent() {
        info = (Text)findComponentById(ResourceTable.Id_info);
        call = (Button)findComponentById(ResourceTable.Id_call);
        clear = (Button)findComponentById(ResourceTable.Id_clear);
    }

    private void setClickedListener() {
        call.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                String toastInfo = info.getText();
                if (toastInfo == null || toastInfo.isEmpty()) {
                    toastInfo = "Please enter the number!";
                } else {
                    toastInfo = "Call " + info.getText();
                }
                new ToastDialog(getContext())
                        .setText(toastInfo)
                        .setAlignment(LayoutAlignment.CENTER)
                        .setOffset(0,180)
                        .show();
            }
        });

        clear.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                info.setText("");
            }
        });

        TableLayout table = (TableLayout)findComponentById(ResourceTable.Id_table);
        int childNum = table.getChildCount();
        for (int index = 0; index < childNum; index++) {
            Button child = (Button)(table.getComponentAt(index));
            child.setClickedListener(new Component.ClickedListener() {
                @Override
                public void onClick(Component component) {
                    if (component instanceof Button) {
                        Button button = (Button)component;
                        info.setText(info.getText() + button.getText());
                    }
                }
            });
        }
    }
}

运行程序
点击Run> Run ‘entry’运行hap包,进入到程序主页,点击主页的TableLayout即可看到拨号盘页面。点击拨号盘上的按钮,拨号盘上方会显示输入的号码;点击拨号盘下方的CLEAR按钮,拨号盘上方显示内容将清空。效果如下所示:

在这里插入图片描述

【挑战主题】2、图片旋转

    1. 项目介绍
      HarmonyOS图像模块支持图像业务的开发,常见功能如图像解码、图像编码、基本的位图操作、图像编辑等。当然,也支持通过接口组合来实现更复杂的图像处理逻辑。本教程以图库图片中旋转、剪裁、缩放、镜像四种常见操作为例,给大家介绍HarmonyOS图像编解码的相关开发指导。
    1. 将图片转换为PixelMap
      图像解码就是将所支持格式的存档图片解码成统一的PixelMap图像,用于后续图像显示或其他处理,比如旋转、缩放、剪裁等。当前支持格式包括JPEG、PNG、GIF、HEIF、WebP、BMP。本例为您提供了getPixelMapFromResource函数,可以将resources/base/media目录下的图片资源转换为PixelMap图像,其中入参为图片的资源ID,
  1. 将图片转换为PixelMap
    图像解码就是将所支持格式的存档图片解码成统一的PixelMap图像,用于后续图像显示或其他处理,比如旋转、缩放、剪裁等。当前支持格式包括JPEG、PNG、GIF、HEIF、WebP、BMP。本例为您提供了getPixelMapFromResource函数,可以将resources/base/media目录下的图片资源转换为PixelMap图像,其中入参为图片的资源ID,
private PixelMap getPixelMapFromResource(int resourceId) {
    InputStream inputStream = null;
    try {
        // 创建图像数据源ImageSource对象
        inputStream = getContext().getResourceManager().getResource(resourceId);
        ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions();
        srcOpts.formatHint = "image/jpg";
        ImageSource imageSource = ImageSource.create(inputStream, srcOpts);


        // 设置图片参数
        ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
        return imageSource.createPixelmap(decodingOptions);
    } catch (IOException e) {
        HiLog.info(LABEL_LOG, "IOException");
    } catch (NotExistException e) {
        HiLog.info(LABEL_LOG, "NotExistException");
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                HiLog.info(LABEL_LOG, "inputStream IOException");
            }
        }
    }
    return null;
}

  1. 图片参数设置
    本例使用图片像素的尺寸为1024*768,点击一次旋转按钮会进行90度的旋转,缩放是按照2:1的比例进行缩放,剪裁是保证宽度不变的情况下对高度进行400像素的剪裁,相关参数设置如下所示:
// 设置图片参数 
ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions(); 
// 旋转 
decodingOptions.rotateDegrees = 90 * whirlCount; 
// 缩放 
decodingOptions.desiredSize = new Size(isScale ? 512 : 0, isScale ? 384 : 0); 
// 剪裁 
decodingOptions.desiredRegion = new Rect(0, 0, isCorp ? 1024 : 0, isCorp ? 400 : 0);
  1. 图片镜像操作
    图片镜像操作就是对图片以纵坐标为轴制作对称图片。image绘制的时候会调用onDraw方法,本例采用对图像Canvas画布的镜像操作实现图片的镜像显示,示例代码如下所示:
private void mirrorImage(PixelMap pixelMap) { 
    scaleX = -scaleX; 
    image.addDrawTask( 
            new Component.DrawTask() { 
                @Override 
                public void onDraw(Component component, Canvas canvas) { 
                    if (isMirror) { 
                        isMirror = false; 
                        PixelMapHolder pmh = new PixelMapHolder(pixelMap); 
                        canvas.scale( 
                                scaleX, 
                                1.0f, 
                                (float) pixelMap.getImageInfo().size.width / 2, 
                                (float) pixelMap.getImageInfo().size.height / 2); 
                        canvas.drawPixelMapHolder( 
                                pmh, 
                                0, 
                                0, 
                                new Paint()); 
                    } 
                } 
            }); 
}

完整s示例:在这里插入代码片

import com.huawei.codelab.ResourceTable; 
 
import ohos.aafwk.ability.AbilitySlice; 
import ohos.aafwk.content.Intent; 
import ohos.agp.components.Button; 
import ohos.agp.components.Component; 
import ohos.agp.components.Image; 
import ohos.agp.render.Canvas; 
import ohos.agp.render.Paint; 
import ohos.agp.render.PixelMapHolder; 
import ohos.global.resource.NotExistException; 
import ohos.hiviewdfx.HiLog; 
import ohos.hiviewdfx.HiLogLabel; 
import ohos.media.image.ImageSource; 
import ohos.media.image.PixelMap; 
import ohos.media.image.common.PixelFormat; 
import ohos.media.image.common.Rect; 
import ohos.media.image.common.Size; 
 
import java.io.IOException; 
import java.io.InputStream; 
 
/** 
 * 图像主页面 
 */ 
public class MainAbilitySlice extends AbilitySlice { 
    private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "MainAbilitySlice"); 
    Image image; 
    PixelMap imagePixelMap; 
    Button whirlImageBtn; 
    Button cropImageBtn; 
    Button scaleImageBtn; 
    Button mirrorImageBtn; 
    private int whirlCount = 0; 
    private boolean isCorp = false; 
    private boolean isScale = false; 
    private boolean isMirror = false; 
    private float scaleX = 1.0f; 
 
    @Override 
    public void onStart(Intent intent) { 
        super.onStart(intent); 
        super.setUIContent(ResourceTable.Layout_ability_main); 
        initView(); 
    } 
 
    private void initView() { 
        if (findComponentById(ResourceTable.Id_whirl_image) instanceof Button) { 
            whirlImageBtn = (Button) findComponentById(ResourceTable.Id_whirl_image); 
        } 
        if (findComponentById(ResourceTable.Id_crop_image) instanceof Button) { 
            cropImageBtn = (Button) findComponentById(ResourceTable.Id_crop_image); 
        } 
        if (findComponentById(ResourceTable.Id_scale_image) instanceof Button) { 
            scaleImageBtn = (Button) findComponentById(ResourceTable.Id_scale_image); 
        } 
        if (findComponentById(ResourceTable.Id_mirror_image) instanceof Button) { 
            mirrorImageBtn = (Button) findComponentById(ResourceTable.Id_mirror_image); 
        } 
        if (findComponentById(ResourceTable.Id_image) instanceof Image) { 
            image = (Image) findComponentById(ResourceTable.Id_image); 
        } 
        whirlImageBtn.setClickedListener(new ButtonClick()); 
        cropImageBtn.setClickedListener(new ButtonClick()); 
        scaleImageBtn.setClickedListener(new ButtonClick()); 
        mirrorImageBtn.setClickedListener(new ButtonClick()); 
    } 
 
    private class ButtonClick implements Component.ClickedListener { 
        @Override 
        public void onClick(Component component) { 
            int btnId = component.getId(); 
            switch (btnId) { 
                case ResourceTable.Id_whirl_image: 
                    // 旋转图片 
                    whirlCount++; 
                    isCorp = false; 
                    isScale = false; 
                    isMirror = false; 
                    imagePixelMap = getPixelMapFromResource(ResourceTable.Media_shanghai); 
                    image.setPixelMap(imagePixelMap); 
                    break; 
                case ResourceTable.Id_crop_image: 
                    // 剪裁图片 
                    whirlCount = 0; 
                    isCorp = !isCorp; 
                    isScale = false; 
                    isMirror = false; 
                    imagePixelMap = getPixelMapFromResource(ResourceTable.Media_shanghai); 
                    image.setPixelMap(imagePixelMap); 
                    break; 
                case ResourceTable.Id_scale_image: 
                    // 缩放图片 
                    whirlCount = 0; 
                    isCorp = false; 
                    isScale = !isScale; 
                    isMirror = false; 
                    imagePixelMap = getPixelMapFromResource(ResourceTable.Media_shanghai); 
                    image.setPixelMap(imagePixelMap); 
                    break; 
                case ResourceTable.Id_mirror_image: 
                    // 镜像图片 
                    whirlCount = 0; 
                    isCorp = false; 
                    isScale = false; 
                    isMirror = true; 
                    imagePixelMap = getPixelMapFromResource(ResourceTable.Media_shanghai); 
                    mirrorImage(imagePixelMap); 
                    image.setPixelMap(imagePixelMap); 
                    break; 
                default: 
                    break; 
            } 
        } 
    } 
 
    private void mirrorImage(PixelMap pixelMap) { 
        scaleX = -scaleX; 
        image.addDrawTask( 
                new Component.DrawTask() { 
                    @Override 
                    public void onDraw(Component component, Canvas canvas) { 
                        if (isMirror) { 
                            isMirror = false; 
                            PixelMapHolder pmh = new PixelMapHolder(pixelMap); 
                            canvas.scale( 
                                    scaleX, 
                                    1.0f, 
                                    (float) pixelMap.getImageInfo().size.width / 2, 
                                    (float) pixelMap.getImageInfo().size.height / 2); 
                            canvas.drawPixelMapHolder( 
                                    pmh, 
                                    0, 
                                    0, 
                                    new Paint()); 
                        } 
                    } 
                }); 
    } 
 
    /** 
     * 通过图片ID返回PixelMap 
     * 
     * @param resourceId 图片的资源ID 
     * @return 图片的PixelMap 
     */ 
    private PixelMap getPixelMapFromResource(int resourceId) { 
        InputStream inputStream = null; 
        try { 
            // 创建图像数据源ImageSource对象 
            inputStream = getContext().getResourceManager().getResource(resourceId); 
            ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); 
            srcOpts.formatHint = "image/jpg"; 
            ImageSource imageSource = ImageSource.create(inputStream, srcOpts); 
 
            // 设置图片参数 
            ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions(); 
            // 旋转 
            decodingOptions.rotateDegrees = 90 * whirlCount; 
            // 缩放 
            decodingOptions.desiredSize = new Size(isScale ? 512 : 0, isScale ? 384 : 0); 
            // 剪裁 
            decodingOptions.desiredRegion = new Rect(0, 0, isCorp ? 1024 : 0, isCorp ? 400 : 0); 
            decodingOptions.desiredPixelFormat = PixelFormat.ARGB_8888; 
            return imageSource.createPixelmap(decodingOptions); 
        } catch (IOException e) { 
            HiLog.info(LABEL_LOG, "IOException"); 
        } catch (NotExistException e) { 
            HiLog.info(LABEL_LOG, "NotExistException"); 
        } finally { 
            if (inputStream != null) { 
                try { 
                    inputStream.close(); 
                } catch (IOException e) { 
                    HiLog.info(LABEL_LOG, "inputStream IOException"); 
                } 
            } 
        } 
        return null; 
    } 
 
    @Override 
    public void onActive() { 
        super.onActive(); 
    } 
 
    @Override 
    public void onForeground(Intent intent) { 
        super.onForeground(intent); 
    } 
} 

<?xml version="1.0" encoding="utf-8"?> 
<DirectionalLayout 
    xmlns:ohos="http://schemas.huawei.com/res/ohos" 
    ohos:height="match_parent" 
    ohos:width="match_parent" 
    ohos:orientation="vertical"> 
 
    <Text 
        ohos:height="match_content" 
        ohos:width="match_content" 
        ohos:layout_alignment="horizontal_center" 
        ohos:text="HarmonyOS图像开发" 
        ohos:text_size="80" 
        ohos:top_margin="40vp" 
        /> 
 
    <DirectionalLayout 
        xmlns:ohos="http://schemas.huawei.com/res/ohos" 
        ohos:height="match_content" 
        ohos:width="match_content" 
        ohos:layout_alignment="horizontal_center" 
        ohos:orientation="horizontal" 
        ohos:top_margin="20vp"> 
 
        <Button 
            ohos:id="$+id:whirl_image" 
            ohos:height="match_content" 
            ohos:width="match_content" 
            ohos:background_element="$graphic:background_button" 
            ohos:padding="12vp" 
            ohos:right_margin="5vp" 
            ohos:text="旋转" 
            ohos:text_size="20vp" 
            ohos:top_margin="10vp"> 
        </Button> 
 
        <Button 
            ohos:id="$+id:crop_image" 
            ohos:height="match_content" 
            ohos:width="match_content" 
            ohos:background_element="$graphic:background_button" 
            ohos:left_margin="5vp" 
            ohos:padding="12vp" 
            ohos:text="剪裁" 
            ohos:text_size="20vp" 
            ohos:top_margin="10vp"> 
        </Button> 
 
        <Button 
            ohos:id="$+id:scale_image" 
            ohos:height="match_content" 
            ohos:width="match_content" 
            ohos:background_element="$graphic:background_button" 
            ohos:left_margin="5vp" 
            ohos:padding="12vp" 
            ohos:text="缩放" 
            ohos:text_size="20vp" 
            ohos:top_margin="10vp"> 
        </Button> 
 
        <Button 
            ohos:id="$+id:mirror_image" 
            ohos:height="match_content" 
            ohos:width="match_content" 
            ohos:background_element="$graphic:background_button" 
            ohos:left_margin="5vp" 
            ohos:padding="12vp" 
            ohos:text="镜像" 
            ohos:text_size="20vp" 
            ohos:top_margin="10vp"/> 
    </DirectionalLayout> 
 
    <Image 
        ohos:id="$+id:image" 
        ohos:height="match_content" 
        ohos:width="match_content" 
        ohos:image_src="$media:shanghai.jpg" 
        ohos:layout_alignment="horizontal_center" 
        ohos:top_margin="20vp"> 
    </Image> 
 
</DirectionalLayout>

此外您还需在resource/base/graphic目录下添加background_button.xml

<?xml version="1.0" encoding="utf-8"?> 
<shape xmlns:ohos="http://schemas.huawei.com/res/ohos" 
       ohos:shape="rectangle"> 
    <corners 
        ohos:radius="40"/> 
    <solid 
        ohos:color="#e9e9e9"/> 
</shape>

在这里插入图片描述

【挑战主题】3、AI文字识别

  1. 介绍
    AI的通用文字识别可以对文档翻拍、街景翻拍等图片来源的文字检测和识别,可以集成在其他应用中,提供文字检测、识别的功能,并根据识别结果提供翻译、搜索等相关服务。该功能在一定程度上支持文本倾斜、拍摄角度倾斜、复杂光照条件以及复杂文本背景等场景的文字识别。通用文字识别详细介绍可参考AI-通用文字识别,分词详细介绍可参考AI-分词。

分词文本限制在500字以内,编码格式必须为utf-8。

分词目前只支持中文语境。
支持处理的图片格式包括JPEG、JPG、PNG、GIF、BMP。
目前支持的语言有:中文、英文、日语、韩语、俄语、意大利语、西班牙语、葡萄牙语、德语,以及法语(将来会增加更多语种),但不支持手写字体识别。

  1. 代码结构解读
    基于AI的通用文字识别示例教程主要内容包括:图片列表展示、输入文本、分词、通用文字识别、结果展示等功能,可在7 完整示例代码中查看工程代码。DevEco Studio工程代码结构如下:
    provider:PictureProvider图片适配类,获取所有图片,并将图片放到图片列表中。
    slice:MainAbilitySlice本示例教程主页面。
    util:工具类
    LogUtil是日志打印类,对HiLog日志进行了封装。
    WordRecognition是通用文字识别类,对图片中的文字进行识别并保存。
    WordSegment是分词类,对输入文本进行分词。
    MainAbility:主程序入口,DevEco Studio生成,未添加逻辑,不需变更。
    MyApplication:DevEco Studio生成,不需变更。
    resources:存放工程使用到的资源文件
    resources\base\element中存放DevEco studio自动生成的配置文件string.json,不用变更。
    resources\base\graphic中存放页面样式文件:
    background_ability_page.xml用于设置界面背景颜色。
    background_ability_main.xml用于设置界面布局样式。
    button_element.xml用于设置按钮样式。
    resources\base\layout中布局文件:
    ability_main.xml用于展示图片和输入文本。
    item_image_layout.xml用于设置图片滑动区域图片。
    resources\base\media下存放图片资源(本教程使用了8张.jpg图片,开发者自行准备;icon.png由DevEco Studio生成不需变更)。
    config.json:配置文件。

完整示例代码
编写布局与样式
1.base/graphic/background_ability_main.xml

<?xml version="1.0" encoding="UTF-8" ?>




2.base/graphic/background_ability_page.xml

<?xml version="1.0" encoding="UTF-8" ?>




3.base/graphic/button_element.xml

<?xml version="1.0" encoding="utf-8"?>





4.base/layout/ability_main.xml

<?xml version="1.0" encoding="utf-8"?>

<Text 
    ohos:id="$+id:text_helloworld" 
    ohos:height="match_content" 
    ohos:width="match_content" 
    ohos:background_element="$graphic:background_ability_main" 
    ohos:layout_alignment="horizontal_center" 
    ohos:text="关键词搜索图片" 
    ohos:text_size="30fp" 
    ohos:top_margin="5vp" 
    /> 

<Text 
    ohos:id="$+id:picture_list" 
    ohos:height="match_content" 
    ohos:width="match_content" 
    ohos:background_element="$graphic:background_ability_main" 
    ohos:layout_alignment="horizontal_center" 
    ohos:text="图片列表" 
    ohos:text_size="20fp" 
    ohos:top_margin="15vp" 
    /> 

<ListContainer 
    ohos:id="$+id:picture_list_show" 
    ohos:height="200vp" 
    ohos:width="match_parent" 
    ohos:orientation="horizontal" 
    ohos:left_margin="5vp" 
    ohos:right_margin="5vp" 
    /> 

<Text 
    ohos:id="$+id:word_seg_title" 
    ohos:height="match_content" 
    ohos:width="match_content" 
    ohos:background_element="$graphic:background_ability_main" 
    ohos:left_margin="5vp" 
    ohos:text="请输入关键词:" 
    ohos:text_size="25fp" 
    ohos:top_margin="10vp" 
    /> 

<TextField 
    ohos:id="$+id:word_seg_text" 
    ohos:height="match_content" 
    ohos:width="match_parent" 
    ohos:background_element="$graphic:background_ability_main" 
    ohos:hint="Enter a statement." 
    ohos:left_padding="5vp" 
    ohos:right_padding="5vp" 
    ohos:text_alignment="vertical_center" 
    ohos:text_size="20fp" 
    ohos:top_margin="5vp"/> 

<Button 
    ohos:id="$+id:button_search" 
    ohos:width="match_content" 
    ohos:height="match_content" 
    ohos:text_size="20fp" 
    ohos:text="开始通用文字识别" 
    ohos:layout_alignment="horizontal_center" 
    ohos:top_margin="10vp" 
    ohos:top_padding="1vp" 
    ohos:bottom_padding="1vp" 
    ohos:right_padding="20vp" 
    ohos:left_padding="20vp" 
    ohos:text_color="white" 
    ohos:background_element="$graphic:button_element" 
    ohos:center_in_parent="true" 
    ohos:align_parent_bottom="true" 
    ohos:bottom_margin="5vp"/> 

<Text 
    ohos:id="$+id:picture_list_result" 
    ohos:height="match_content" 
    ohos:width="match_content" 
    ohos:background_element="$graphic:background_ability_main" 
    ohos:layout_alignment="horizontal_center" 
    ohos:text="搜索结果" 
    ohos:text_size="20fp" 
    ohos:top_margin="5vp" 
    /> 

<ListContainer 
    ohos:id="$+id:picture_list_match" 
    ohos:height="200vp" 
    ohos:width="match_parent" 
    ohos:orientation="horizontal" 
    ohos:left_margin="5vp" 
    ohos:right_margin="5vp" 
    /> 
5.base/layout/item_image_layout.xml <?xml version="1.0" encoding="utf-8"?>

<Image 
    ohos:id="$+id:select_picture_list" 
    ohos:height="200vp" 
    ohos:width="200vp" 
    ohos:layout_alignment="horizontal_center" 
    ohos:top_margin="1vp" 
    ohos:scale_mode="stretch" 
    /> 
功能逻辑代码 com/huawei/searchimagebykeywords/provider/PictureProvider import com.huawei.searchimagebykeywords.ResourceTable;

import ohos.agp.components.BaseItemProvider;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.Image;
import ohos.agp.components.LayoutScatter;
import ohos.app.Context;

import java.util.Optional;

public class PictureProvider extends BaseItemProvider {
private int[] pictureLists;
private Context context;

/** 
 *  picture provider 
 * 
 * @param pictureLists pictureLists 
 * @param context context 
 */ 
public PictureProvider(int[] pictureLists, Context context) { 
    this.pictureLists = pictureLists; 
    this.context = context; 
} 

@Override 
public int getCount() { 
    return pictureLists == null ? 0 : pictureLists.length; 
} 

@Override 
public Object getItem(int position) { 
    return Optional.of(this.pictureLists[position]); 
} 

@Override 
public long getItemId(int position) { 
    return position; 
} 

@Override 
public Component getComponent(int var1, Component var2, ComponentContainer var3) { 
    ViewHolder viewHolder = null; 
    Component component = var2; 
    if (component == null) { 
        component = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_item_image_layout, 
                null, false); 
        viewHolder = new ViewHolder(); 
        Component componentImage = component.findComponentById(ResourceTable.Id_select_picture_list); 
        if (componentImage instanceof Image) { 
            viewHolder.image = (Image) componentImage; 
        } 
        component.setTag(viewHolder); 
    } else { 
        if (component.getTag() instanceof ViewHolder) { 
            viewHolder = (ViewHolder) component.getTag(); 
        } 
    } 
    if (viewHolder != null) { 
        viewHolder.image.setPixelMap(pictureLists[var1]); 
    } 
    return component; 
} 

private static class ViewHolder { 
    Image image; 
} 

}
com/huawei/searchimagebykeywords/slice/MainAbilitySlice
import com.huawei.searchimagebykeywords.ResourceTable;
import com.huawei.searchimagebykeywords.provider.PictureProvider;
import com.huawei.searchimagebykeywords.util.WordRecognition;
import com.huawei.searchimagebykeywords.util.WordSegment;

import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.ListContainer;
import ohos.agp.components.TextField;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class MainAbilitySlice extends AbilitySlice {
private static final int LIST_CONTAINER_ID_SHOW = ResourceTable.Id_picture_list_show;
private static final int LIST_CONTAINER_ID_MATCH = ResourceTable.Id_picture_list_match;
private static final int NEG_ONE = -1;
private static final int ZERO = 0;
private static final int ONE = 1;
private static final int TWO = 2;
private Context slice;
private EventRunner runner;
private MyEventHandle myEventHandle;
private int[] pictureLists = new int[]{ResourceTable.Media_1, ResourceTable.Media_2,
ResourceTable.Media_3, ResourceTable.Media_4, ResourceTable.Media_5,
ResourceTable.Media_6, ResourceTable.Media_7, ResourceTable.Media_8};
private Component selectComponent;
private int selectPosition;
private Button button;
private TextField textField;
private Map<Integer, String> imageInfos;
private int[] matchPictures;

@Override 
public void onStart(Intent intent) { 
    super.onStart(intent); 
    super.setUIContent(ResourceTable.Layout_ability_main); 

    slice = MainAbilitySlice.this; 

    // 展示图片列表 
    setSelectPicture(pictureLists, LIST_CONTAINER_ID_SHOW); 

    // 所有图片通用文字识别 
    wordRecognition(); 

    // 设置需要分词的语句 
    Component componentText = findComponentById(ResourceTable.Id_word_seg_text); 
    if (componentText instanceof TextField) { 
        textField = (TextField) componentText; 
    } 

    // 点击按钮进行文字识别 
    Component componentSearch = findComponentById(ResourceTable.Id_button_search); 
    if (componentSearch instanceof Button) { 
        button = (Button) componentSearch; 
        button.setClickedListener(listener -> wordSegment()); 
    } 
} 

@Override 
public void onActive() { 
    super.onActive(); 
} 

@Override 
public void onForeground(Intent intent) { 
    super.onForeground(intent); 
} 

// 设置图片选择区域 
private void setSelectPicture(int[] pictures, int id) { 
    // 获取图片 
    PictureProvider newsTypeAdapter = new PictureProvider(pictures, this); 

    Component componentById = findComponentById(id); 
    if (componentById instanceof ListContainer) { 
        ListContainer listContainer = (ListContainer) componentById; 
        listContainer.setItemProvider(newsTypeAdapter); 
    } 
} 

// 通用文字识别 
private void wordRecognition() { 
    initHandler(); 
    WordRecognition wordRecognition = new WordRecognition(); 
    wordRecognition.setParams(slice, pictureLists, myEventHandle); 
    wordRecognition.sendResult(null); 
} 

// 分词 
private void wordSegment() { 
    // 组装关键词,作为分词对象 
    String requestData = "{\"text\":" + textField.getText() + ",\"type\":0}"; 
    initHandler(); 
    new WordSegment().wordSegment(slice, requestData, myEventHandle); 
} 

// 匹配图片 
private void matchImage(List<String> list) { 
    Set<Integer> matchSets = new HashSet<>(); 
    for (String str: list) { 
        for (Integer key : imageInfos.keySet()) { 
            if (imageInfos.get(key).indexOf(str) != NEG_ONE) { 
                matchSets.add(key); 
            } 
        } 
    } 
    // 获得匹配的图片 
    matchPictures = new int[matchSets.size()]; 
    int i = 0; 
    for (int match: matchSets) { 
        matchPictures[i] = match; 
        i++; 
    } 
    // 展示图片 
    setSelectPicture(matchPictures, LIST_CONTAINER_ID_MATCH); 
} 

private void initHandler() { 
    runner = EventRunner.getMainEventRunner(); 
    if (runner == null) { 
        return; 
    } 
    myEventHandle = new MyEventHandle(runner); 
} 

public class MyEventHandle extends EventHandler { 
    MyEventHandle(EventRunner runner) throws IllegalArgumentException { 
        super(runner); 
    } 

    @Override 
    protected void processEvent(InnerEvent event) { 
        super.processEvent(event); 
        int eventId = event.eventId; 
        if (eventId == ONE) { 
            // 通用文字识别 
            if (event.object instanceof Map) { 
                imageInfos = (Map) event.object; 
            } 
        } 
        if (eventId == TWO) { 
            // 分词 
            if (event.object instanceof List) { 
                List<String> lists = (List) event.object; 
                if ((lists.size() > ZERO) && (!"no keywords".equals(lists.get(ZERO)))) { 
                    // 根据输入关键词 匹配图片 
                    matchImage(lists); 
                } 
            } 
        } 
    } 
} 

}
com/huawei/searchimagebykeywords/util/LogUtil
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;

public class LogUtil {
private static final String TAG_LOG = “LogUtil”;

private static final HiLogLabel LABEL_LOG = new HiLogLabel(0, 0, LogUtil.TAG_LOG); 

private static final String LOG_FORMAT = "%{public}s: %{public}s"; 

private LogUtil() { 
} 

public static void info(String tag, String msg) { 
    HiLog.info(LABEL_LOG, LOG_FORMAT, tag, msg); 
} 

public static void error(String tag, String msg) { 
    HiLog.info(LABEL_LOG, LOG_FORMAT, tag, msg); 
} 

}
com/huawei/searchimagebykeywords/util/WordRecognition
import com.huawei.searchimagebykeywords.slice.MainAbilitySlice;

import ohos.ai.cv.common.ConnectionCallback;
import ohos.ai.cv.common.VisionCallback;
import ohos.ai.cv.common.VisionConfiguration;
import ohos.ai.cv.common.VisionImage;
import ohos.ai.cv.common.VisionManager;
import ohos.ai.cv.text.ITextDetector;
import ohos.ai.cv.text.Text;
import ohos.ai.cv.text.TextConfiguration;
import ohos.ai.cv.text.TextDetectType;
import ohos.app.Context;
import ohos.eventhandler.InnerEvent;
import ohos.global.resource.NotExistException;
import ohos.global.resource.Resource;
import ohos.global.resource.ResourceManager;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;
import ohos.media.image.common.PixelFormat;
import ohos.media.image.common.Rect;
import ohos.media.image.common.Size;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class WordRecognition {
private static final boolean IS_ASYNC = false;
private static final int IS_ASYNC_CODE = 700;
private Context slice;
private ITextDetector textDetector;
private PixelMap pixelMap;
private MainAbilitySlice.MyEventHandle handle;
private int[] pictureLists;
private int mediaId;
private Map maps = new HashMap<>();
private int index;
private int result;

public void setParams(Context context, int[] pictureIds, MainAbilitySlice.MyEventHandle myEventHandle) { 
    slice = context; 
    pictureLists = pictureIds; 
    handle = myEventHandle; 
} 

public void wordRecognition(Context context, int resId, MainAbilitySlice.MyEventHandle myEventHandle) { 
    mediaId = resId; 
    // 实例化ITextDetector接口 
    textDetector = VisionManager.getTextDetector(context); 

    // 实例化VisionImage对象image,并传入待检测图片pixelMap 
    pixelMap = getPixelMap(resId); 
    VisionImage image = VisionImage.fromPixelMap(pixelMap); 

    // 定义VisionCallback<Text>回调,异步模式下用到 
    VisionCallback<Text> visionCallback = getVisionCallback(); 

    // 定义ConnectionCallback回调,实现连接能力引擎成功与否后的操作 
    ConnectionCallback connectionCallback = getConnectionCallback(image, visionCallback); 

    // 建立与能力引擎的连接 
    VisionManager.init(context, connectionCallback); 
} 

private VisionCallback getVisionCallback() { 
    return new VisionCallback<Text>() { 
        @Override 
        public void onResult(Text text) { 
            sendResult(text.getValue()); 
        } 

        @Override 
        public void onError(int i) { 
        } 

        @Override 
        public void onProcessing(float v) { 
        } 
    }; 
} 

private ConnectionCallback getConnectionCallback(VisionImage image, VisionCallback<Text> visionCallback) { 
    return new ConnectionCallback() { 
        @Override 
        public void onServiceConnect() { 
            // 实例化Text对象text 
            Text text = new Text(); 

            // 通过TextConfiguration配置textDetector()方法的运行参数 
            TextConfiguration.Builder builder = new TextConfiguration.Builder(); 
            builder.setProcessMode(VisionConfiguration.MODE_IN); 
            builder.setDetectType(TextDetectType.TYPE_TEXT_DETECT_FOCUS_SHOOT); 
            builder.setLanguage(TextConfiguration.AUTO); 
            TextConfiguration config = builder.build(); 
            textDetector.setVisionConfiguration(config); 
            // 调用ITextDetector的detect()方法 
            if (!IS_ASYNC) { 
                int result2 = textDetector.detect(image, text, null); // 同步 
                sendResult(text.getValue()); 
            } else { 
                int result2 = textDetector.detect(image, null, visionCallback); // 异步 
            } 
        } 

        @Override 
        public void onServiceDisconnect() { 
            // 释放 
            if ((!IS_ASYNC && (result == 0)) || (IS_ASYNC && (result == IS_ASYNC_CODE))) { 
              textDetector.release(); 
            } 
            if (pixelMap != null) { 
                pixelMap.release(); 
                pixelMap = null; 
            } 
            VisionManager.destroy(); 
        } 
    }; 
} 

public void sendResult(String value) { 
    if (textDetector != null) { 
        textDetector.release(); 
    } 
    if (pixelMap != null) { 
        pixelMap.release(); 
        pixelMap = null; 
        VisionManager.destroy(); 
    } 
    if (value != null) { 
        maps.put(mediaId, value); 
    } 
    if ((maps != null) && (maps.size() == pictureLists.length)) { 
        InnerEvent event = InnerEvent.get(1, 0, maps); 
        handle.sendEvent(event); 
    } else { 
        wordRecognition(slice, pictureLists[index], handle); 
        index++; 
    } 
} 

// 获取图片 
private PixelMap getPixelMap(int resId) { 
    ResourceManager manager = slice.getResourceManager(); 

    byte[] datas = new byte[0]; 
    try { 
        Resource resource = manager.getResource(resId); 
        datas = readBytes(resource); 
        resource.close(); 
    } catch (IOException | NotExistException e) { 
        LogUtil.error("get pixelmap failed, read resource bytes failed, ", e.getLocalizedMessage()); 
    } 

    ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions(); 
    srcOpts.formatHint = "image/jpg"; 
    ImageSource imageSource; 
    imageSource = ImageSource.create(datas, srcOpts); 
    ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); 
    decodingOpts.desiredSize = new Size(0, 0); 
    decodingOpts.desiredRegion = new Rect(0, 0, 0, 0); 
    decodingOpts.desiredPixelFormat = PixelFormat.ARGB_8888; 
    pixelMap = imageSource.createPixelmap(decodingOpts); 
    return pixelMap; 
} 

private static byte[] readBytes(Resource resource) { 
    final int bufferSize = 1024; 
    final int ioEnd = -1; 

    ByteArrayOutputStream output = new ByteArrayOutputStream(); 
    byte[] buffers = new byte[bufferSize]; 
    byte[] results = new byte[0]; 
    while (true) { 
        try { 
            int readLen = resource.read(buffers, 0, bufferSize); 
            if (readLen == ioEnd) { 
                results = output.toByteArray(); 
                break; 
            } 
            output.write(buffers, 0, readLen); 
        } catch (IOException e) { 
            LogUtil.error("OrcAbilitySlice.getPixelMap", "read resource failed "); 
            break; 
        } finally { 
            try { 
                output.close(); 
            } catch (IOException e) { 
                LogUtil.error("OrcAbilitySlice.getPixelMap", "close output failed"); 
            } 
        } 
    } 
    return results; 
} 

}
com/huawei/searchimagebykeywords/util/WordSegment
import com.huawei.searchimagebykeywords.slice.MainAbilitySlice;

import ohos.ai.nlu.NluClient;
import ohos.ai.nlu.NluRequestType;
import ohos.ai.nlu.OnResultListener;
import ohos.ai.nlu.ResponseResult;
import ohos.app.Context;
import ohos.eventhandler.InnerEvent;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class WordSegment {
private static final boolean IS_ASYNC = true;
private static final String WORDS = “words”;
private static final int ZERO = 0;
private static final int TWO = 2;
private static final int STEP = 8;
private Context slice;
private MainAbilitySlice.MyEventHandle handle;

public void wordSegment(Context context, String requestData, MainAbilitySlice.MyEventHandle myEventHandle) { 
    slice = context; 
    handle = myEventHandle; 

    // 使用NluClient静态类进行初始化,通过异步方式获取服务的连接。 
    NluClient.getInstance().init(context, new OnResultListener<Integer>() { 
        @Override 
        public void onResult(Integer resultCode) { 
            if (!IS_ASYNC) { 
                // 同步 
                ResponseResult responseResult = NluClient.getInstance().getWordSegment(requestData, 
                        NluRequestType.REQUEST_TYPE_LOCAL); 
                sendResult(responseResult.getResponseResult()); 
                release(); 
            } else { 
                // 异步 
                wordSegmentAsync(requestData); 
            } 
        } 
    }, true); 
} 

private void wordSegmentAsync(String requestData) { 
    ResponseResult responseResult = NluClient.getInstance().getWordSegment(requestData, 
            NluRequestType.REQUEST_TYPE_LOCAL, new OnResultListener<ResponseResult>() { 
                @Override 
                public void onResult(ResponseResult asyncResult) { 
                    sendResult(asyncResult.getResponseResult()); 
                    release(); 
                } 
            }); 
} 

private void sendResult(String result) { 
    List lists = null; // 分词识别结果 
    // 将result中分词结果转换成list 
    if (result.contains("\"message\":\"success\"")) { 
        String words = result.substring(result.indexOf(WORDS) + STEP, 
                result.lastIndexOf("]")).replaceAll("\"", ""); 
        if ((words == null) || ("".equals(words))) { 
            lists = new ArrayList(1); 
            lists.add("no keywords"); // 未识别到分词结果,返回"no keywords" 
        } else { 
            lists = Arrays.asList(words.split(",")); 
        } 
    } 

    InnerEvent event = InnerEvent.get(TWO, ZERO, lists); 
    handle.sendEvent(event); 
} 

private void release() { 
    NluClient.getInstance().destroy(slice); 
} 

}
com/huawei/searchimagebykeywords/MainAbility
import com.huawei.searchimagebykeywords.slice.MainAbilitySlice;

import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
public class MainAbility extends Ability {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setMainRoute(MainAbilitySlice.class.getName());
}
}
com/huawei/searchimagebykeywords/MyApplication
import ohos.aafwk.ability.AbilityPackage;

public class MyApplication extends AbilityPackage {
@Override
public void onInitialize() {
super.onInitialize();
}
}

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值