#DAYU200体验官# 生鲜配送App 原创 精华

入门大师小波哥
发布于 2022-7-5 11:37
浏览
3收藏

目录

主题

本帖使用Dayu200为开发板,展示一个在线生鲜配送的App首页。

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

设计效果图

首页上半部分:
 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区

首页下半部分:
 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区

Dayu200的预览配置

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

资源导入

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

首页结构

在新建工程时,选中“Tablet(平板)”作为默认显示设备,虽然手机页面与大屏网页区别比较大,其实布局结构思路上并不需要实质性的改变。
使用既有的index.ets入口页作为首页,分析页面的层次结构,可按上中下3个部分依次入列,即Column布局。
网页上部分有导航,直觉上属于上部分,不过由于网页比较长用户可以向下滑动,大部分实际应用场景中导航能随着用户滑动到下半部分而保持在顶部,灵活起见可将导航放在整个页面层次结构之上。
依此思路布局的话,代码上整体是一个Stack,内容部分是Column结构,结构骨架代码如下:

Stack { //堆叠结构

	Column(){  //内容列

	Top()  //上

	Mid()  //中

	Bottom() //下

	}

      Nav() //导航菜单

}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

导航

导航本身内容在一行之内,不过由于有一个锐利的光源垂直照射阴影效果,依照设计,依旧要在其下放置一个略短的同类型结构,背景色略淡。
依此思路布局的话,代码上整体是一个Stack,内容部分是Row结构,结构骨架代码如下:

Stack { //堆叠结构

     Shadow() //阴影


	Row(){  //内容列

	Left()  //左

	Center()  //中

	Right() //右

	}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

要创建组件,依照惯例,在pages目录下新建源码文件nav.ets。

阴影层

阴影层相对于菜单的背景层透明度为0.5,并有20的圆角。

Column() {
      }
      .width(750)
      .height(150)
      .backgroundColor('#1F242B')
      .borderRadius(20)
      .opacity(0.5)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区

菜单层

为了制造出阴影的效果,将菜单层的位置往垂直方向(y轴)上再上移20。

Row() {
      }
      .width(800)
      .height(150)
      .backgroundColor('#1F242B')
      .borderRadius(20)
      .offset({
        y: -20
      })
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区

菜单阴影效果

将上述2个层合并置于Stack内,形成阴影效果,代码如下:

Stack() {

      Column() {
      }
      .width(750)
      .height(150)
      .backgroundColor('#1F242B')
      .borderRadius(20)
      .opacity(0.5)

      Row() {
      }
      .width(800)
      .height(150)
      .backgroundColor('#1F242B')
      .borderRadius(20)
      .offset({
        y: -20
      })

    }
    .width('100%')
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区

菜单内容

菜单内容左侧是一个开关图标,距离菜单左侧边距为40:

Image($r("app.media.toggle"))
          .width(64)
          .height(39)
          .margin({left:40})
  • 1.
  • 2.
  • 3.
  • 4.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区

中间的文字单独组成一行,间距20,宽度设为总宽度的60%:

Row({space: 20}) {

          Blank()

          Text('首页')
            .fontSize(20)
            .fontColor(Color.White)

          Text('关于')
            .fontSize(20)
            .fontColor(Color.White)

          Text('菜单')
            .fontSize(20)
            .fontColor(Color.White)

          Text('主厨')
            .fontSize(20)
            .fontColor(Color.White)

          Text('文化')
            .fontSize(20)
            .fontColor(Color.White)

          Blank()

        }
        .width('60%')
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区
菜单层最右侧是一个红色大按钮,距离菜单最右侧边距为40,这样与左侧图标的40左边距形成对称:

Button() {
          Text('联系我们')
            .fontColor(Color.White)
            .fontSize(20)
        }
        .width(170)
        .height(58)
        .backgroundColor('#FF5146')
        .borderRadius(7)
        .type(ButtonType.Normal)
	.margin(right:40)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区

完整代码

再给3个之间插入空白,导航栏的整体代码如下:

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

    Column () {
      Stack() {

        Column() {
        }
        .width(900)
        .height(90)
        .backgroundColor('#1F242B')
        .borderRadius(20)
        .opacity(0.5)

        Row() {

          Image($r("app.media.toggle"))
            .width(64)
            .height(35)
            .objectFit(ImageFit.Contain)
            .margin({left:40})

          Blank()

          Row({space: 20}) {

            Blank()

            Text('首页')
              .fontSize(15)
              .fontColor(Color.White)

            Text('关于')
              .fontSize(15)
              .fontColor(Color.White)

            Text('菜单')
              .fontSize(15)
              .fontColor(Color.White)

            Text('主厨')
              .fontSize(15)
              .fontColor(Color.White)

            Text('文化')
              .fontSize(15)
              .fontColor(Color.White)

            Blank()

          }
          .width('60%')

          Blank()

          Button() {
            Text('联系我们')
              .fontColor(Color.White)
              .fontSize(14)
          }
          .width(170)
          .height(45)
          .backgroundColor('#FF5146')
          .borderRadius(7)
          .type(ButtonType.Normal)
          .margin({right:40})

        }
        .width(950)
        .height(100)
        .backgroundColor('#1F242B')
        .borderRadius(20)
        .padding({top: 20})
        .offset({
          y: -20
        })

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


  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.

上半部分

上半部分页面看起来层次非常丰富,这对布局也提出了更高的要求。不过无论层次有多丰富,都可以通过行列和层互相交错堆叠来实现。
要创建组件,依照惯例,在pages目录下新建源码文件up.ets。
笔者选择的整体骨架结构,依旧沿用Stack分层,每一层使用Column或Row来继续分解:

Stack {   //页面上半部分

	Back() //背景图片层

	Theme() //主题文字层

}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

背景图片层

背景图片层有3个交错的图片,最底层的是左侧的曲线状填充:

Stack() {

      Row() {

        Image($r("app.media.leftTopMask"))
          .width(703)
          .objectFit(ImageFit.Fill)

        Blank()

      }
      .width('100%')

    }
    .width('100%')
    .height('100%')
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区
但是对比设计图,观察到图片并不是完全显示,而是往左侧有一定的偏移:

Stack() {

      Row() {

        Image($r("app.media.leftTopMask"))
          .width(703)
          .objectFit(ImageFit.Fill)
	.offset({x: -150})

        Blank()

      }
      .width('100%')

    }
    .width('100%')
    .height('100%')
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

添加偏移后的预览:
 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区

右侧的蔬菜水果图片左侧有一部分覆盖在最底层图片之上:

 Row() {

        Blank()

        Image($r("app.media.cover"))
          .width(649)
          .objectFit(ImageFit.Fill)

      }
      .width('100%')
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区
在这两个图层之上,还有一个认证徽章小图:

Column() {

        Image($r("app.media.cert"))
          .width(134)
          .objectFit(ImageFit.Contain)

      }
      .width('100%')
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区
对比设计图,图片需要左上有一定的偏移:

Column() {

        Image($r("app.media.cert"))
          .width(134)
          .objectFit(ImageFit.Contain)
          .offset({x: -150, y: -150})

      }
      .width('100%')
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区
背景图片层整体还需要主题色背景,蔬菜图片高度需要有左侧曲线块一致:

Stack() {

      Row() {

        Image($r("app.media.leftTopMask"))
          .width(703)
          .objectFit(ImageFit.Fill)
          .offset({x: -150})

        Blank()

      }
      .width('100%')

      Row() {

        Blank()

        Image($r("app.media.cover"))
          .width(649)
          .objectFit(ImageFit.Fill)
          .margin(top:120)

      }
      .width('100%')


      Column() {

        Image($r("app.media.cert"))
          .width(134)
          .objectFit(ImageFit.Contain)
          .offset({x: -150, y: -150})

      }
      .width('100%')

    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F9F4E5')
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区

主题文字层

网页的主题文字列的布局非常简单,注意其中的“超快”和“配送”因为颜色不同,所以拆分成2段不同的Text组合在一行之内:

 Column() {

        Text('轻松追踪物流')
          .fontSize(14)
          .fontColor('#FF5146')

        Row() {

          Text('超快')
            .fontSize(40)

          Text('配送')
            .fontSize(40)
            .fontColor('#FF5146')
        }

        Text('&')
          .fontSize(40)

        Text('直送上门')
          .fontSize(40)

        Text("无论您身在任何一个城市,24小时内蔬菜瓜果、\n肉食禽蛋,我们都将风雨无阻,细致送达。\n100%新鲜,100%有机,100%源头")
          .fontSize(14)
          .fontWeight(FontWeight.Lighter)
          .padding(top: 20)

      }
      .alignItems(HorizontalAlign.Start)
      .padding(left: 60)
      .width('100%')
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区

文字列下方是一行内2个按钮,第一个搜索按钮的文字覆盖在按钮背景之上:

Row() {

            Image($r("app.media.search"))
              .height(17)
              .width(17)
              .objectFit(ImageFit.Contain)
              .margin({right: 20})

            Text('查找分店')
              .fontColor(Color.White)

          }
          .borderRadius(27)
          .height(40)
          .backgroundColor('#FF5146')
          .width(160)
          .padding({left: 20})
          .margin({top: 30})
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区
与搜索按钮在同一行内右侧的是下单按钮,下单按钮左侧有一个播放图片:

Row() {

            Image($r("app.media.play"))
              .height(45)
              .width(45)
              .objectFit(ImageFit.Contain)

            Text('如何下单?')

          }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区
播放按钮正常布局,将其放在按钮组内,并且加上按钮阴影效果:

Row({space: 15}) {

          Row() {

            Image($r("app.media.search"))
              .height(17)
              .width(17)
              .objectFit(ImageFit.Contain)
              .margin({right: 20, left: 20})


            Text('查找分店')
              .fontColor(Color.White)

          }
          .borderRadius(27)
          .height(40)
          .backgroundColor('#FF5146')
          .width(160)
          .shadow({
            radius: 20,
            offsetX: 5,
            offsetY: 5,
            color: Color.Gray,
          })
          
          Row() {

            Image($r("app.media.play"))
              .height(45)
              .width(45)
              .objectFit(ImageFit.Contain)

            Text('如何下单?')

          }

        }
        .margin(top: 30)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区

右侧指示图片层

在蔬菜图片的上方有一个指示图片,想要指示图片到达指定的水果位置,需要同时调整它的容器,即列在水平和垂直方向的偏移量(offset):

Column() {

        Image($r("app.media.target"))
          .objectFit(ImageFit.Contain)
          .width(260)
          .height(150)

      }
      .alignItems(HorizontalAlign.End)
      .offset({x: -125, y: -130})
      .width('100%')
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区

完整代码和效果

至此,上半部分所有组成子组件已经完成,把它们组合起来,up.ets完整代码如下:

import Nav from './nav.ets'

@Entry
@Component
struct Up {
  build() {

    Stack() {

      Stack() {

        Row() {

          Image($r("app.media.leftTopMask"))
            .width(703)
            .objectFit(ImageFit.Fill)
            .offset({x: -150})

          Blank()

        }
        .width('100%')

        Row() {

          Blank()

          Image($r("app.media.cover"))
            .width(649)
            .objectFit(ImageFit.Fill)
            .margin({top:120})

        }
        .width('100%')


        Column() {

          Image($r("app.media.cert"))
            .width(134)
            .objectFit(ImageFit.Contain)
            .offset({x: -150, y: -150})

        }
        .width('100%')

      }
      .width('100%')
      .height('100%')
      .backgroundColor('#F9F4E5')

      Column() {

        Text('轻松追踪物流')
          .fontSize(14)
          .fontColor('#FF5146')

        Row() {

          Text('超快')
            .fontSize(40)

          Text('配送')
            .fontSize(40)
            .fontColor('#FF5146')
        }

        Text('&')
          .fontSize(40)

        Text('直送上门')
          .fontSize(40)

        Text("无论您身在任何一个城市,24小时内蔬菜瓜果、\n肉食禽蛋,我们都将风雨无阻,细致送达。\n100%新鲜,100%有机,100%源头")
          .fontSize(14)
          .fontWeight(FontWeight.Lighter)
          .padding({top: 20})


        Row({space: 15}) {

          Row() {

            Image($r("app.media.search"))
              .height(17)
              .width(17)
              .objectFit(ImageFit.Contain)
              .margin({right: 20, left: 20})


            Text('查找分店')
              .fontColor(Color.White)

          }
          .borderRadius(27)
          .height(40)
          .backgroundColor('#FF5146')
          .width(160)
          .shadow({
            radius: 20,
            offsetX: 5,
            offsetY: 5,
            color: Color.Gray,
          })

          Row() {

            Image($r("app.media.play"))
              .height(45)
              .width(45)
              .objectFit(ImageFit.Contain)

            Text('如何下单?')

          }

        }
        .margin({top: 30})



      }
      .alignItems(HorizontalAlign.Start)
      .padding({left: 60})
      .width('100%')

      Column() {

        Image($r("app.media.target"))
          .objectFit(ImageFit.Contain)
          .width(260)
          .height(150)

      }
      .alignItems(HorizontalAlign.End)
      .offset({x: -125, y: -130})
      .width('100%')

      Nav()

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

  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.

中间部分

中间部分比较简单,一系列友情链接网站的logo图片,均匀占据一行之内的空间。要创建新组件,在pages下新建mid.ets,代码如下:

@Entry
@Component
export default struct Mid {

  build() {

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

      Image($r("app.media.partner1"))
        .width(249)
        .height(110)
        .objectFit(ImageFit.Fill)

      Image($r("app.media.partner2"))
        .width(249)
        .height(110)
        .objectFit(ImageFit.Fill)

      Image($r("app.media.partner3"))
        .width(249)
        .height(110)
        .objectFit(ImageFit.Fill)

      Image($r("app.media.partern4"))
        .width(249)
        .height(110)
        .objectFit(ImageFit.Fill)

    }
    .width('100%')
    .height('25%')
    .padding(40)

  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区

下半部分

下半部分是一系列的甜甜圈卡片列表,均匀占据一行之内的空间。要创建新组件,在pages下新建bottom.ets。

卡片结构

单个卡片是由背景层和内容层叠加而成,其中内容层为3个组件组成的一列。

Stack {

	Image()

	Column() {
	
	Image()

	Text()

	Button()

	}	

}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区

卡片背景

把卡片背景图至于卡片容器Stack的最底层:

Stack() {

        Image($r("app.media.donutMask"))
          .width(341)
          .height(476)
          .objectFit(ImageFit.Contain)

      }
      .borderRadius(20)
      .backgroundColor('#DC7CFF')
      .width(341)
      .height(476)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区
发现图片左侧并未与容器最左侧对齐,遇到这种情况可以将图片包含在一个Row容器中,并缩短图片宽度,右侧加入Blank组件,以求与设计图一致,代码优化如下:

Stack() {

        Row() {

          Image($r("app.media.donutMask"))
            .width(300)
            .height(476)
            .objectFit(ImageFit.Fill)

          Blank()

        }
        .width('100%')


      }
      .borderRadius(20)
      .backgroundColor('#DC7CFF')
      .width(341)
      .height(476)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区

卡片内容

卡片内容的布局在一列之中,注意按钮的阴影效果,以及适当调整间距:

Column() {

          Image($r("app.media.donut"))
            .width(229)
            .height(182)
            .objectFit(ImageFit.Contain)

          Blank()

          Text('蓝莓甜甜圈')
            .fontSize(32)
            .fontColor(Color.White)
            .fontWeight(FontWeight.Bold)

          Blank()

          Button(){
            Text('5折大酬宾')
              .fontSize(18)
              .margin({
                left: 40,
                right: 40,
                top: 15,
                bottom: 15}
              )
          }
            .type(ButtonType.Normal)
            .backgroundColor(Color.White)
            .borderRadius(10)
            .width(232)
            .height(60)
            .shadow({
              radius: 25,
              color: Color.Gray}
            )

}
.height('80%')
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区
参照第一张卡片来构建第二张卡片:

Stack() {

        Row() {

          Image($r("app.media.donutMask"))
            .width(300)
            .height(476)
            .objectFit(ImageFit.Fill)

          Blank()

        }
        .width('100%')

        Column() {

          Image($r("app.media.donut"))
            .width(229)
            .height(182)
            .objectFit(ImageFit.Contain)

          Blank()

          Text('巧克力甜甜圈')
            .fontSize(32)
            .fontColor(Color.White)
            .fontWeight(FontWeight.Bold)

          Blank()

          Button(){
            Text('5折大酬宾')
              .fontSize(18)
              .margin({
                left: 40,
                right: 40,
                top: 15,
                bottom: 15}
              )
          }
          .type(ButtonType.Normal)
          .backgroundColor(Color.White)
          .borderRadius(10)
          .width(232)
          .height(60)
          .shadow({
            radius: 25,
            color: Color.Gray}
          )

        }
        .height('80%')

      }
      .borderRadius(20)
      .backgroundColor('#7CD8FF')
      .width(341)
      .height(476)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区

第三张卡片的代码:

Stack() {

        Row() {

          Image($r("app.media.donutMask"))
            .width(300)
            .height(476)
            .objectFit(ImageFit.Fill)

          Blank()

        }
        .width('100%')

        Column() {

          Image($r("app.media.donut"))
            .width(229)
            .height(182)
            .objectFit(ImageFit.Contain)

          Blank()

          Text('草莓甜甜圈')
            .fontSize(32)
            .fontColor(Color.White)
            .fontWeight(FontWeight.Bold)

          Blank()

          Button(){
            Text('4折大酬宾')
              .fontSize(18)
              .margin({
                left: 40,
                right: 40,
                top: 15,
                bottom: 15}
              )
          }
          .type(ButtonType.Normal)
          .backgroundColor(Color.White)
          .borderRadius(10)
          .width(232)
          .height(60)
          .shadow({
            radius: 25,
            color: Color.Gray}
          )

        }
        .height('80%')

      }
      .borderRadius(20)
      .backgroundColor('#BAFF7C')
      .width(341)
      .height(476)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区

卡片列表

把上面的3张卡片放入一行之中:

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

        Stack() {

          Row() {

            Image($r("app.media.donutMask"))
              .width(280)
              .height(400)
              .objectFit(ImageFit.Fill)

            Blank()

          }
          .width('100%')

          Column() {

            Image($r("app.media.donut"))
              .width(200)
              .height(160)
              .objectFit(ImageFit.Contain)

            Blank()

            Text('蓝莓甜甜圈')
              .fontSize(25)
              .fontColor(Color.White)
              .fontWeight(FontWeight.Bold)

            Blank()

            Button(){
              Text('5折大酬宾')
                .fontSize(15)
                .margin({
                  left: 40,
                  right: 40,
                  top: 15,
                  bottom: 15
                })
            }
            .type(ButtonType.Normal)
            .backgroundColor(Color.White)
            .borderRadius(10)
            .width(220)
            .height(50)
            .shadow({
              radius: 25,
              color: Color.Gray
            })

          }
          .height('80%')

        }
        .borderRadius(20)
        .backgroundColor('#DC7CFF')
        .width(280)
        .height(400)
        .margin(10)

        Stack() {

          Row() {

            Image($r("app.media.donutMask"))
              .width(280)
              .height(400)
              .objectFit(ImageFit.Fill)

            Blank()

          }
          .width('100%')

          Column() {

            Image($r("app.media.donut"))
              .width(200)
              .height(160)
              .objectFit(ImageFit.Contain)

            Blank()

            Text('蓝莓甜甜圈')
              .fontSize(25)
              .fontColor(Color.White)
              .fontWeight(FontWeight.Bold)

            Blank()

            Button(){
              Text('5折大酬宾')
                .fontSize(15)
                .margin({
                  left: 40,
                  right: 40,
                  top: 15,
                  bottom: 15
                })
            }
            .type(ButtonType.Normal)
            .backgroundColor(Color.White)
            .borderRadius(10)
            .width(220)
            .height(50)
            .shadow({
              radius: 25,
              color: Color.Gray
            })

          }
          .height('80%')

        }
        .borderRadius(20)
        .backgroundColor('#7CD8FF')
        .width(280)
        .height(400)
        .margin(10)

        Stack() {

          Row() {

            Image($r("app.media.donutMask"))
              .width(280)
              .height(400)
              .objectFit(ImageFit.Fill)

            Blank()

          }
          .width('100%')

          Column() {

            Image($r("app.media.donut"))
              .width(200)
              .height(160)
              .objectFit(ImageFit.Contain)

            Blank()

            Text('草莓甜甜圈')
              .fontSize(25)
              .fontColor(Color.White)
              .fontWeight(FontWeight.Bold)

            Blank()

            Button(){
              Text('4折大酬宾')
                .fontSize(15)
                .margin({
                  left: 40,
                  right: 40,
                  top: 15,
                  bottom: 15
                })
            }
            .type(ButtonType.Normal)
            .backgroundColor(Color.White)
            .borderRadius(10)
            .width(220)
            .height(50)
            .shadow({
              radius: 25,
              color: Color.Gray
            })

          }
          .height('80%')

        }
        .borderRadius(20)
        .backgroundColor('#BAFF7C')
        .width(280)
        .height(400)
        .margin(10)

      }
      .width('100%')
      .height('100%')
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区

卡片列表容器背景

需要加上整个卡片列表的背景色和背景图:

Stack() {

      Row() {

        Blank()

        Image($r("app.media.rightBottomMask"))
          .width(703)
          .objectFit(ImageFit.Fill)
          .offset(x: 150)

      }
      .width('100%')
    }
    .width('100%')
    .height('80%')
    .backgroundColor('#F9F4E5')
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区

完整组件代码和预览效果

考虑到卡片实际预览之间没有空隙,需要缩小卡片大小。bottom.ets完整源文件:

@Entry
@Component
export default struct Bottom {
  build() {
    Stack() {

      Row() {

        Blank()

        Image($r("app.media.rightBottomMask"))
          .width(703)
          .objectFit(ImageFit.Fill)
          .offset({x: 150})

      }
      .width('100%')

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

        Stack() {

          Row() {

            Image($r("app.media.donutMask"))
              .width(280)
              .height(400)
              .objectFit(ImageFit.Fill)

            Blank()

          }
          .width('100%')

          Column() {

            Image($r("app.media.donut"))
              .width(200)
              .height(160)
              .objectFit(ImageFit.Contain)

            Blank()

            Text('蓝莓甜甜圈')
              .fontSize(25)
              .fontColor(Color.White)
              .fontWeight(FontWeight.Bold)

            Blank()

            Button(){
              Text('5折大酬宾')
                .fontSize(15)
                .margin({
                  left: 40,
                  right: 40,
                  top: 15,
                  bottom: 15
                })
            }
            .type(ButtonType.Normal)
            .backgroundColor(Color.White)
            .borderRadius(10)
            .width(220)
            .height(50)
            .shadow({
              radius: 25,
              color: Color.Gray
            })

          }
          .height('80%')

        }
        .borderRadius(20)
        .backgroundColor('#DC7CFF')
        .width(280)
        .height(400)
        .margin(10)

        Stack() {

          Row() {

            Image($r("app.media.donutMask"))
              .width(280)
              .height(400)
              .objectFit(ImageFit.Fill)

            Blank()

          }
          .width('100%')

          Column() {

            Image($r("app.media.donut"))
              .width(200)
              .height(160)
              .objectFit(ImageFit.Contain)

            Blank()

            Text('蓝莓甜甜圈')
              .fontSize(25)
              .fontColor(Color.White)
              .fontWeight(FontWeight.Bold)

            Blank()

            Button(){
              Text('5折大酬宾')
                .fontSize(15)
                .margin({
                  left: 40,
                  right: 40,
                  top: 15,
                  bottom: 15
                })
            }
            .type(ButtonType.Normal)
            .backgroundColor(Color.White)
            .borderRadius(10)
            .width(220)
            .height(50)
            .shadow({
              radius: 25,
              color: Color.Gray
            })

          }
          .height('80%')

        }
        .borderRadius(20)
        .backgroundColor('#7CD8FF')
        .width(280)
        .height(400)
        .margin(10)

        Stack() {

          Row() {

            Image($r("app.media.donutMask"))
              .width(280)
              .height(400)
              .objectFit(ImageFit.Fill)

            Blank()

          }
          .width('100%')

          Column() {

            Image($r("app.media.donut"))
              .width(200)
              .height(160)
              .objectFit(ImageFit.Contain)

            Blank()

            Text('草莓甜甜圈')
              .fontSize(25)
              .fontColor(Color.White)
              .fontWeight(FontWeight.Bold)

            Blank()

            Button(){
              Text('4折大酬宾')
                .fontSize(15)
                .margin({
                  left: 40,
                  right: 40,
                  top: 15,
                  bottom: 15
                })
            }
            .type(ButtonType.Normal)
            .backgroundColor(Color.White)
            .borderRadius(10)
            .width(220)
            .height(50)
            .shadow({
              radius: 25,
              color: Color.Gray
            })

          }
          .height('80%')

        }
        .borderRadius(20)
        .backgroundColor('#BAFF7C')
        .width(280)
        .height(400)
        .margin(10)

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

    }
    .width('100%')
    .height('80%')
    .backgroundColor('#F9F4E5')

  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
  • 191.
  • 192.
  • 193.
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.
  • 206.
  • 207.
  • 208.
  • 209.
  • 210.
  • 211.
  • 212.
  • 213.
  • 214.
  • 215.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区

下半屏预览

设计中中间与下半部分加起来相当于上半部分的比例是1:1,即占据整个屏幕的宽和高,为了测试期间,讲中间部分与下半部分做一个组合,来查看实际的半屏效果。
在pages下新建一个secondhalf.ets,导入mid.ets和bottom.ets,将两者组合到一列中:

import Mid from './mid.ets'
import Bottom from './bottom.ets'

@Entry
@Component
struct Secondhalf {
  build() {
    Flex({
      direction: FlexDirection.Column,
      alignItems: ItemAlign.Center,
      justifyContent: FlexAlign.Center
    }) {
      Mid()
      Bottom()
    }
    .width('100%')
    .height('100%')
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

 #DAYU200体验官# 生鲜配送App-鸿蒙开发者社区

总结

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

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
media.zip 1.88M 26次下载
FoodDelivery.zip 7.38M 43次下载
已于2022-7-6 12:03:09修改
6
收藏 3
回复
举报
6
3
3
3条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

老师的布局还是很漂亮的!

回复
2022-7-5 15:00:22
W⃰H⃰B⃰
W⃰H⃰B⃰

还得是我波神啊

回复
2022-7-6 10:10:14
入门大师小波哥
入门大师小波哥 回复了 W⃰H⃰B⃰
还得是我波神啊

一起学习兄弟

回复
2022-7-6 14:00:11


回复
    相关推荐