DEV Community

Cover image for Component Offset, Popup Arrow Color & Bubble Radius, Dynamic Attributes, Scan UI Implementation
kouwei qing
kouwei qing

Posted on

Component Offset, Popup Arrow Color & Bubble Radius, Dynamic Attributes, Scan UI Implementation

【Daily HarmonyOS Next Knowledge】Component Offset, Popup Arrow Color & Bubble Radius, Dynamic Attributes, Scan UI Implementation

1. HarmonyOS popup component offset after page content switching?

interface dataItem {
  title: string;
  price: number;
  price2: number;
}

@Entry
@Component
struct Index {
  @State dataSource: Array<dataItem> = [
    { title: 'AAAAAA', price: 100, price2: 111 },
    { title: 'BBBBBB', price: 299, price2: 398 }
  ];
  @State index: number = 0;
  @State qty: number = 0;
  @State qty2: number = 0;
  @State total: number = 0;
  @State total2: number = 0;
  @State showModal: boolean = false;
  @State showPopup: boolean = false;
  @State showPopup2: boolean = false;

  handleClick(type: string) {
    if (type === 'minus' && this.qty > 0) {
      this.qty -= 1;
      this.total = this.qty * this.dataSource[this.index].price;
      this.showPopup = this.qty > 0;
    } else if (type === 'add') {
      this.qty += 1;
      this.total = this.qty * this.dataSource[this.index].price;
      this.showPopup = this.qty > 0;
    }
  }

  handleClick2(type: string) {
    if (type === 'minus' && this.qty2 > 0) {
      this.qty2 -= 1;
      this.total2 = this.qty2 * this.dataSource[this.index].price2;
      this.showPopup2 = this.qty2 > 0;
    } else if (type === 'add') {
      this.qty2 += 1;
      this.total2 = this.qty2 * this.dataSource[this.index].price2;
      this.showPopup2 = this.qty2 > 0;
    }
  }

  @Builder
  modalBuilder() {
    Column() {
      ForEach(this.dataSource, (item: dataItem, index: number) => {
        Text(item.title)
          .width('90%')
          .height(50)
          .textAlign(TextAlign.Center)
          .border({ width: 1 })
          .margin({ bottom: 10 })
          .onClick(() => {
            this.index = index;
            this.total = this.qty * this.dataSource[this.index].price;
            this.total2 = this.qty2 * this.dataSource[this.index].price2;
            this.showModal = false;
          })
      }, (item: dataItem, index: number) => {
        return item.title;
      })
    }
    .padding({ top: 100 })
    .width('100%')
    .height('100%')
    .backgroundColor(Color.White)
  }

  @Builder
  popupBuilder(type: number) {
    Column() {
      Text(String(type === 1 ? this.total : this.total2))
        .fontSize(11)
        .fontColor(Color.White)
        .padding({
          top: 1,
          bottom: 1,
          left: 12,
          right: 12
        })
        .backgroundColor(Color.Black)
    }
  }

  build() {
    Column() {
      Row() {
        Text(this.dataSource[this.index].title)
      }
      .height(50)
      .width('90%')
      .justifyContent(FlexAlign.Center)
      .border({ width: 1 })
      .bindSheet(this.showModal, this.modalBuilder(), {
        height: 300,
        dragBar: false
      })
      .onClick(() => {
        this.showModal = !this.showModal;
      })

      Column() {
        Row() {
          Text('-')
            .width(30)
            .height(30)
            .backgroundColor(Color.Red)
            .fontColor(Color.White)
            .textAlign(TextAlign.Center)
            .onClick(() => this.handleClick('minus'))
          Text(String(this.total))
            .height(30)
            .border({ width: 1, color: Color.Red })
            .width(60)
            .textAlign(TextAlign.Center)
          Text('+')
            .width(30)
            .height(30)
            .backgroundColor(Color.Red)
            .fontColor(Color.White)
            .textAlign(TextAlign.Center)
            .onClick(() => this.handleClick('add'))
        }
        .margin({ bottom: 20 })
        .bindPopup(this.showPopup, {
          builder: this.popupBuilder(1),
          popupColor: Color.Black,
          placement: Placement.Top,
          autoCancel: false,
          radius: 1,
          mask: false,
          arrowWidth: 8,
          arrowHeight: 6,
          shadow: ShadowStyle.OUTER_DEFAULT_XS
        })

        Row() {
          Text('-')
            .width(30)
            .height(30)
            .backgroundColor(Color.Red)
            .fontColor(Color.White)
            .textAlign(TextAlign.Center)
            .onClick(() => this.handleClick2('minus'))
          Text(String(this.total2))
            .height(30)
            .border({ width: 1, color: Color.Red })
            .width(60)
            .textAlign(TextAlign.Center)
          Text('+')
            .width(30)
            .height(30)
            .backgroundColor(Color.Red)
            .fontColor(Color.White)
            .textAlign(TextAlign.Center)
            .onClick(() => this.handleClick2('add'))
        }
        .bindPopup(this.showPopup2, {
          builder: this.popupBuilder(2),
          popupColor: Color.Black,
          placement: Placement.Top,
          autoCancel: false,
          radius: 1,
          mask: false,
          arrowWidth: 8,
          arrowHeight: 6,
          shadow: ShadowStyle.OUTER_DEFAULT_XS
        })
      }
      .alignItems(HorizontalAlign.Start)
      .width('100%')
      .padding(20)
    }
    .width('100%')
    .height('100%')
    .padding({ top: 50 })
  }
}
Enter fullscreen mode Exit fullscreen mode

2. How to set arrow color and bubble content radius when using HarmonyOS bindPopup?

  • radius: '10vp' // Set bubble corner radius
  • backgroundBlurStyle: BlurStyle.NONE // Set arrow color, associated with the popupColor attribute

Demo reference:

@Entry
@Component
struct BindPopupDemo {
  @State customPopup: boolean = false;

  @Builder
  popupBuilder() {
    Column({ space: 2 }) {
      Row().width(64)
        .height(64)
        .backgroundColor(0x409eff)
      Text('Popup')
        .fontSize(10)
        .fontColor(Color.White)
    }
    .justifyContent(FlexAlign.SpaceAround)
    .width(100)
    .height(100)
    .padding(5)
  }

  @Builder
  customBubbleInstructionBuilder() {
    Stack() {
      Text() {
        Span("2021年12月20日-2022月1日30日每人限购8件  已购买3件,还可购5件").fontSize(12)
        Span(" 已购买3件,还可购5件").fontSize(14)
      }.fontColor(Color.White)
      .maxLines(2).textOverflow({ overflow: TextOverflow.Ellipsis }).ellipsisMode(EllipsisMode.END)
    }.backgroundColor(0x409eff)
    .width(100)
    .padding({
      left: 12,
      right: 12,
      top: 18,
      bottom: 8
    })
  }

  build() {
    Column() {
      Button('click')
        .onClick(() => {
          this.customPopup = !this.customPopup;
        })
        .backgroundColor(0xf56c6c)
        .bindPopup(this.customPopup, {
          builder: this.customBubbleInstructionBuilder,
          placement: Placement.Top,
          maskColor: 0x33000000,
          popupColor: 0xf56c6c,
          enableArrow: true,
          radius: '10vp',
          backgroundBlurStyle: BlurStyle.NONE,
          onStateChange: (e) => {
            if (!e.isVisible) {
              this.customPopup = false;
            }
          }
        })
    }
    .justifyContent(FlexAlign.Center)
    .width('100%')
    .height(437)
  }
}
Enter fullscreen mode Exit fullscreen mode

3. Usage of HarmonyOS NativeXComponent?

Reference document: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/_o_h___native_x_component-V5

Native XComponent describes the surface and touch events held by ArkUI XComponent, which can be used for EGL/OpenGLES and media data input, and displayed on ArkUI XComponent.

4. HarmonyOS new TextAttribute() causes a crash with the error "TextAttribute is not defined"?

@Component
export struct IconFontView {
  @Prop content: string | null = null;
  @Prop iconModifier: TextAttribute = new TextAttribute();
 private textModifier: TextModifier = new TextModifier(this.iconModifier);
Enter fullscreen mode Exit fullscreen mode

The above code compiles successfully but errors at runtime.

Incorrect usage of TextAttribute. Modify as follows (refer to documentation for usage):

Document link: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-universal-attributes-attribute-modifier-V5

Refer to the usage of buttonAttribute:

class MyButtonModifier implements AttributeModifier<ButtonAttribute> {
  isDark: boolean = false
  applyNormalAttribute(instance: ButtonAttribute): void {
    if (this.isDark) {
      instance.backgroundColor(Color.Black)
    } else {
      instance.backgroundColor(Color.Red)
    }
  }
}

@Entry
@Component
struct attributeDemo {
  @State modifier: MyButtonModifier = new MyButtonModifier()

  build() {
    Row() {
      Column() {
        Button("Button")
          .attributeModifier(this.modifier)
          .onClick(() => {
            this.modifier.isDark = !this.modifier.isDark
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}
Enter fullscreen mode Exit fullscreen mode

5. How to implement HarmonyOS ArkTS scan UI?

@Entry
@Component
struct Page240419172038091_bak {
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
  private screenCenterX: number = 0
  private screenCenterY: number = 0
  @State sCanLineY: number = 0

  build() {
    Stack({ alignContent: Alignment.Center }) {
      Image($r("app.media.bg")).width(200)
      Canvas(this.context).width("100%").height("100%").backgroundColor(Color.Transparent).onReady(() => {
        let canvasWidth = this.context.width
        let canvasHeight = this.context.height
        this.screenCenterX = canvasWidth / 2
        this.screenCenterY = canvasHeight / 2
        this.context.fillStyle = "#80000000"
        this.context.beginPath()
        this.context.moveTo(0, 0)
        this.context.lineTo(0, this.context.height)
        this.context.lineTo(this.context.width, this.context.height)
        this.context.lineTo(this.context.width, 0)
        this.context.lineTo(0, 0)
        this.context.fill()
        this.context.clearRect(this.screenCenterX - 100, this.screenCenterY - 100, 200, 200)
        this.context.beginPath();
        this.context.moveTo(this.screenCenterX, this.screenCenterY)
        this.context.fillStyle = "#802ac327";
        this.context.fillRect(this.screenCenterX - 100, this.screenCenterY - 100, 200, 2)
        setInterval(() => {
          this.context.clearRect(this.screenCenterX - 100, this.screenCenterY - 100, 200, 200)
          if (this.sCanLineY > 197) {
            this.sCanLineY = 0
          } else {
            this.sCanLineY++
          }
          this.context.fillRect(this.screenCenterX - 100, this.screenCenterY - 100 + this.sCanLineY, 200, 2)
        }, 8)
      })
    }.width("100%").height("100%")
  }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)