鸿蒙应用:多设备闹钟开发教程(2)

主列表页面

鸿蒙应用:多设备闹钟帮你把多个房间的娃同时叫醒!

项目地址:https://github.com/Madixin/CrazyClock
文章介绍及教程:https://blog.csdn.net/sd2131512/article/details/117571607

本节我们将开发闹钟的主列表页面。这个页面包含底部TabList的里闹钟设置两个tab,点击闹钟时显示闹钟列表,点击设置时显示关于,设备等信息。

 

1.开发主页面的xml资源文件

1.1 在string.json中添加资源文件

{
  "string": [
    {
      "name": "app_name",
      "value": "多设备闹钟"
    },
    {
      "name": "clock",
      "value": "闹钟"
    },
    {
      "name": "device",
      "value": "设备"
    },
    {
      "name": "about",
      "value": "关于"
    },
    {
      "name": "setting",
      "value": "设置"
    }
  ]
}

2.在resources/base/graphic下添加图片资源文件闹钟设置展开的图标。这3个图标可从iconfont中下载png格式,然后使用IDE的Svg to xml功能引入。  

3.在resources/base/graphic下添加layout资源文件list_divider.xml,用于列表的分割线

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

4.在resources/base/layoutx下添加layout资源文件item_clock.xml,用于自定义那种列表,里面包含了两个Text,一个是Switch控件和一个分隔线Component。

item_clock.xml

<?xml version="1.0" encoding="utf-8"?>
<DependentLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_content"
    ohos:width="match_parent"
    ohos:orientation="vertical">
​
    <Text
        ohos:id="$+id:item_text_time"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:layout_alignment="center"
        ohos:left_margin="20vp"
        ohos:padding="4vp"
        ohos:text="Time"
        ohos:text_size="20fp"/>
​
    <Text
        ohos:id="$+id:item_text_name"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:below="$id:item_text_time"
        ohos:layout_alignment="center"
        ohos:left_margin="20vp"
        ohos:padding="4vp"
        ohos:text="Name"
        ohos:text_size="20fp"/>
​
    <Switch
        ohos:id="$+id:item_switch_state"
        ohos:height="30vp"
        ohos:width="60vp"
        ohos:align_parent_right="true"
        ohos:right_margin="20vp"
        ohos:top_margin="20vp"
        ohos:text_state_off="OFF"
        ohos:text_state_on="ON"/>
​
    <Component
        ohos:height="1vp"
        ohos:width="match_parent"
        ohos:background_element="$graphic:list_divider"
        ohos:below="$id:item_text_name"/>
</DependentLayout>

5.在entry/src/main/config.json中修改界面主题风格,去掉窗口Title显示。

 "metaData": {
     "customizeData": [
      {
        "name": "hwc-theme",
        "value": "androidhwext:style/Theme.Emui.NoTitleBar"
      }
      ]
}

6.最后完成主列表界面的布局。其中通过控制两个DependentLayout的显示和隐藏,分别实现闹钟和设置两个tab页的切换。

<?xml version="1.0" encoding="utf-8"?>
<DependentLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:orientation="vertical">
​
    <DirectionalLayout
        ohos:id="$+id:layout_clock"
        ohos:height="match_parent"
        ohos:width="match_parent"
        ohos:orientation="vertical"
        ohos:above="$id:tab_bottom_list">
        <DependentLayout
            ohos:height="56vp"
            ohos:width="match_parent"
            ohos:padding="10vp"
            >
​
            <Text
                ohos:id="$+id:text_clockname"
                ohos:height="match_content"
                ohos:width="match_content"
                ohos:background_element="$graphic:background_ability_main"
                ohos:layout_alignment="horizontal_center"
                ohos:text="$string:app_name"
                ohos:text_size="24fp"
                ohos:align_parent_left="true"
                ohos:vertical_center="true"
                ohos:left_margin="20vp"
                />
​
            <Image
                ohos:id="$+id:image_add_clock"
                ohos:height="24vp"
                ohos:width="24vp"
                ohos:right_margin="20vp"
                ohos:foreground_element="$media:add"
                ohos:align_parent_right="true"
                ohos:vertical_center="true"/>
​
        </DependentLayout>
​
        <ListContainer
            ohos:id="$+id:list_clock_view"
            ohos:height="match_parent"
            ohos:width="match_parent"/>
​
    </DirectionalLayout>
​
    <DirectionalLayout
        ohos:id="$+id:layout_setting"
        ohos:height="match_parent"
        ohos:width="match_parent"
        ohos:orientation="vertical"
        ohos:above="$id:tab_bottom_list"
        ohos:visibility="hide">
​
        <DependentLayout
            ohos:height="56vp"
            ohos:width="match_parent"
            ohos:padding="10vp"
            >
            <Text
                ohos:height="match_content"
                ohos:width="match_content"
                ohos:background_element="$graphic:background_ability_main"
                ohos:layout_alignment="horizontal_center"
                ohos:text="$string:app_name"
                ohos:text_size="24fp"
                ohos:align_parent_left="true"
                ohos:vertical_center="true"
                ohos:left_margin="20vp"
                />
        </DependentLayout>
​
​
        <DependentLayout
            ohos:height="match_content"
            ohos:width="match_parent">
            <Text
                ohos:id="$+id:text_aboutLabel"
                ohos:height="match_content"
                ohos:width="match_content"
                ohos:text="$string:about"
                ohos:text_size="20fp"
                ohos:layout_alignment="center"
                ohos:top_margin="10vp"
                ohos:bottom_margin="10vp"
                ohos:left_margin="20vp"/>
​
            <Image
                ohos:id="$+id:icon_right_about"
                ohos:height="24vp"
                ohos:width="12vp"
                ohos:align_parent_right="true"
                ohos:right_margin="20vp"
                ohos:top_margin="10vp"
                ohos:image_src="$graphic:right_grey"/>
​
            <Component
                ohos:height="1vp"
                ohos:width="match_parent"
                ohos:background_element="$graphic:list_divider"
                ohos:below="$id:text_aboutLabel"/>
        </DependentLayout>
​
        <DependentLayout
            ohos:height="match_content"
            ohos:width="match_parent">
            <Text
                ohos:id="$+id:text_deviceLabel"
                ohos:height="match_content"
                ohos:width="match_content"
                ohos:text="$string:device"
                ohos:text_size="20fp"
                ohos:layout_alignment="center"
                ohos:top_margin="10vp"
                ohos:bottom_margin="10vp"
                ohos:left_margin="20vp"/>
​
            <Image
                ohos:id="$+id:icon_right_device"
                ohos:height="24vp"
                ohos:width="12vp"
                ohos:align_parent_right="true"
                ohos:right_margin="20vp"
                ohos:top_margin="10vp"
                ohos:image_src="$graphic:right_grey"/>
​
            <Component
                ohos:height="1vp"
                ohos:width="match_parent"
                ohos:background_element="$graphic:list_divider"
                ohos:below="$id:text_deviceLabel"/>
        </DependentLayout>
​
    </DirectionalLayout>
​
    <TabList
        ohos:id="$+id:tab_bottom_list"
        ohos:align_parent_bottom="true"
        ohos:top_margin="10vp"
        ohos:tab_margin="24vp"
        ohos:tab_length="140vp"
        ohos:text_size="20fp"
        ohos:height="56vp"
        ohos:width="match_parent"
        ohos:layout_alignment="center"
        ohos:orientation="horizontal"
        ohos:text_alignment="left|vertical_center"
​
        ohos:normal_text_color="#FF881515"
        ohos:selected_text_color="#FFEC0B0B"
        ohos:selected_tab_indicator_color="#FF1F0606"
        ohos:selected_tab_indicator_height="2vp"
        >
    </TabList>
</DependentLayout>

2.实现MainAbilitySlice里listContainer和TabList的数据

2.1 创建实体类Clock,这个类包含了闹钟对象的所有属性

Clock.java

package com.madixin.clock.setting.model;
public class Clock {
    private int id;//主键
​
    private String name;//名称
​
    private int hour;//小时
​
    private int minute;//分钟
​
    private int bell;//铃声
​
    private int duration;//持续时间
​
    private boolean isEnable;//是否开启
​
    public int getId() {
        return id;
    }
​
    public void setId(int id) {
        this.id = id;
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public int getHour() {
        return hour;
    }
​
    public void setHour(int hour) {
        this.hour = hour;
    }
​
    public int getMinute() {
        return minute;
    }
​
    public void setMinute(int minute) {
        this.minute = minute;
    }
​
    public int getBell() {
        return bell;
    }
​
    public void setBell(int bell) {
        this.bell = bell;
    }
​
    public int getDuration() {
        return duration;
    }
​
    public void setDuration(int duration) {
        this.duration = duration;
    }
​
    public boolean isEnable() {
        return isEnable;
    }
​
    public void setEnable(boolean enable) {
        isEnable = enable;
    }
}

2.2 创建ListViewClockItemProvider类继承BaseItemProvider,并实现其相关接口,它用于将clock对象转换成自定义列表项,其中内部类ViewHolder用于缓存自定义列表项的空间,避免每次都使用findComponentById查找控件。

ListViewClockItemProvider.java

package com.madixin.clock.setting.provider;
​
import com.madixin.clock.setting.ResourceTable;
import com.madixin.clock.setting.model.Clock;
import ohos.aafwk.ability.AbilitySlice;
import ohos.agp.components.*;
​
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;
​
public class ListViewClockItemProvider extends BaseItemProvider {
​
    private AbilitySlice slice;
​
    private List<Clock> dataList = new LinkedList<>();
​
    private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
​
    public ListViewClockItemProvider(AbilitySlice abilitySlice) {
        this.slice = abilitySlice;
    }
​
    @Override
    public int getCount() {
        return dataList.size();
    }
​
    @Override
    public Object getItem(int i) {
        return dataList.get(i);
    }
​
    @Override
    public long getItemId(int i) {
        return i;
    }
​
    public List<Clock> getDataList() {
        return dataList;
    }
​
    public void setDataList(List<Clock> dataList) {
        this.dataList = dataList;
    }
​
    @Override
    public Component getComponent(int position, Component component, ComponentContainer componentContainer) {
        final Component cpt;
        ViewHolder viewHolder;
​
        if (component == null) {
            cpt = LayoutScatter.getInstance(slice).parse(ResourceTable.Layout_item_clock, null, false);
            viewHolder = new ViewHolder();
            viewHolder.textName = (Text) cpt.findComponentById(ResourceTable.Id_item_text_name);
            viewHolder.textTime = (Text) cpt.findComponentById(ResourceTable.Id_item_text_time);
            viewHolder.switchState = (Switch) cpt.findComponentById(ResourceTable.Id_item_switch_state);
            cpt.setTag(viewHolder);
        } else {
            cpt = component;
            viewHolder = (ViewHolder) component.getTag();
        }
​
        Clock clock = dataList.get(position);
        viewHolder.textName.setText(clock.getName());
​
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, clock.getHour());
        calendar.set(Calendar.MINUTE, clock.getMinute());
        viewHolder.textTime.setText(sdf.format(calendar.getTime()));
        viewHolder.switchState.setChecked(clock.isEnable());
​
        return cpt;
    }
​
    class ViewHolder {
        Text textName;
        Text textTime;
        Switch switchState;
    }
}

2.3 在MainAbilitySlice的onstart方法里分别实现initTablist和initListContainer方法,动态添加listcontainer和tablist的数据。其中使用到了ClockManager的添加和查询方法,可先创建ClockManager类,并实现空的返回。

package com.madixin.clock.setting.slice;
​
import com.madixin.clock.common.util.LogUtil;
import com.madixin.clock.setting.ResourceTable;
import com.madixin.clock.setting.manager.ClockManager;
import com.madixin.clock.setting.model.Clock;
import com.madixin.clock.setting.provider.ListViewClockItemProvider;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Component;
import ohos.agp.components.Image;
import ohos.agp.components.ListContainer;
import ohos.agp.components.TabList;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.ElementScatter;
​
import java.util.LinkedList;
import java.util.List;
​
public class MainAbilitySlice extends AbilitySlice {
​
    private static final String TAG = MainAbilitySlice.class.getName();
​
    private Image imageAddClock;
​
    private ListContainer listClockContainer;
​
    private ListViewClockItemProvider listViewClockItemProvider;
​
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_main);
​
        initTablist();
        initListContainer();
    }
​
    private void initListContainer() {
        listClockContainer = (ListContainer) this.findComponentById(ResourceTable.Id_list_clock_view);
        listViewClockItemProvider = new ListViewClockItemProvider(this);
​
        List<Clock> clockList = getAllClocks();
        if (clockList.size() == 0) {
            Clock clock1 = new Clock();
            clock1.setName("zzz闹钟");
            clock1.setBell(0);
            clock1.setHour(6);
            clock1.setDuration(10);
            clock1.setMinute(66);
            clock1.setEnable(true);
​
            ClockManager.getInstance(this.getApplicationContext()).createNewClock(clock1);
​
            Clock clock2 = new Clock();
            clock2.setName("madixin闹钟");
            clock2.setBell(0);
            clock2.setHour(8);
            clock2.setDuration(10);
            ClockManager.getInstance(this.getApplicationContext()).createNewClock(clock2);
​
            clockList.add(clock1);
            clockList.add(clock2);
        }
​
        listViewClockItemProvider.setDataList(clockList);
        listClockContainer.setItemProvider(listViewClockItemProvider);
        listClockContainer.setReboundEffect(true);
    }
​
    private List<Clock> getAllClocks() {
        return new LinkedList<>();
    }
​
    private void initTablist() {
        this.getApplicationContext();
        Element icon = ElementScatter.getInstance(this.getContext()).parse(ResourceTable.Graphic_clock);
​
        TabList tabList = (TabList) this.findComponentById(ResourceTable.Id_tab_bottom_list);
        TabList.Tab tab = tabList.new Tab(this.getContext());
        tab.setText(ResourceTable.String_clock);
        tab.setIconElement(icon);
        tab.setPadding(130, 0, 0, 0);
        tabList.addTab(tab);
​
        TabList.Tab tab2 = tabList.new Tab(this.getContext());
        tab2.setText(ResourceTable.String_setting);
​
        //tab2.setPadding(12, 0, 12, 0);
        Element icon2 = ElementScatter.getInstance(this.getContext()).parse(ResourceTable.Graphic_setting);
​
        tab2.setIconElement(icon2);
        tab2.setPadding(130, 0, 0, 0);
        tabList.addTab(tab2);
​
        tabList.selectTab(tab);
        tabList.setFixedMode(true);
​
        AbilitySlice curSlice = this;
​
        tabList.addTabSelectedListener(new TabList.TabSelectedListener() {
            Component clockComponent = curSlice.findComponentById(ResourceTable.Id_layout_clock);
            Component settingComponent = curSlice.findComponentById(ResourceTable.Id_layout_setting);
            @Override
            public void onSelected(TabList.Tab tab) {
                LogUtil.info(TAG, "onSelected: " + tab.getPosition());
                switch (tab.getPosition()) {
                    case 0:
                        clockComponent.setVisibility(Component.VISIBLE);
                        settingComponent.setVisibility(Component.HIDE);
                        break;
                    case 1:
                        clockComponent.setVisibility(Component.HIDE);
                        settingComponent.setVisibility(Component.VISIBLE);
                        break;
                }
            }
​
            @Override
            public void onUnselected(TabList.Tab tab) {
​
            }
​
            @Override
            public void onReselected(TabList.Tab tab) {
​
            }
        });
    }
​
    @Override
    public void onActive() {
        super.onActive();
    }
​
    @Override
    public void onForeground(Intent intent) {
        super.onForeground(intent);
    }
}

2.4 如果想后续方便的模拟数据以及预览界面,建议使用DevEco Studio的MockPreview功能:首先需要在gradle中引入依赖,然后添加MockMainAbilitySlice类继承PreviewerMock,并使用@PreviewerMockMethod去mock initTablist和getAllClocks两个方法,这样就能方便地使用mockpreview预览主列表界面了。

    implementation group:'com.huawei.deveco',name:"previewer-mock-core",version:'1.0.0.1'
package com.madixin.clock.setting.mock;

import com.huawei.asm.core.PreviewerMock;
import com.huawei.asm.core.annotation.PreviewerMockMethod;
import com.madixin.clock.setting.ResourceTable;
import com.madixin.clock.setting.model.Clock;
import com.madixin.clock.setting.slice.MainAbilitySlice;
import ohos.agp.components.Component;
import ohos.agp.components.TabList;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.ElementScatter;

import java.util.LinkedList;
import java.util.List;

public class MockMainAbilitySlice extends PreviewerMock {
    private static final String TAG = MockMainAbilitySlice.class.getName();

    @PreviewerMockMethod
    public void initTablist(MainAbilitySlice mainAbilitySlice) {
        Element icon = ElementScatter.getInstance(mainAbilitySlice.getContext()).parse(ResourceTable.Graphic_clock);

        TabList tabList = (TabList) mainAbilitySlice.findComponentById(ResourceTable.Id_tab_bottom_list);
        TabList.Tab tab = tabList.new Tab(mainAbilitySlice.getContext());
        tab.setText(ResourceTable.String_clock);
        tab.setIconElement(icon);
        tab.setPadding(130, 0, 0, 0);
        tabList.addTab(tab);

        TabList.Tab tab2 = tabList.new Tab(mainAbilitySlice.getContext());
        tab2.setText(ResourceTable.String_setting);

        Element icon2 = ElementScatter.getInstance(mainAbilitySlice.getContext()).parse(ResourceTable.Graphic_setting);

        tab2.setIconElement(icon2);
        tab2.setPadding(130, 0, 0, 0);
        tabList.addTab(tab2);
        tabList.setFixedMode(true);
        tabList.selectTab(tab);

        tabList.addTabSelectedListener(new TabList.TabSelectedListener() {
            @Override
            public void onSelected(TabList.Tab tab) {
                Component clockComponent = mainAbilitySlice.findComponentById(ResourceTable.Id_layout_clock);
                Component settingComponent = mainAbilitySlice.findComponentById(ResourceTable.Id_layout_setting);

                switch (tab.getPosition()) {
                    case 0:
                        clockComponent.setVisibility(Component.VISIBLE);
                        settingComponent.setVisibility(Component.HIDE);

                        break;
                    case 1:
                        clockComponent.setVisibility(Component.HIDE);
                        settingComponent.setVisibility(Component.VISIBLE);
                        break;
                }
            }

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

            }

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

            }
        });
    }

    @PreviewerMockMethod
    public List<Clock> getAllClocks(MainAbilitySlice mainAbilitySlice) {
        List<Clock> clockList = new LinkedList<>();
        Clock clock1 = new Clock();
        clock1.setName("早起闹钟");
        clock1.setHour(7);
        clock1.setMinute(55);
        clock1.setEnable(true);

        Clock clock2 = new Clock();
        clock2.setName("上班闹钟");
        clock2.setHour(8);
        clock2.setMinute(0);
        clock2.setEnable(false);

        Clock clock3 = new Clock();
        clock3.setName("下班闹钟");
        clock3.setHour(9);
        clock3.setMinute(7);
        //clock3.setTime("09:00");


        clockList.add(clock1);
        clockList.add(clock2);
        clockList.add(clock3);
        return clockList;
    }

    @PreviewerMockMethod
    public void createNewClock(MainAbilitySlice mainAbilitySlice) {

    }
}

3.小结

本节完成了主列表页面的开发,以及mockpreview的预览。

下一步我们将开发闹钟创建界面。

4.代码地址:

github,提交记录:66f74fdb058f58fb6d640f94017532f9174ac392

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值