DEV Community

儿歌八万首
儿歌八万首

Posted on

Develop a simple app using HarmonyOS ArkUI

An HarmonyOS application developed based on ArkUI. It calls the open API 玩android and implements functions such as simple page navigation, login, preservation of the login status, data display, and H5 page loading.

bottom navigation

Bottom Navigation Bar on the Home Page

The bottom navigation is implemented using Tabs. The page composition of the Tabs component consists of two parts, namely TabContent and TabBar. TabContent is the content page, and TabBar is the navigation tab bar. Each TabContent should have a tab corresponding to its content, which can be configured through the tabBar property of TabContent.

Tabs({ barPosition: BarPosition.End }) {
  TabContent() {
    HomeComponent()
  }.align(Alignment.Top)
  .tabBar(this.tabBuilder("Home", 0, $r("app.media.main_index_select_icon"), $r("app.media.main_index_icon")))

  TabContent() {
    SystemComponent()
  }.align(Alignment.Top)
  .tabBar(this.tabBuilder("System", 1, $r("app.media.main_house_select_icon"), $r("app.media.main_house_icon")))

  TabContent() {
    ProjectComponent()
  }.tabBar(this.tabBuilder("Project", 2, $r("app.media.main_message_select_icon"), $r("app.media.main_message_icon")))

  TabContent() {
    MyComponent()
  }.align(Alignment.Top)
  .tabBar(this.tabBuilder("My", 3, $r("app.media.main_me_select_icon"), $r("app.media.main_me_icon")))
}.scrollable(false)
.divider({ strokeWidth: 0.3 })
.animationDuration(0)
.onChange((index) => {
  this.currentIndex = index
})
Enter fullscreen mode Exit fullscreen mode

The barPosition controls the position of the navigation bar. BarPosition.Start represents the top navigation bar, and BarPosition.End represents the bottom navigation bar;

The divider can define the style of the navigation bar dividing line; animationDuration sets the switching animation duration of the navigation page; onChange listens to the navigation page switching.

HomeComponent, SystemComponent, ProjectComponent, and MyComponent are four custom page components. Switching the navigation can switch to the corresponding page.

Custom Component on the Home Page (HomeComponent)

The HomeComponent on the home page is composed of the Swiper component for the carousel image and the list component, which is used to display the article list. It is nested with a pull-to-refresh component PullToRefresh. The approximate structure is as follows:

Pull-to-refresh/Load-more on pull-up
PullToRefresh({
  data: this.articleList,
  scroller: this.scroller,
  onRefresh: () => {
    // Callback for refreshing
  },
  onLoadMore: () => {
   // Callback for loading more
  },
  customList: () => {
   // Refresh the page content
    Scroll(this.scroller) {
       Column(){
          // Carousel image
          Swiper(){}
          // Article list
          ForEach(this.articleList, (item: ArticleData) => {
             ArticleListItem({ article: item })
          })
       }
    }
})
Enter fullscreen mode Exit fullscreen mode

The third-party library @ohos/pulltorefresh is used for the refresh component. The sub-component of the refresh component must be a scrollable component. Here, since the page consists of a carousel image and a list component, a Scroll component is nested on the outer layer to ensure the normal operation of the page. SystemComponent is a constructor @builder within a custom component, which can abstract reusable UI elements into a method and is used here to display the layout of each item in the list.

Tips: The Scroll component and PullToRefresh need to share a controller Scroller.

Custom Component for the System (SystemComponent)

The system page is composed of top Tabs nested with Grid and a pull-to-refresh pulltorefresh list. The Grid component is a component provided by the system for displaying grids.

The page structure is as follows:

// Top navigation bar
Tabs({ barPosition: BarPosition.Start }){
  TabContent(){
    Column(){
    // Top grid component
      Grid(){}
      // Pull-to-refresh component
      PullToRefresh({
        customList: () => {
        // Scrollable component
          Scroll(){
            Column(){
            // Article list item
              ArticleListItem()
            }
          }
        }
      })
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Below the navigation bar of this page, a grid component is nested, and below the grid component, a pull-to-refresh component is used to nest the list for display. When switching the navigation, call the interface to refresh the grid and list data, and selecting the grid component page will refresh the list data.

Custom Component for the Project (ProjectComponent)

The project page is composed of Tabs directly nested with a pull-to-refresh component, and the pull-to-refresh component is nested with a Grid grid component. The page structure is as follows:

// Top navigation bar
Tabs({ barPosition: BarPosition.Start }){
   TabContent(){
     // Pull-to-refresh component
      PullToRefresh({
        customList: () => {
           Grid(this.scroller) {
             ForEach(this.projectList, (item: ArticleData) => {
               GridItem() {
                 // Style of the grid item
               }
             })
           }
           .columnsTemplate("1fr 1fr")
           .width("95%")
           .columnsGap(10)
           .scrollBar(BarState.Off)
           .padding(1)
        }
      })
   }
}
Enter fullscreen mode Exit fullscreen mode

The columnsTemplate method can set the number of columns of the grid. One 1fr represents one column. columnsGap sets the spacing between lists, and scrollBar sets the style of the progress bar.

Network Request @ohos/axios

The third-party library @ohos/axios is used for network requests and is simply encapsulated as follows:

export class HttpUtils {
  private static instance: HttpUtils = new HttpUtils()
  private axiosInstance: AxiosInstance

  private constructor() {
    this.axiosInstance = axios.create({
      baseURL: 'https://www.wanandroid.com/',
      timeout: 10 * 1000,
      // Set the global request header
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      // Set the proxy
      // proxy: { host: "192.168.10.229", port: 8888, exclusionList: [] }
    });

    // Intercept the request data and handle some business logic, such as adding cookies to the request
    this.axiosInstance.interceptors.request.use(async (config: InternalAxiosRequestConfig) => {
      if (config.url != WanAndroidUrl.Login) {
        // If it is not the login interface, add cookies to the request header
        const cookies = await PFUtils.get<string>("cookies").then()
        config.headers["Cookie"] = cookies
      }
      console.log("Request data: ", JSON.stringify(config.headers))
      return config;
    });

    // Intercept the response data and handle some business logic, such as saving cookies
    this.axiosInstance.interceptors.response.use((response: AxiosResponse) => {
      console.log("Response data: ", response.config.url)
      console.log("Response data: ", JSON.stringify(response.data))

      if (response.config.url == WanAndroidUrl.Login) {
        // If it is the login interface, save the cookies
        const cookies = response.headers["set-cookie"] as string[]
        // Save the cookies to the cache
        PFUtils.put<string>("cookies", cookies.toString())
        // Save the login status
        PFUtils.put<boolean>("LoginState", true)
        // Notify other pages that the user has logged in successfully
        emitter.emit({ eventId: Constant.USER_LOGIN })
      }

      return response;
    }, (error: AxiosError) => {
      // Do something with the response error
      console.log("Request error data: ", JSON.stringify(error))
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

Project address: HarmonyOS Version of WanAndroid

Top comments (0)