[Daily HarmonyOS Next Knowledge] Custom Popup for Sharing, Badge Flicker Fix, etc.
1. How to implement a custom sharing popup?
Requirements:
- A bottom-up sharing panel with two rows, supporting horizontal swiping.
- A base component for bottom popups with customizable content.
Reference Code:
import { BusinessError } from '@ohos.base';
import { ComponentContent } from "@ohos.arkui.node";
import { PromptAction } from '@kit.ArkUI';
class Params {
ApplicationSharings: string[] = [];
Sharings: string[] = [];
promptAction: PromptAction;
numss: number = 0
constructor(ApplicationSharings: string[], Sharings: string[] = [], promptAction: PromptAction, numss: number) {
this.ApplicationSharings = ApplicationSharings;
this.Sharings = Sharings;
this.promptAction = promptAction;
this.numss = numss;
}
}
@Builder
function buildText($$: Params) {
Column() {
Text('网页由mp.xxx.xxx.com提供')
.fontSize(10)
// .fontWeight(FontWeight.Bold)
// .margin({bottom: 36})
Grid() {
ForEach($$.ApplicationSharings, (item: string, index) => {
GridItem() {
Column() {
Image($r('app.media.app_icon'))
.height(50).width(50)
Text(item)
.fontSize(10)
}
}
})
}
.height(100)
.rowsGap(20)
.columnsGap(20)
.scrollBar(BarState.Off)
.rowsTemplate('1fr')
Grid() {
ForEach($$.Sharings, (item: string, index) => {
GridItem() {
Column() {
Image($r('app.media.app_icon'))
.height(50).width(50)
Text(item)
.fontSize(10)
}
}
})
}
.height(100)
.rowsGap(20)
.columnsGap(20)
.scrollBar(BarState.Off)
.rowsTemplate('1fr')
Button('取消')
.width('100%')
.fontColor(Color.Black)
.backgroundColor(Color.White)
.onClick(() => {
/*let sasasa1 = LocalStorage.getShared()?.get('uiContext') as UIContext
let sasasa = LocalStorage.getShared()?.get('PropAA') as ComponentContent<Params>
try {
$$.promptAction.closeCustomDialog(sasasa);
} catch (error) {
let message = (error as BusinessError).message;
let code = (error as BusinessError).code;
console.error(`:::OpenCustomDialog args error code is ${code}, message is ${message}`);
};*/
let link1: SubscribedAbstractProperty<number> = storage.link('PropA');
let numsss = link1.get()
console.log(':::numsss', link1.get())
link1.set(++numsss)
// $$.numss++
// console.log(':::$$.numss',$$.numss)
})
}
.backgroundColor('#FFF0F0F0')
.width('90%')
.height('30%')
.borderRadius(10)
}
let para: Record<string, number> = { 'PropA': 1 };
let storage: LocalStorage = new LocalStorage(para); // Create new instance and initialize with given object
// let globalBuilder: WrappedBuilder<[Params]> = wrapBuilder(buildText);
@Entry(storage)
@Component
struct CustomDialogDemo {
@State message: string = "hello"
@State ApplicationSharings: string[] =
['转发', '群发给客户', '群发到客户群', '分享到同事吧', '收藏', '群发到客户群', '分享到同事吧', '收藏', '刷新',
'翻译', '复制链接', '调整字体', '刷新', '翻译']
@State Sharings: string[] = ['最小化', '复制链接', '调整字体', '刷新', '翻译', '复制链接', '调整字体', '刷新', '翻译']
@LocalStorageLink('PropA') @Watch('onchang') nums: number = 0;
// @State @Watch('onchang') nums :number = 0;
@LocalStorageLink('uiContext') aaa: UIContext = this.getUIContext();
@LocalStorageLink('PropAA') shjsh: ComponentContent<Params> | null =
null //new ComponentContent(this.aaa,wrapBuilder(ssss));
// @LocalStorageLink('PropAA') shjsh:ComponentContent<Params> = new ComponentContent(this.aaa, globalBuilder);
aboutToAppear(): void {
// setInterval(()=>{
// console.log(":::nums",this.nums)
// },1000)
}
onchang() {
console.log('::: onchang')
try {
this.aaa.getPromptAction().closeCustomDialog(this.shjsh);
} catch (error) {
let message = (error as BusinessError).message;
let code = (error as BusinessError).code;
console.error(`OpenCustomDialog args error code is ${code}, message is ${message}`);
}
;
}
build() {
Row() {
Column() {
TextInput()
.id('aaa')
.visibility(Visibility.None)
Button("click me")
.onClick(() => {
let uiContext = this.getUIContext();
let promptAction = uiContext.getPromptAction();
let contentNode = new ComponentContent(uiContext, wrapBuilder(buildText),
new Params(this.ApplicationSharings, this.Sharings, promptAction, this.nums));
this.shjsh = contentNode
try {
promptAction.openCustomDialog(contentNode);
} catch (error) {
let message = (error as BusinessError).message;
let code = (error as BusinessError).code;
console.error(`OpenCustomDialog args error code is ${code}, message is ${message}`);
}
;
})
}
.width('100%')
.height('100%')
}
.height('100%')
}
}
2. Badge flickers when switching between numeric and non-numeric states?
Scenarios causing flickering:
- Switching between Badge with/without a numeric value.
- Toggle Badge visibility.
Solution: Use the onComplete
callback to ensure images load before updating the Badge.
Reference: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/development-intro-api-V5?catalogVersion=V5
Reference Code:
@Entry
@Component
struct BadgeDemo {
@State message: string = 'Hello World';
@State sizes: string = '0'
@State isDnd: boolean = false;
build() {
Row() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(() => {
this.isDnd = !this.isDnd;
})
Stack() {
Badge({
value: '',
position: { x: 40, y: 0 },
style: { badgeSize: 15, badgeColor: Color.Red }
}) {
Image($r('app.media.icon'))
.width(50)
.height(50)
.onComplete(() => {
this.isDnd = !this.isDnd;
})
}
.visibility(this.isDnd ? Visibility.Visible : Visibility.None)
Badge({
count: 98,
maxCount: 99,
position: { x: 30, y: 0 },
style: { fontSize: 15, badgeSize: 15, badgeColor: Color.Red }
}) {
Image($r('app.media.icon'))
.width(50)
.height(50)
}
.visibility(this.isDnd ? Visibility.None : Visibility.Visible)
}
}
.height('100%')
}
}
3. How to delay toggling a switch and its callback?
Current Behavior: The toggle state changes immediately with an instant callback.
Scenario: When turning on a toggle, if an error occurs during the process, resetting the toggle triggers the state change callback unintentionally.
Solution: Use hitTestBehavior
and setTimeout
:
@Entry
@Component
struct Index {
@State isDarkMode: boolean = false
build() {
Column() {
Column() {
Toggle({ type: ToggleType.Switch, isOn: $$this.isDarkMode })
.onChange((isOn: boolean) => {
console.info('Toggle.onChange:isOn' + isOn)
this.isDarkMode = isOn
getContext(this).getApplicationContext().setColorMode(this.isDarkMode ? 0 : 1)
})
}
.hitTestBehavior(HitTestMode.Block)
.onClick(() => {
setTimeout(() => {
this.isDarkMode = !this.isDarkMode
}, 10000)
})
}.width('100%').height('100%').padding(32)
}
}
4. getColorSync(resource)
returns light mode color in dark mode?
Solutions:
- Pass the resource ID directly:
getContext(component).resourceManager.getColorSync($r("app.color.xxx").id)
- Add configuration to
module.json5
in the package with dark mode resources:
"metadata": [
{
"name": "ContextResourceConfigLoadFromParentTemp",
"value": "true"
}
]
5. How to remove tones from pinyin when converting Chinese characters?
Solution: Convert characters to pinyin first, then remove tones:
let transliterator = i18n.Transliterator.getInstance('Any-Latn');
let res = transliterator.transform('中国');
let transliterator2 = i18n.Transliterator.getInstance('Latin-ASCII');
let res2 = transliterator2.transform(res);
Top comments (0)