#DAYU200体验官# 世界巡游团App 原创 精华

入门大师小波哥
发布于 2022-7-5 22:22
浏览
1收藏

@toc

主题

本帖使用Dayu200为开发板,展示一个在线旅游App - 世界巡游团。

注意:本文不涉及App上的用户互动,仅为页面设计效果的实现。

设计效果图

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

Dayu200的预览配置

为了大幅提高UI的开发效率,降低Dayu200的使用门槛,在开发过程中,强烈建议使用DevEco Studio 3.0 Beta3(OpenHarmony)的MatePadPro作为预览配置,并调整到竖屏模式,最终与Dayu200上的效果近似一致。
#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

资源导入

本案例为了简单起见,文字与颜色直接写在代码中,仅图片资源需要导入,将所需图片拖到资源文件夹的media子目录中:
#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

启动页

使用默认的index.ets入口页作为启动页,分析页面的结构,所有的元素都可以放入一个Column容器中,即组件依次放入一列之中布局。

封面组件

封面由4张度假酒店的门面图片组成,整体上呈现一种瀑布流的布局的Grid组件。不过当前Grid组件尚未支持瀑布流布局,作为迂回的实现,可以改为两列式的左右拼接,两侧各占50%的水平空间,即内部横向布局(Row)。
要创建一个新组件,依照惯例,在pages目录下新建源码文件bannerLeft.ets,用于容纳左侧图片,左侧最下方的图片有一个暗色效果,可以调低图片的亮度。

Image()
	.brightness(0.3)

图片本身的尺寸固定大小,另有圆角和内边距:

Column({space:20}) {
      Image($r("app.media.cover1"))
        .width(149)
        .height(222)
        .objectFit(ImageFit.Contain)
        .borderRadius(14)

      Image($r("app.media.cover2"))
        .width(149)
        .height(222)
        .objectFit(ImageFit.Contain)
        .borderRadius(14)
        .brightness(0.3)
	.width('50%')

    }
    .padding(20)

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
再创建一个新组件,依照惯例,在pages目录下新建源码文件bannerRight.ets,布局与左
侧的相似,右侧最下方图片同样调低亮度,完整代码如下:

Column({space:20}) {
      Image($r("app.media.cover3"))
        .width(149)
        .height(222)
        .objectFit(ImageFit.Contain)
        .borderRadius(14)

      Image($r("app.media.cover4"))
        .width(149)
        .height(222)
        .objectFit(ImageFit.Contain)
        .borderRadius(14)
        .brightness(0.3)
	.width('50%')

    }
    .padding(20)

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
不过看起来图片产生了尺寸不对称问题,原因是图片本身可能存在大小不同,如果使用
相同的保持比例的填充方式,就会在容器大小固定的情况下产生变化。
需要把原先图片的ObjectFit从Contain:

Image(){

}
        .objectFit(ImageFit.Contain)

改为:

Image(){

}
        .objectFit(ImageFit.Fill)

更新组件代码:

@Entry
@Component
struct BannerRight {
  build() {

    Column({space:20}) {

      Image($r("app.media.cover3"))
        .width(149)
        .height(222)
        .objectFit(ImageFit.Fill)
        .borderRadius(14)

      Image($r("app.media.cover4"))
        .width(149)
        .height(222)
        .objectFit(ImageFit.Fill)
        .borderRadius(14)
        .brightness(0.3)

    }
    .padding(20)
.width('50%')
  }
}

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
最后创建封面组件,依照惯例,在pages目录下新建源码文件banner.ets,将左右两侧容器组合起来,完整代码如下:

import bannerLeft from './bannerLeft.ets'
import bannerRight from './bannerRight.ets'

@Entry
@Component
export default struct Banner {
  build() {
    Flex({
      direction: FlexDirection.Row,
      alignItems: ItemAlign.Center,
      justifyContent: FlexAlign.Center
    }) {
      bannerLeft()
      bannerRight()
    }

  }
}

因为通常创建新组件默认可能是生成Flex组件作为根容器,为了便利起见,在很多情况下,可以Flex组件代替Row组件,唯一需要是把direction属性设为Row即可。
#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

启动按钮组件

启动页最下方是开始按钮,左侧一个右箭头图标略微离圆角有一点距离,右侧是文字,针对这种布局,可以使用Row容器,插入Blank组件来布局,相对比使用Flex容器更直观也容易理解。

Row() {

      Image($r("app.media.start"))
        .width(42)
        .height(42)
        .margin({
          left:5}
        )

      Blank()

      Text('开始巡游')
        .fontSize(18)
        .fontWeight(FontWeight.Bold)

      Blank()
    }
    .borderRadius(27)
    .width(247)
    .height(52)
    .margin(10)

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
比较有挑战的是按钮的渐变色背景,观察设计稿的效果,是从上到下的淡绿色到绿色的过渡,可以使用线性渐变属性:

Row(){
}
	.linearGradient()

线性渐变有3个参数:angle: 线性渐变的角度,direction: 线性渐变的方向,colors: 为渐变的颜色描述,repeating: 为渐变的颜色重复着色。

加上从上至下,即水平180度从淡绿色到绿色的参数:

Row(){
}
	.linearGradient({
	angle: 180,
      direction: GradientDirection.Bottom,
      colors: [[0x00F4FF,0],[0x00ADB5,1]]}
)

完整按钮代码如下:

@Entry
@Component
export default struct StartButton {
  build() {
    Row() {
      Image($r("app.media.start"))
        .width(42)
        .height(42)
        .margin({
          left:5
        })
      Blank()
      Text('开始巡游')
        .fontSize(18)
        .fontColor(Color.White)
        .fontWeight(FontWeight.Bold)
      Blank()
    }
    .borderRadius(27)
    .width(247)
    .height(52)
    .margin(10)
    .linearGradient({
      angle: 180,
      direction: GradientDirection.Bottom,
      colors: [[0x00F4FF,0],[0x00ADB5,1]]
    })
  }
}

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

背景色

在index.ets中使用Column容器包含所有子组件,给予背景色:

Column() {

      banner()
      StartButton()

    }
    .width('100%')
    .height('100%')
    .backgroundColor('#252A39')

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

右侧封面修正

到了这一步才发现右侧封面是相同大小,不过不用担心,因为是组件式的组合,可以直接修改右侧封面组件上方图片的高度为184,下方图片高度为273。bannerRight.ets的代码更新如下:

@Entry
@Component
struct BannerRight {
  build() {

    Column({space:20}) {

      Image($r("app.media.cover3"))
        .width(149)
        .height(184)
        .objectFit(ImageFit.Fill)
        .borderRadius(14)

      Image($r("app.media.cover4"))
        .width(149)
        .height(273)
        .objectFit(ImageFit.Fill)
        .borderRadius(14)
        .brightness(0.3)

    }
    .padding(20)
.width('50%')
  }
}

修正之后,再次刷新首页预览:
#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

完整代码和效果

把启动页的两段文字都加入,形成完整的index.ets代码如下:

import banner from './banner.ets'
import StartButton from './StartButton.ets'

@Entry
@Component
struct Index {
  build() {
    Column() {
      banner()
      Text("世界巡游团,启航")
        .fontSize(32)
        .fontColor(Color.White)
      Blank()
      Text("极尽所能,让您搜索优美的度假圣地")
        .fontSize(16)
        .fontColor('#767D92')
      Blank()
      StartButton()
      Blank()
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#252A39')
  }
}

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

首页

分析页面的结构,与启动页非常相似,只不过组件较多。所有的元素都可以放入一个Column容器中,即组件依次放入一列之中布局。要创建组件,依照惯例,在pages目录下新建源码文件home.ets。

导航组件

导航由位于一行以内的文字块与头像图片组成,即内部横向布局(Row)。文字块的2块文字按列布局。
要创建一个新组件,依照惯例,在pages目录下新建源码文件nav.ets。

文字块:

Column(){

        Text('小雅')
          .fontSize(25)
          .fontWeight(FontWeight.Bold)
          .fontColor(Color.White)

        Text('探索世界之美')
          .fontSize(18)
          .fontColor('#767D92')

      }
      .alignItems(HorizontalAlign.Start)

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

头像图片

Image($r("app.media.avatar"))
        .height(44)
        .width(44)
        .objectFit(ImageFit.Fill)

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

组合起来

@Entry
@Component
struct Nav {
  build() {

    Flex(
      direction: FlexDirection.Row,
      alignItems: ItemAlign.Center,
      justifyContent: FlexAlign.SpaceBetween
    ) {

      Column(){

        Text('小雅')
          .fontSize(25)
          .fontWeight(FontWeight.Bold)
          .fontColor(Color.White)

        Text('探索世界之美')
          .fontSize(18)
          .fontColor('#767D92')

      }
      .alignItems(HorizontalAlign.Start)

      Image($r("app.media.avatar"))
        .height(44)
        .width(44)
        .objectFit(ImageFit.Fill)

    }
    .padding(20)
    .width('100%')

  }
}

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

口号文字组件

此组件非常简单,两段文字放入一列中。要创建组件,依照惯例,在pages目录下新建源码文件nav.ets。
完整代码如下:

@Entry
@Component
struct Slogon {
  build() {

    Column() {

      Text('发现\n度假新世界')
        .fontSize(35)
        .fontWeight(FontWeight.Bold)
        .fontColor(Color.White)

      Text('度假圣地搜索、一触即达')
        .fontSize(18)
        .fontColor('#767D92')

    }
    .alignItems(HorizontalAlign.Start)
    .padding(20)
    .width('100%')
  }
}

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

搜索条组件

按照惯例要新建一个组件,在pages目录下新建一个searchbar.ets。搜索条右侧有一个渐变带图标的按钮,可以使用线性渐变属性修饰一个Row容器即可:

Row(){

        Image($r("app.media.filter"))
          .width(42)
          .height(42)
          .margin({
            left:5}
          )
      }
      .borderRadius(12)
      .height(52)
      .width(52)
      .linearGradient({
        angle: 180,
        direction: GradientDirection.Bottom,
        colors: [[0x00F4FF,0],[0x00ADB5,1]]}
      )

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
搜索输入框可以使用TextInput组件:

TextInput(
        placeholder: '搜索'
      )
        .placeholderColor('#767D92')
        .width('75%')
        .height(52)

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
至于搜索前面的搜索小图标,TextInput暂不支持使用图标。这里留给读者去思考如何实现。
把两个组件组合起来,完整代码如下:

@Entry
@Component
export default struct Searchbar {
  build() {
    Row() {
      TextInput({
        placeholder: '搜索'
      })
        .placeholderColor('#767D92')
        .width('75%')
        .height(52)
      Blank()
      Row(){
        Image($r("app.media.filter"))
          .width(42)
          .height(42)
          .margin({
            left:5
          })
      }
      .borderRadius(12)
      .height(52)
      .width(52)
      .linearGradient({
        angle: 180,
        direction: GradientDirection.Bottom,
        colors: [[0x00F4FF,0],[0x00ADB5,1]]
      })

    }
    .padding(20)
    .width('100%')

  }
}

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

筛选按钮栏

按照惯例要新建一个组件,在pages目录下新建一个filter.ets。因为筛选可能有很多个按钮,未能显示的筛选按钮可以向右滑动后展示,那么这里毫无疑问要选择List组件。滑动方向listDirection设置为Horizontal水平,另加上边距20:

List() {

      ListItem() {

	}

}
.listDirection(Axis.Horizontal)
.padding(20)

List中的每一项由ListItem进行包裹。先来实现第一个带渐变色的圆角“全部”按钮:

Row(){

          Text('全部')
            .fontWeight(FontWeight.Bold)
            .fontColor(Color.White)
            .fontSize(18)
            .padding({top:8,bottom:8,left:20, right:20})

        }
        .borderRadius(8)
        .linearGradient({
          angle: 180,
          direction: GradientDirection.Bottom,
          colors: [[0x00F4FF,0],[0x00ADB5,1]]
        })

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
嵌入ListItem中:

List() {

      ListItem() {

        Row(){

          Text('全部')
            .fontWeight(FontWeight.Bold)
            .fontColor(Color.White)
            .fontSize(18)
            .padding(top:8,bottom:8,left:20, right:20)

        }
        .borderRadius(8)
        .linearGradient({
          angle: 180,
          direction: GradientDirection.Bottom,
          colors: [[0x00F4FF,0],[0x00ADB5,1]]
        })

      }

    }
    .listDirection(Axis.Horizontal)
    .padding(20)

接着是未选中的第二个“探险之旅”按钮,与选中的相比,未选中的按钮背景为深色无渐变,字体呈灰白色:

ListItem() {

        Row(){

          Text('探险之旅')
            .fontWeight(FontWeight.Lighter)
            .fontColor('#767D92')
            .fontSize(18)
            .padding({top:8,bottom:8,left:20, right:20})

        }
        .borderRadius(8)
        .backgroundColor('#2D3344')

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
好像两个按钮之间需要空隙,给List整体配置一个间距:

List({space:10}) {

      ListItem() {

        Row(){

          Text('全部')
            .fontWeight(FontWeight.Bold)
            .fontColor(Color.White)
            .fontSize(18)
            .padding({top:8,bottom:8,left:20, right:20})

        }
        .borderRadius(8)
        .linearGradient({
          angle: 180,
          direction: GradientDirection.Bottom,
          colors: [[0x00F4FF,0],[0x00ADB5,1]]}
        )

      }

      ListItem() {

        Row(){

          Text('探险之旅')
            .fontWeight(FontWeight.Lighter)
            .fontColor('#767D92')
            .fontSize(18)
            .padding(top:8,bottom:8,left:20, right:20)

        }
        .borderRadius(8)
        .backgroundColor('#2D3344')

      }


    }
    .listDirection(Axis.Horizontal)
    .padding(20)

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

下一个按钮布局与上一个相同,文字做更改:

ListItem() {

        Row(){

          Text('洞穴')
            .fontWeight(FontWeight.Lighter)
            .fontColor('#767D92')
            .fontSize(18)
            .padding({top:8,bottom:8,left:20, right:20})

        }
        .borderRadius(8)
        .backgroundColor('#2D3344')

      }

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
第四个按钮也是相同的布局:

ListItem() {

        Row(){

          Text('沙漠')
            .fontWeight(FontWeight.Lighter)
            .fontColor('#767D92')
            .fontSize(18)
            .padding({top:8,bottom:8,left:20, right:20})

        }
        .borderRadius(8)
        .backgroundColor('#2D3344')

      }

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
可以看到默认因为按钮总体长度超出了List宽度,会被屏幕截断,尝试在向右滑动一下列表:
#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
筛选按钮栏源文件filter.ets完整的代码如下:

@Entry
@Component
export default struct Filter {
  build() {

    List({space:10}) {

      ListItem() {

        Row(){

          Text('全部')
            .fontWeight(FontWeight.Bold)
            .fontColor(Color.White)
            .fontSize(12)
            .padding({top:8,bottom:8,left:20, right:20})

        }
        .borderRadius(8)
        .linearGradient({
          angle: 180,
          direction: GradientDirection.Bottom,
          colors: [[0x00F4FF,0],[0x00ADB5,1]]
        })

      }

      ListItem() {

        Row(){

          Text('探险之旅')
            .fontWeight(FontWeight.Lighter)
            .fontColor('#767D92')
            .fontSize(12)
            .padding({top:8,bottom:8,left:20, right:20})

        }
        .borderRadius(8)
        .backgroundColor('#2D3344')

      }

      ListItem() {

        Row(){

          Text('洞穴')
            .fontWeight(FontWeight.Lighter)
            .fontColor('#767D92')
            .fontSize(12)
            .padding({top:8,bottom:8,left:20, right:20})

        }
        .borderRadius(8)
        .backgroundColor('#2D3344')

      }

      ListItem() {

        Row(){

          Text('沙漠')
            .fontWeight(FontWeight.Lighter)
            .fontColor('#767D92')
            .fontSize(12)
            .padding({top:8,bottom:8,left:20, right:20})

        }
        .borderRadius(8)
        .backgroundColor('#2D3344')

      }


    }
    .listDirection(Axis.Horizontal)
    .padding(20)
    .height(80)
  }
}

推荐卡片列表组件

推荐卡片列表组件分为标题栏和推荐卡片列表。在pages下新建card.ets。
标题栏非常简单,文字在一行之内,两侧加上间距:

Row() {

      Text('推荐')
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .fontColor(Color.White)

      Blank()

      Text('看全部')
        .fontSize(16)
        .fontColor('#A7A6A7')

    }
    .padding(20)
    .width('100%')

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
推荐卡片列表也是一个可以水平左右滚动的组件,选择List及ListItem组件,给予标准间距20:

List({space: 20}) {

      ListItem(){



      }

    }
    .listDirection(Axis.Horizontal)

先来实现单独的卡片,卡片由背景图、右上角收藏按钮、左下角两段文字描述叠加组成。首先是圆角背景图:

Stack() {
            Image($r("app.media.item1"))
              .width(220)
              .height(290)
              .objectFit(ImageFit.Fill)
              .borderRadius(14)
}

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

然后右上角加入收藏按钮,收藏按钮居右,可以包含在一个Row中:

Row() {

              Blank()

              Row() {

                Image($r("app.media.heart_white"))
                  .width(32)
                  .height(32)
                  .objectFit(ImageFit.Fill)


              }
                .backgroundColor(Color.Gray)
                .backdropBlur(0.9)
                .borderRadius(8)

            }
            .width('100%')
            .padding(20)

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
可以看到预览中的位置并不在右上角,因为下方的文字区域还没生成,稍候再来解决。文字区域由两端按列布局的左对齐文字,加上左侧的标准边距20,以及右侧的行距构成:

Row() {

                Column() {

                  Text('圣胡安')
                    .fontSize(25)
                    .fontWeight(FontWeight.Bold)
                    .fontColor(Color.White)

                  Text('美国 阿拉巴马')
                    .fontSize(18)
                    .fontColor(Color.White)
                  
                }
                .alignItems(HorizontalAlign.Start)
                .padding(20)

                Blank()

 }
   .width('100%')

再将爱心图标和文字区域整体放入一个Column中,Column尺寸与背景图尺寸一致:

Column() {

              Row() {

                Blank()

                Row() {

                  Image($r("app.media.heart_white"))
                    .width(32)
                    .height(32)
                    .objectFit(ImageFit.Fill)
                  
                }
                .backgroundColor(Color.Gray)
                .backdropBlur(0.9)
                .borderRadius(8)

              }
              .width('100%')
              .padding(20)

              Blank()

              Row() {

                Column() {

                  Text('圣胡安')
                    .fontSize(25)
                    .fontWeight(FontWeight.Bold)
                    .fontColor(Color.White)

                  Text('美国 阿拉巴马')
                    .fontSize(18)
                    .fontColor(Color.White)

                }
                .alignItems(HorizontalAlign.Start)
                .padding(20)

                Blank()
              }
              .width('100%')

            }
            .width(220)
            .height(290)

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
整个叠加出来的Stack代码,作为第一张卡片的ListItem代码如下:

ListItem() {

          Stack() {
            Image($r("app.media.item1"))
              .width(220)
              .height(290)
              .objectFit(ImageFit.Fill)
              .borderRadius(14)

            Column() {

              Row() {

                Blank()

                Row() {

                  Image($r("app.media.heart_white"))
                    .width(32)
                    .height(32)
                    .objectFit(ImageFit.Fill)

                }
                .backgroundColor(Color.Gray)
                .backdropBlur(0.9)
                .borderRadius(8)

              }
              .width('100%')
              .padding(20)

              Blank()

              Row() {

                Column() {

                  Text('圣胡安')
                    .fontSize(25)
                    .fontWeight(FontWeight.Bold)
                    .fontColor(Color.White)

                  Text('美国 阿拉巴马')
                    .fontSize(18)
                    .fontColor(Color.White)

                }
                .alignItems(HorizontalAlign.Start)
                .padding(20)

                Blank()
              }
              .width('100%')

            }
            .width(220)
            .height(290)



          }
          
        }

第二张卡片,替换其中的背景图和文字区域:

ListItem() {

          Stack() {
            Image($r("app.media.item2"))
              .width(220)
              .height(290)
              .objectFit(ImageFit.Fill)
              .borderRadius(14)

            Column() {

              Row() {

                Blank()

                Row() {

                  Image($r("app.media.heart_white"))
                    .width(32)
                    .height(32)
                    .objectFit(ImageFit.Fill)

                }
                .backgroundColor(Color.Gray)
                .backdropBlur(0.9)
                .borderRadius(8)

              }
              .width('100%')
              .padding(20)

              Blank()

              Row() {

                Column() {

                  Text('海边公寓')
                    .fontSize(25)
                    .fontWeight(FontWeight.Bold)
                    .fontColor(Color.White)

                  Text('圭亚那 科里亚')
                    .fontSize(18)
                    .fontColor(Color.White)

                }
                .alignItems(HorizontalAlign.Start)
                .padding(20)

                Blank()
              }
              .width('100%')

            }
            .width(220)
            .height(290)



          }

        }

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
第三张卡片,如上替换其中的背景图和文字区域:

ListItem() {

          Stack() {
            Image($r("app.media.item3"))
              .width(220)
              .height(290)
              .objectFit(ImageFit.Fill)
              .borderRadius(14)

            Column() {

              Row() {

                Blank()

                Row() {

                  Image($r("app.media.heart_white"))
                    .width(32)
                    .height(32)
                    .objectFit(ImageFit.Fill)

                }
                .backgroundColor(Color.Gray)
                .backdropBlur(0.9)
                .borderRadius(8)

              }
              .width('100%')
              .padding(20)

              Blank()

              Row() {

                Column() {

                  Text('蒙特维多')
                    .fontSize(25)
                    .fontWeight(FontWeight.Bold)
                    .fontColor(Color.White)

                  Text('澳大利亚 悉尼')
                    .fontSize(18)
                    .fontColor(Color.White)

                }
                .alignItems(HorizontalAlign.Start)
                .padding(20)

                Blank()
              }
              .width('100%')

            }
            .width(220)
            .height(290)



          }

        }

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
发现拖动到最右端没有边距,增加List的外边距,完整List代码如下:

List({space: 20}) {

        ListItem() {

          Stack() {
            Image($r("app.media.item1"))
              .width(220)
              .height(290)
              .objectFit(ImageFit.Fill)
              .borderRadius(14)

            Column() {

              Row() {

                Blank()

                Row() {

                  Image($r("app.media.heart_white"))
                    .width(32)
                    .height(32)
                    .objectFit(ImageFit.Fill)

                }
                .backgroundColor(Color.Gray)
                .backdropBlur(0.9)
                .borderRadius(8)

              }
              .width('100%')
              .padding(20)

              Blank()

              Row() {

                Column() {

                  Text('圣胡安')
                    .fontSize(25)
                    .fontWeight(FontWeight.Bold)
                    .fontColor(Color.White)

                  Text('美国 阿拉巴马')
                    .fontSize(18)
                    .fontColor(Color.White)

                }
                .alignItems(HorizontalAlign.Start)
                .padding(20)

                Blank()
              }
              .width('100%')

            }
            .width(220)
            .height(290)



          }

        }

        ListItem() {

          Stack() {
            Image($r("app.media.item2"))
              .width(220)
              .height(290)
              .objectFit(ImageFit.Fill)
              .borderRadius(14)

            Column() {

              Row() {

                Blank()

                Row() {

                  Image($r("app.media.heart_white"))
                    .width(32)
                    .height(32)
                    .objectFit(ImageFit.Fill)

                }
                .backgroundColor(Color.Gray)
                .backdropBlur(0.9)
                .borderRadius(8)

              }
              .width('100%')
              .padding(20)

              Blank()

              Row() {

                Column() {

                  Text('海边公寓')
                    .fontSize(25)
                    .fontWeight(FontWeight.Bold)
                    .fontColor(Color.White)

                  Text('圭亚那 科里亚')
                    .fontSize(18)
                    .fontColor(Color.White)

                }
                .alignItems(HorizontalAlign.Start)
                .padding(20)

                Blank()
              }
              .width('100%')

            }
            .width(220)
            .height(290)



          }

        }

        ListItem() {

          Stack() {
            Image($r("app.media.item3"))
              .width(220)
              .height(290)
              .objectFit(ImageFit.Fill)
              .borderRadius(14)

            Column() {

              Row() {

                Blank()

                Row() {

                  Image($r("app.media.heart_white"))
                    .width(32)
                    .height(32)
                    .objectFit(ImageFit.Fill)

                }
                .backgroundColor(Color.Gray)
                .backdropBlur(0.9)
                .borderRadius(8)

              }
              .width('100%')
              .padding(20)

              Blank()

              Row() {

                Column() {

                  Text('蒙特维多')
                    .fontSize(25)
                    .fontWeight(FontWeight.Bold)
                    .fontColor(Color.White)

                  Text('澳大利亚 悉尼')
                    .fontSize(18)
                    .fontColor(Color.White)

                }
                .alignItems(HorizontalAlign.Start)
                .padding(20)

                Blank()
              }
              .width('100%')

            }
            .width(220)
            .height(290)



          }

        }

      }
      .margin(20)
      .listDirection(Axis.Horizontal)

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
可以看到预览中标题不可见,是因为暂时还未切换到整个页面带背景色的情况下,此时可以切换成暗黑模式查看标题栏:
#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
完整的推荐卡片列表组件代码如下:

@Entry
@Component
export default struct Card {
  build() {

    Column(){

      Row() {

        Text('推荐')
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .fontColor(Color.White)

        Blank()

        Text('看全部')
          .fontSize(16)
          .fontColor('#A7A6A7')

      }
      .padding({left:20, right: 30, top: 5, bottom:5})
      .width('100%')

      List({space: 20}) {

        ListItem() {

          Stack() {
            Image($r("app.media.item1"))
              .width(220)
              .height(290)
              .objectFit(ImageFit.Fill)
              .borderRadius(14)

            Column() {

              Row() {

                Blank()

                Row() {

                  Image($r("app.media.heart_white"))
                    .width(32)
                    .height(32)
                    .objectFit(ImageFit.Fill)

                }
                .backgroundColor(Color.Gray)
                .backdropBlur(0.9)
                .borderRadius(8)

              }
              .width('100%')
              .padding(20)

              Blank()

              Row() {

                Column() {

                  Text('圣胡安')
                    .fontSize(25)
                    .fontWeight(FontWeight.Bold)
                    .fontColor(Color.White)

                  Text('美国 阿拉巴马')
                    .fontSize(18)
                    .fontColor(Color.White)

                }
                .alignItems(HorizontalAlign.Start)
                .padding(20)

                Blank()
              }
              .width('100%')

            }
            .width(220)
            .height(290)



          }

        }

        ListItem() {

          Stack() {
            Image($r("app.media.item2"))
              .width(220)
              .height(290)
              .objectFit(ImageFit.Fill)
              .borderRadius(14)

            Column() {

              Row() {

                Blank()

                Row() {

                  Image($r("app.media.heart_white"))
                    .width(32)
                    .height(32)
                    .objectFit(ImageFit.Fill)

                }
                .backgroundColor(Color.Gray)
                .backdropBlur(0.9)
                .borderRadius(8)

              }
              .width('100%')
              .padding(20)

              Blank()

              Row() {

                Column() {

                  Text('海边公寓')
                    .fontSize(25)
                    .fontWeight(FontWeight.Bold)
                    .fontColor(Color.White)

                  Text('圭亚那 科里亚')
                    .fontSize(18)
                    .fontColor(Color.White)

                }
                .alignItems(HorizontalAlign.Start)
                .padding(20)

                Blank()
              }
              .width('100%')

            }
            .width(220)
            .height(290)



          }

        }

        ListItem() {

          Stack() {
            Image($r("app.media.item3"))
              .width(220)
              .height(290)
              .objectFit(ImageFit.Fill)
              .borderRadius(14)

            Column() {

              Row() {

                Blank()

                Row() {

                  Image($r("app.media.heart_white"))
                    .width(32)
                    .height(32)
                    .objectFit(ImageFit.Fill)

                }
                .backgroundColor(Color.Gray)
                .backdropBlur(0.9)
                .borderRadius(8)

              }
              .width('100%')
              .padding(20)

              Blank()

              Row() {

                Column() {

                  Text('蒙特维多')
                    .fontSize(25)
                    .fontWeight(FontWeight.Bold)
                    .fontColor(Color.White)

                  Text('澳大利亚 悉尼')
                    .fontSize(18)
                    .fontColor(Color.White)

                }
                .alignItems(HorizontalAlign.Start)
                .padding(20)

                Blank()
              }
              .width('100%')

            }
            .width(220)
            .height(290)



          }

        }

      }
      .margin({left:20,right:20})
      .listDirection(Axis.Horizontal)
      .height(290)
    }

  }
}

选项卡组件

在pages下新建tabbar.ets,作为底部选项卡的组件源文件。选项卡的所有组件都在一个Row中,其中第一个是熟悉的渐变色按钮,左侧也配了一个图标:

Row() {

        Blank()

        Image($r("app.media.home"))
          .width(28)
          .height(28)
          .margin({
            left:5
          })

        Text('主页')
          .fontSize(16)
          .fontColor(Color.White)
          .fontWeight(FontWeight.Bold)
          .padding(left:10)

        Blank()

      }
      .borderRadius(27)
      .width(126)
      .height(48)
      .margin(10)
      .linearGradient({
        angle: 180,
        direction: GradientDirection.Bottom,
        colors: [[0x00F4FF,0],[0x00ADB5,1]]
      })

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

第二个收藏按钮:

Image($r("app.media.heart"))
        .width(28)
        .height(28)
        .objectFit(ImageFit.Fill)

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

第三个购物车按钮:

Image($r("app.media.cart"))
        .width(28)
        .height(28)
        .objectFit(ImageFit.Fill)

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
第四个是个人按钮:

Image($r("app.media.user"))
        .width(28)
        .height(28)
        .objectFit(ImageFit.Fill)

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

选项卡整体效果如下:

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

需要在各图标间插入Blank以便均匀分布在一行以内,tabbar.ets的完整源码如下:

@Entry
@Component
export default struct Tabbar {
  build() {

    Row() {

      Row() {

        Blank()

        Image($r("app.media.home"))
          .width(28)
          .height(28)
          .margin({
            left:5
          })

        Text('主页')
          .fontSize(16)
          .fontColor(Color.White)
          .fontWeight(FontWeight.Bold)
          .padding({left:10})

        Blank()

      }
      .borderRadius(27)
      .width(126)
      .height(48)
      .margin(10)
      .linearGradient({
        angle: 180,
        direction: GradientDirection.Bottom,
        colors: [[0x00F4FF,0],[0x00ADB5,1]]
      })

      Blank()

      Image($r("app.media.heart"))
        .width(28)
        .height(28)
        .objectFit(ImageFit.Fill)

      Blank()

      Image($r("app.media.cart"))
        .width(28)
        .height(28)
        .objectFit(ImageFit.Fill)

      Blank()

      Image($r("app.media.user"))
        .width(28)
        .height(28)
        .objectFit(ImageFit.Fill)

      Blank()

    }
    .width('100%')
    .padding({left: 20,right:20,bottom: 10})
//    .height('100%')

  }
}

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

首页的调整优化

把上述的组件依次导入到index.ets的Home组件中,完整代码如下:

import Nav from './nav.ets'
import Slogon  from './slogon.ets'
import Searchbar from './searchbar.ets'
import Filter from './filter.ets'
import Card from './card.ets'
import Tabbar from './tabbar.ets'


@Entry
@Component
struct Home {
  build() {
    Column() {
      Nav()
      Slogon()
      Searchbar()
      Filter()
      Card()
      Tabbar()
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#252A39')
  }
}

此时预览不一定能完美适配整个页面,依然需要对每个子组件对针对性的字体、容器、边距等调整优化。

nav.ets优化后:

@Entry
@Component
struct Nav {
  build() {
    Flex(
      direction: FlexDirection.Row,
      alignItems: ItemAlign.Center,
      justifyContent: FlexAlign.SpaceBetween
    ) {

      Column(){

        Text('小雅')
          .fontSize(25)
          .fontWeight(FontWeight.Bold)
          .fontColor(Color.White)

        Text('探索世界之美')
          .fontSize(18)
          .fontColor('#767D92')

      }
      .alignItems(HorizontalAlign.Start)

      Image($r("app.media.avatar"))
        .height(44)
        .width(44)
        .objectFit(ImageFit.Fill)

    }
    .padding({top:10,bottom: 5, left:20,right:20})
    .width('100%')

  }
}

slogon.ets优化后:

@Entry
@Component
export default struct Slogon {
  build() {
    Column() {
      Text('发现\n度假新世界')
        .fontSize(30)
        .fontWeight(FontWeight.Bold)
        .fontColor(Color.White)
      Text('度假圣地搜索、一触即达')
        .fontSize(15)
        .fontColor('#767D92')
    }
    .alignItems(HorizontalAlign.Start)
    .padding(20)
    .width('100%')
  }
}

searchbar.ets优化后:

@Entry
@Component
export default struct Searchbar {
  build() {
    Row() {
      TextInput({
        placeholder: '搜索'
      })
        .placeholderColor('#767D92')
        .width('75%')
        .height(52)
      Blank()
      Row(){
        Image($r("app.media.filter"))
          .width(42)
          .height(42)
          .margin({
            left:5
          })
      }
      .borderRadius(12)
      .height(52)
      .width(52)
      .linearGradient({
        angle: 180,
        direction: GradientDirection.Bottom,
        colors: [[0x00F4FF,0],[0x00ADB5,1]]
      })

    }
    .padding(20)
    .width('100%')

  }
}

filter.ets优化后:

@Entry
@Component
export default struct Filter {
  build() {

    List({space:10}) {

      ListItem() {

        Row(){

          Text('全部')
            .fontWeight(FontWeight.Bold)
            .fontColor(Color.White)
            .fontSize(12)
            .padding({top:8,bottom:8,left:20, right:20})

        }
        .borderRadius(8)
        .linearGradient({
          angle: 180,
          direction: GradientDirection.Bottom,
          colors: [[0x00F4FF,0],[0x00ADB5,1]]
        })

      }

      ListItem() {

        Row(){

          Text('探险之旅')
            .fontWeight(FontWeight.Lighter)
            .fontColor('#767D92')
            .fontSize(12)
            .padding({top:8,bottom:8,left:20, right:20})

        }
        .borderRadius(8)
        .backgroundColor('#2D3344')

      }

      ListItem() {

        Row(){

          Text('洞穴')
            .fontWeight(FontWeight.Lighter)
            .fontColor('#767D92')
            .fontSize(12)
            .padding({top:8,bottom:8,left:20, right:20})

        }
        .borderRadius(8)
        .backgroundColor('#2D3344')

      }

      ListItem() {

        Row(){

          Text('沙漠')
            .fontWeight(FontWeight.Lighter)
            .fontColor('#767D92')
            .fontSize(12)
            .padding({top:8,bottom:8,left:20, right:20})

        }
        .borderRadius(8)
        .backgroundColor('#2D3344')

      }


    }
    .listDirection(Axis.Horizontal)
    .padding(20)
    .height(80)
  }
}

card.ets优化后:

@Entry
@Component
export default struct Card {
  build() {

    Column(){

      Row() {

        Text('推荐')
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .fontColor(Color.White)

        Blank()

        Text('看全部')
          .fontSize(16)
          .fontColor('#A7A6A7')

      }
      .padding({left:20, right: 30, top: 5, bottom:5})
      .width('100%')

      List({space: 20}) {

        ListItem() {

          Stack() {
            Image($r("app.media.item1"))
              .width(220)
              .height(290)
              .objectFit(ImageFit.Fill)
              .borderRadius(14)

            Column() {

              Row() {

                Blank()

                Row() {

                  Image($r("app.media.heart_white"))
                    .width(32)
                    .height(32)
                    .objectFit(ImageFit.Fill)

                }
                .backgroundColor(Color.Gray)
                .backdropBlur(0.9)
                .borderRadius(8)

              }
              .width('100%')
              .padding(20)

              Blank()

              Row() {

                Column() {

                  Text('圣胡安')
                    .fontSize(25)
                    .fontWeight(FontWeight.Bold)
                    .fontColor(Color.White)

                  Text('美国 阿拉巴马')
                    .fontSize(18)
                    .fontColor(Color.White)

                }
                .alignItems(HorizontalAlign.Start)
                .padding(20)

                Blank()
              }
              .width('100%')

            }
            .width(220)
            .height(290)



          }

        }

        ListItem() {

          Stack() {
            Image($r("app.media.item2"))
              .width(220)
              .height(290)
              .objectFit(ImageFit.Fill)
              .borderRadius(14)

            Column() {

              Row() {

                Blank()

                Row() {

                  Image($r("app.media.heart_white"))
                    .width(32)
                    .height(32)
                    .objectFit(ImageFit.Fill)

                }
                .backgroundColor(Color.Gray)
                .backdropBlur(0.9)
                .borderRadius(8)

              }
              .width('100%')
              .padding(20)

              Blank()

              Row() {

                Column() {

                  Text('海边公寓')
                    .fontSize(25)
                    .fontWeight(FontWeight.Bold)
                    .fontColor(Color.White)

                  Text('圭亚那 科里亚')
                    .fontSize(18)
                    .fontColor(Color.White)

                }
                .alignItems(HorizontalAlign.Start)
                .padding(20)

                Blank()
              }
              .width('100%')

            }
            .width(220)
            .height(290)



          }

        }

        ListItem() {

          Stack() {
            Image($r("app.media.item3"))
              .width(220)
              .height(290)
              .objectFit(ImageFit.Fill)
              .borderRadius(14)

            Column() {

              Row() {

                Blank()

                Row() {

                  Image($r("app.media.heart_white"))
                    .width(32)
                    .height(32)
                    .objectFit(ImageFit.Fill)

                }
                .backgroundColor(Color.Gray)
                .backdropBlur(0.9)
                .borderRadius(8)

              }
              .width('100%')
              .padding(20)

              Blank()

              Row() {

                Column() {

                  Text('蒙特维多')
                    .fontSize(25)
                    .fontWeight(FontWeight.Bold)
                    .fontColor(Color.White)

                  Text('澳大利亚 悉尼')
                    .fontSize(18)
                    .fontColor(Color.White)

                }
                .alignItems(HorizontalAlign.Start)
                .padding(20)

                Blank()
              }
              .width('100%')

            }
            .width(220)
            .height(290)



          }

        }

      }
      .margin({left:20,right:20})
      .listDirection(Axis.Horizontal)
      .height(290)
    }

  }
}

全部子组件优化后的首页预览如下:
#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

详情页

详情页由全屏的背景图、导航栏、缩略图列表和详情卡片堆叠而成。要创建组件,依照惯例,在pages目录下新建源码文件detail.ets。

导航栏

在pages目录下新建源码文件nav2.ets。导航栏由返回按钮和用户头像在一列内组成,首先是返回按钮:

Row() {

        Blank()

        Image($r("app.media.back"))
          .width(32)
          .height(32)
          .objectFit(ImageFit.Contain)

        Blank()
      }
      .width(52)
      .height(52)
      .backgroundColor(Color.Gray)
      .backdropBlur(0.8)
      .borderRadius(8)

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
加上右侧头像已经中间的间距,以及导航栏容器Row整体的内边距:

@Entry
@Component
struct Nav2 {
  build() {

    Row() {

      Row() {

        Blank()

        Image($r("app.media.back"))
          .width(32)
          .height(32)
          .objectFit(ImageFit.Contain)

        Blank()
      }
      .width(52)
      .height(52)
      .backgroundColor(Color.Gray)
      .backdropBlur(0.8)
      .borderRadius(8)

      Blank()

      Image($r("app.media.avatar"))
        .width(44)
        .height(44)
        .objectFit(ImageFit.Contain)

    }
    .width('100%')
    .padding(20)
    
  }
}

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

缩略图列表

缩略图列表由4张带边框的小图排成一行组成。在pages下新建thumb.ets文件,先实现单个的缩略图:

Image($r("app.media.cover1"))
        .width(50)
        .height(50)
        .objectFit(ImageFit.Fill)
        .borderRadius(8)

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
把图片装入一个Row,再设置一个内边距即可便捷创建一个描边的效果:

Row() {
        Image($r("app.media.cover1"))
          .width(50)
          .height(50)
          .objectFit(ImageFit.Fill)
          .borderRadius(8)
      }
      .borderRadius(8)
      .backgroundColor(Color.Gray)
      .padding(5)

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
把其他缩略图就加上,完整代码如下:

@Entry
@Component
export default struct Thumb {

  build() {

    Flex({
      direction: FlexDirection.Row,
      alignItems: ItemAlign.Center,
      justifyContent: FlexAlign.SpaceAround
    }) {

      Row() {

        Image($r("app.media.cover1"))
          .width(50)
          .height(50)
          .objectFit(ImageFit.Fill)
          .borderRadius(8)

      }
      .borderRadius(8)
      .backgroundColor(Color.Gray)
      .padding(5)

      Row() {

        Image($r("app.media.cover2"))
          .width(50)
          .height(50)
          .objectFit(ImageFit.Fill)
          .borderRadius(8)

      }
      .borderRadius(8)
      .backgroundColor(Color.Gray)
      .padding(5)

      Row() {

        Image($r("app.media.cover3"))
          .width(50)
          .height(50)
          .objectFit(ImageFit.Fill)
          .borderRadius(8)

      }
      .borderRadius(8)
      .backgroundColor(Color.Gray)
      .padding(5)

      Row() {

        Image($r("app.media.cover4"))
          .width(50)
          .height(50)
          .objectFit(ImageFit.Fill)
          .borderRadius(8)

      }
      .borderRadius(8)
      .backgroundColor(Color.Gray)
      .padding(5)

    }
    .padding({left: 30, right:30, bottom: 30})
    .width('100%')

  }
}

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

详情卡片

在pages下新建infoCard.ets源文件。首先是卡片容器,高度是屏幕高度的一半,有主题背景色:

Column() {

    }
    .backgroundColor('#262A39')
    .borderRadius(44)
    .width('100%')
    .height('50%')

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
卡片标题由左侧文字区域和右侧收藏按钮组成:

Row() {

        Column() {

          Text('蒙特维多庄园')
            .fontSize(30)
            .fontWeight(FontWeight.Bold)
            .fontColor(Color.White)

          Text('澳大利亚 悉尼')
            .fontSize(15)
            .fontColor('#767D92')

        }
        .alignItems(HorizontalAlign.Start)
        .padding(20)

        Blank()

        Column() {

          Image($r("app.media.bookmark"))
            .height(32)
            .width(32)
            .objectFit(ImageFit.Contain)

        }
        .padding(10)
        .borderRadius(8)
        .backgroundColor('#2D3344')

      }
      .width('100%')
      .padding(right:20)

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

标题下方是参观人的头像和人数,注意头像是一个叠加在另一个之上,视觉效果像是一串圆形硬币向右展开,先放置一个Row容器和左侧的Stack容器和一个头像:

Row() {
        Stack() {
          Image($r("app.media.avatar"))
            .height(40)
            .width(40)
            .borderRadius(20)
            .objectFit(ImageFit.Contain)
          
        }

      }
      .width('100%')
      .padding(20)

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
然后依次挨个叠加其他头像,简单起见可以使用封面的图来作为其他头像的后续,要注意挨个相对于左侧的边距偏移,即translate属性中的x值:

Row() {
        Stack() {
          Image($r("app.media.item3"))
            .height(40)
            .width(40)
            .borderRadius(20)
            .objectFit(ImageFit.Fill)

          Image($r("app.media.cover1"))
            .height(40)
            .width(40)
            .borderRadius(20)
            .objectFit(ImageFit.Fill)
            .translate({x: 25})

          Image($r("app.media.cover2"))
            .height(40)
            .width(40)
            .borderRadius(20)
            .objectFit(ImageFit.Fill)
            .translate({x: 50})

          Image($r("app.media.cover3"))
            .height(40)
            .width(40)
            .borderRadius(20)
            .objectFit(ImageFit.Fill)
            .translate({x: 75})

          Image($r("app.media.item1"))
            .height(40)
            .width(40)
            .borderRadius(20)
            .objectFit(ImageFit.Fill)
            .translate({x: 100})

          Image($r("app.media.avatar"))
            .height(40)
            .width(40)
            .borderRadius(20)
            .objectFit(ImageFit.Fill)
            .translate({x: 125})
          
        }
        .height(40)

        Blank()

        Text('50人参团')
          .fontColor('#00ADB5')
          .fontSize(14)
          .fontWeight(FontWeight.Bold)

      }
      .width('100%')
      .padding(20)

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
接下来是详情描述区,布局与标题类似:

Column(){

        Row() {

          Text('描述')
            .fontSize(18)
            .fontWeight(FontWeight.Bold)
            .fontColor(Color.White)

          Blank()

          Text('看更多')
            .fontSize(16)
            .fontColor('#00ADB5')

        }
        .width('100%')
        .padding({bottom: 20})


        Text('蒙特维多乡村庄园是一个宁静的,位于生态保护区附近舒适度假酒店,此处的赛若普兰诺地区以蒙特维度蝴蝶花园而闻名于世。')
          .fontSize(15)
          .fontColor('#767D92')

      }
      .alignItems(HorizontalAlign.Start)
      .padding({left:20, right: 20})

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
卡片的最后一个部分是价格和预定按钮,其中按钮保持整个设计中统一的渐变色:

Row() {

        Column() {

          Text('定价')
            .fontSize(18)
            .fontColor('#767D92')

          Text('$20/晚')
            .fontSize(22)
            .fontWeight(FontWeight.Bold)
            .fontColor(Color.White)


        }
        .alignItems(HorizontalAlign.Start)

        Blank()

      }
      .width('100%')
      .padding({left:20, right: 20, bottom:30})

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区

渐变按钮完整代码:

Column() {

          Blank()

          Text('现在预定')
            .fontSize(18)
            .fontColor(Color.White)
            .fontWeight(FontWeight.Bold)

          Blank()
          
        }
        .borderRadius(18)
        .width(188)
        .height(52)
        .linearGradient({
          angle: 180,
          direction: GradientDirection.Bottom,
          colors: [[0x00F4FF,0],[0x00ADB5,1]]}
        )

#DAYU200体验官# 世界巡游团App-鸿蒙开发者社区
信息卡片完整代码:

@Entry
@Component
struct InfoCard {
  build() {

    Column() {

      Row() {

        Column() {

          Text('蒙特维多庄园')
            .fontSize(30)
            .fontWeight(FontWeight.Bold)
            .fontColor(Color.White)

          Text('澳大利亚 悉尼')
            .fontSize(15)
            .fontColor('#767D92')

        }
        .alignItems(HorizontalAlign.Start)
        .padding(20)

        Blank()

        Column() {

          Image($r("app.media.bookmark"))
            .height(32)
            .width(32)
            .objectFit(ImageFit.Contain)

        }
        .padding(10)
        .borderRadius(8)
        .backgroundColor('#2D3344')

      }
      .width('100%')
      .padding({ right: 20 })

      Row() {
        Stack() {
          Image($r("app.media.item3"))
            .height(40)
            .width(40)
            .borderRadius(20)
            .objectFit(ImageFit.Fill)

          Image($r("app.media.cover1"))
            .height(40)
            .width(40)
            .borderRadius(20)
            .objectFit(ImageFit.Fill)
            .translate({ x: 25 })

          Image($r("app.media.cover2"))
            .height(40)
            .width(40)
            .borderRadius(20)
            .objectFit(ImageFit.Fill)
            .translate({ x: 50 })

          Image($r("app.media.cover3"))
            .height(40)
            .width(40)
            .borderRadius(20)
            .objectFit(ImageFit.Fill)
            .translate({ x: 75 })

          Image($r("app.media.item1"))
            .height(40)
            .width(40)
            .borderRadius(20)
            .objectFit(ImageFit.Fill)
            .translate({ x: 100 })

          Image($r("app.media.avatar"))
            .height(40)
            .width(40)
            .borderRadius(20)
            .objectFit(ImageFit.Fill)
            .translate({ x: 125 })

        }
        .height(40)

        Blank()

        Text('50人参团')
          .fontColor('#00ADB5')
          .fontSize(14)
          .fontWeight(FontWeight.Bold)

      }
      .width('100%')
      .padding(20)

      Column() {

        Row() {

          Text('描述')
            .fontSize(18)
            .fontWeight(FontWeight.Bold)
            .fontColor(Color.White)

          Blank()

          Text('看更多')
            .fontSize(16)
            .fontColor('#00ADB5')

        }
        .width('100%')
        .padding({ bottom: 20 })


        Text('蒙特维多乡村庄园是一个宁静的,位于生态保护区附近舒适度假酒店,此处的赛若普兰诺地区以蒙特维度蝴蝶花园而闻名于世。')
          .fontSize(15)
          .fontColor('#767D92')

      }
      .alignItems(HorizontalAlign.Start)
      .padding( {left: 20, right: 20} )

      Blank()

      Row() {

        Column() {

          Text('定价')
            .fontSize(18)
            .fontColor('#767D92')

          Text('$20/晚')
            .fontSize(22)
            .fontWeight(FontWeight.Bold)
            .fontColor(Color.White)


        }
        .alignItems(HorizontalAlign.Start)

        Blank()

        Column() {

          Blank()

          Text('现在预定')
            .fontSize(18)
            .fontColor(Color.White)
            .fontWeight(FontWeight.Bold)

          Blank()

        }
        .borderRadius(18)
        .width(188)
        .height(52)
        .linearGradient(
          angle: 180,
          direction: GradientDirection.Bottom,
          colors: [[0x00F4FF,0],[0x00ADB5,1]]
        )

      }
      .width('100%')
      .padding({left:20, right: 20, bottom:30})


    }
    .backgroundColor('#262A39')
    .borderRadius(44)
    .width('100%')
    .height('50%')

  }
}

详情页的调整优化

把上述的组件依次导入到detail.ets的Detail组件中,完整代码如下:

import Nav2 from './nav2.ets'
import Thumb from './thumb.ets'
import InfoCard from './infocard.ets'

@Entry
@Component
struct Detail {
  build() {

    Stack() {

      Image($r("app.media.cover4"))
        .objectFit(ImageFit.Fill)

      Column() {

        Nav2()

        Blank()

        Thumb()

        InfoCard()

      }
      .width('100%')
      .height('100%')

    }
    .width('100%')
    .height('100%')
  }
}

总结

Dayu200不仅适合设备开发,更适合App开发,配合最新的DevEco Studio 3.0,即使您手头没有设备,也可以进行相对完善的UI开发大部分工作。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
media.zip 4M 35次下载
WorldTouring.zip 22.81M 39次下载
已于2022-11-18 10:24:27修改
3
收藏 1
回复
举报
2条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

老师界面设计的总是那么好看

回复
2022-7-6 10:35:19
入门大师小波哥
入门大师小波哥 回复了 红叶亦知秋
老师界面设计的总是那么好看

必须的老铁

回复
2022-7-6 13:59:18
回复
    相关推荐