HarmonyOS realizes WeChat app-like effects from scratch - basic interface construction

Recently, news related to the development of HarmonyOS has been very popular. It is rumored that Huawei mobile phones will no longer support native Android applications in the future, so the Harmony version corresponding to the development of original Android applications has also been put on the agenda by a series of major manufacturers. As a nominal mobile development engineer ((⊙o⊙)..., I write more about Python than Android recently), I have to learn it when others don't allow me. This learning plan is to implement a WeChat-like app effect. We plan to implement the conventional app effects so that if you need to write a Harmony application later, you can get started directly.

Since I have many years of development experience and development experience in multiple languages, I have written a lot about Javascript and TypeScript, so for < /span> series of articles. At the same time, the knowledge points that I think are more important designed in the article will be explained in the article. TypeScriptThe grammar part will not be explained too much. Students who want to learn it quickly can directly check my quick startTypeScript

Functional split

The above is just a simple splitting example. When we get a function, we must first split the page. After the function we want to implement is implemented through a sub-module, finally through the splicing of the sub-modules, we can get A complete feature.

Detailed implementation

The first lesson today is to implement the overall interface construction first. The final effect is as shown below.

When we click, we can switch the tab content interface above.

Harmony provides many ways to implement the bottom navigation bar. If used in real projects, you can directly use the methods provided by the system. The method I adopt here is to use the most basic code to implement it myself, so that I can also connect to some functions I want to learn. It is good to use it out of the box, but it is also easy for us to miss a lot of key knowledge.

Implement BottomNavigationItem

The bottom of the whole here is oneBottomNavigation, which is realized by a combination of four BottomNavigationItem. First define an entity class to store bottom navigation bar object information.

export class BottomNavigationEntity {
  /**
   * 底部导航tab标题
   */
  title: Resource;

  /**
   * 底部导航tab图片
   */
  image: Resource;

  /**
   * 底部导航tab图片,未选中
   */
  unCheckImage: Resource;

  /**
   * tab类型标志位
   */
  tag: number;

  constructor(tag: number, title: Resource, image: Resource, unCheckImage: Resource) {
    this.tag = tag;
    this.title = title;
    this.image = image;
    this.unCheckImage = unCheckImage;
  }
}

Next

The component is a combination of an icon + a text. The first reaction is that we should go to the Column component.

ColumnIn the component, the flex method is used to process the content of the component. alignItems(value: HorizontalAlign): ColumnAttribute; # 水平方向 justifyContent(value: FlexAlign): ColumnAttribute; # 垂直方向 After understanding this, let’s look at the specific BottomNavigationItem encapsulation code.

@Preview  # 方便单个view直接预览
@Component  # 标记是一个组件,可供其他组件引用
export default struct BottomNavigationItem {
  private navigationItem: BottomNavigationEntity;
  
  # 这里的Link是用于父组件和子组件进行通信	
  @Link currentIndex: number;

  build() {
    Column({ space: 5 }) {
    # 这里判断如果当前选中的item是当前的这个,则使用选中状态图片
      Image(this.currentIndex === this.navigationItem.tag ? this.navigationItem.image : this.navigationItem.unCheckImage)
        .width(24)
        .height(24)
      Text(this.navigationItem.title)
        .fontSize(14)
        .fontColor(this.currentIndex === this.navigationItem.tag ? Color.Green : 0x333333)
    }
  }
}

The code is very simple. For@LinkIf you are not clear about it now, it doesn’t matter. I will give a special explanation in the end.

Implement BottomNavigation

@Preview
@Component
export default struct BottomNavigation {
  @Link currentItemIndex: number;

  build() {
    Row({ space: 5 }) {
      //  这里通过对结合遍历,生成BottomNavigationItem进行填充BottomNavigation
      ForEach(navigationViewModel.getNavigationList(), (item: BottomNavigationEntity, index: number) => {
        # 对于这里的$currentItemIndex写法可以先将疑问留着,后续结合Link一并说明
        BottomNavigationItem({ navigationItem: item, currentIndex: $currentItemIndex })
          .onClick(() => {
          	#  点击后更新选中的item,以实现刷新界面的效果
            this.currentItemIndex = index
          })
      })
    }
    .width('100%')
    .height(65)
    .padding({
      top: 5,
      bottom: 5
    })
    .justifyContent(FlexAlign.SpaceAround)
    .backgroundColor(0xF3EEEA)
  }
}

Implement WechatMainFrame

The overall interface combination is composed using RelativeContainer, and BottomNavigation is fixed at the bottom of the screen, and the bottom of the content area is at BottomNavigation, align the top with the top of the screen so that it fills the area above BottomNavigation. In the content area, use Stack to display all content in a cascading manner. To switch to which display, use the visibility method to set the page display.

@Entry
@Component
struct WechatMainFrame {
  @State currentCheckIndex: number = 0;

  build() {
    RelativeContainer() {
      BottomNavigation({ currentItemIndex: $currentCheckIndex })
        .alignRules({
          bottom: { anchor: "__container__", align: VerticalAlign.Bottom },
          left: { anchor: "__container__", align: HorizontalAlign.Start }
        })
        .id("bottomNavigation")

      Stack() {
        HomeFragment().visibility(this.currentCheckIndex == 0 ? Visibility.Visible : Visibility.Hidden)
        ContactFragment().visibility(this.currentCheckIndex == 1 ? Visibility.Visible : Visibility.Hidden)
        DiscoverFragment().visibility(this.currentCheckIndex == 2 ? Visibility.Visible : Visibility.Hidden)
        MeFragment().visibility(this.currentCheckIndex == 3 ? Visibility.Visible : Visibility.Hidden)
      }
      .width('100%')
      .height('100%')
      .alignRules({
        left: { anchor: "__container__", align: HorizontalAlign.Start },
        right: { anchor: "__container__", align: HorizontalAlign.End },
        bottom: { anchor: "bottomNavigation", align: VerticalAlign.Top },
        top: { anchor: "__container__", align: VerticalAlign.Top }
      })
      .id("contentPanel")
    }
    .width('100%').height('100%')
  }
}

EntryAbility

export default class EntryAbility extends UIAbility {
  ...
  onWindowStageCreate(windowStage: window.WindowStage) {
    // Main window is created, set main page for this ability
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

    windowStage.loadContent('pages/WechatMainFrame', (err, data) => {
      if (err.code) {
        hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
        return;
      }
      hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
    });
  }
  ...

At this point, the frame structure of the entire page is completed.

Notes on @Link

For more detailed information, please see the official article.

For view updates, we can use @State to mark variables, but @State cannot be used across files. At this time, the implementation of @Link makes up for the shortcomings of @State. Use the words @Link. Variables decorated with @Link in the child component establish a two-way data binding with the corresponding data source in the parent component.

  • A variable decorated with @Link shares the same value as the data source in its parent component.
  • The @Link decorator cannot be used in custom components decorated with @Entry.
  • The syntax for @Link child components to initialize @State from the parent component is Comp({ aLink: this.aState }). Comp({aLink: $aState}) is also supported.

Let’s return to the above code. Analyze the code. When we click in , it will change to trigger the change of the interface ui. In , we need to pass the value of the selected item to itself. As a passed value, you need to use the tag. In this way, after clicking, the value of will also be triggered to change, so as to achieve the effect of changing the layout. The judgment of will also change according to this value. BottomNavigation.onClick(() => { this.currentItemIndex = index })@Link currentItemIndex: number;BottomNavigationItem({ navigationItem: item, currentIndex: $currentItemIndex })indexBottomNavigationItem\$BottomNavigationItemBottomNavigationItem\

After is clicked, in addition to updating the status of BottomNavigation, it is also necessary to judge the content area and display different interfaces. Therefore, BottomNavigation’s @Link currentItemIndex: number; needs to be bidirectionally bound to WechatMainFrame’s @State currentCheckIndex: number = 0; BottomNavigation({ currentItemIndex: $currentCheckIndex }). Finally, when we click of BottomNavigation, it will be bidirectionally bound to change the content area upwards and , and it will also be bound to < /span>Two-way binding changes the bottom navigation display. onclickWechatMainFrameBottomNavigationItem

Since I am also implementing functional logic while learning, I have to write articles and implement code functions, so the updates are generally limited to one article every 2 to 3 days. The article will try to cover the knowledge points that I think are more important. Take it out and explain. For those who are still unclear after reading it, you can send a private message or read other articles to learn more. The acquisition of knowledge should not be limited. I hope my article will help you.

In order to allow everyone to better learn the development technology of Harmony OS, we have specially compiled the "Harmony OS Development Learning Manual" (890 pages in total). I hope it will be helpful to everyone:https://qr21.cn/FV7h05

"Harmony OS Development Learning Manual"

Must-see for getting started:https://qr21.cn/FV7h05

  1. Application Development Guide (ArkTS)
  2. Introduction to Application Development (Java)

HarmonyOS concept:https://qr21.cn/FV7h05

  1. system definition
  2. Technology Architecture
  3. Technical characteristics
  4. system security

How to get started quickly:https://qr21.cn/FV7h05

  1. basic concept
  2. Building your first ArkTS application
  3. Build your first JS application
  4. ……

Development basics:https://qr21.cn/FV7h05

  1. Application basics
  2. Configuration file
  3. Application data management
  4. Application security management
  5. App privacy protection
  6. Third-party application call control mechanism
  7. Resource classification and access
  8. Learn the ArkTS language
  9. ……

Developed based on ArkTS:https://qr21.cn/FV7h05

  1. Ability development
  2. UI opening
  3. Public events and notifications
  4. window management
  5. media
  6. Safety
  7. Networks and Links
  8. phone service
  9. Data management
  10. Background Task Management
  11. Device management
  12. Equipment usage information statistics
  13. DFX
  14. international development
  15. Folding screen series
  16. ……

Guess you like

Origin blog.csdn.net/maniuT/article/details/134785992