HarmonyOS 鸿蒙Next 限启动页、权限使用说明、权限管理、嵌套滚动Demo请求
HarmonyOS 鸿蒙Next 限启动页、权限使用说明、权限管理、嵌套滚动Demo请求
嵌套滚动demo:
@Entry
@Component
struct StickyNestedScroll {
@Styles
listCard() {
.backgroundColor(Color.White)
.height(72)
.width("100%")
.borderRadius(12)
}
@State textOffset: number = 0
@State textMargin: number = 0
scroller: Scroller = new Scroller()
@State swiperOffset: number = 0
@State top: number = 100
@State visible: boolean = false
@State visible1: Visibility = Visibility.Visible
@State number1: number = 0
@State XiDing: boolean = false
private swiperController: SwiperController = new SwiperController()
private data: MyDataSource = new MyDataSource([])
private data1: MyDataSource = new MyDataSource([])
private scrollerForScroll: Scroller = new Scroller()
@Builder
SwiperItem(item: string) {
Column(){
Text(item.toString())
.width('100%')
.height("100%")
.backgroundColor(0xAFEEEE)
.textAlign(TextAlign.Center)
.fontSize(30)
}.width('100%')
.height(80)
.margin({ left: 5, right: 5 })
.backgroundColor(Color.White)
}
@Builder
SwiperItem1(item: string) {
Column(){
Text(item.toString())
.width('100%')
.height("100%")
.backgroundColor('#fff')
.textAlign(TextAlign.Center)
.fontSize(30)
}.width('100%')
.height(50)
.margin({ left: 5, right: 5 })
.backgroundColor(Color.White)
}
build() {
Column() {
TextInput({ placeholder: 'input your word...' })
.width('95%')
.height(40)
.margin(10)
// swiper组件在屏幕中完全不可见时的逻辑
if (this.visible) {
Swiper(this.swiperController) {
LazyForEach(this.data, (item: string) => {
this.SwiperItem1(item)
}, (item: string) => item)
}
.displayCount(5)
.indicator(false)
.autoPlay(false)
.cachedCount(2)
.index(1)
.itemSpace(0)
.curve(Curve.Linear)
}
Scroll(this.scrollerForScroll) {
Column() {
Swiper(this.swiperController) {
LazyForEach(this.data, (item: string) => {
this.SwiperItem(item)
}, (item: string) => item)
}
.margin({top: this.swiperOffset})
.displayCount(5)
.indicator(false)
.autoPlay(false)
.cachedCount(2)
.index(1)
.itemSpace(0)
.curve(Curve.Linear)
Row({ space: 20 }) {
Text('春节不打烊(高度50)')
}
.visibility(this.visible1)
.width('100%')
.height(50)
.justifyContent(FlexAlign.Center)
.backgroundColor(Color.Orange)
.border({radius: { topLeft: 20, topRight: 20 }})
Row({ space: 20 }) {
Text('男童')
Text('女童')
}
.width('100%')
.height(50)
.justifyContent(FlexAlign.Center)
.backgroundColor(Color.Gray)
Row({ space: 20 }) {
Text('¥100以下')
Text('¥100-¥150')
Text('¥150以上')
}
.width('100%')
.height(50)
.justifyContent(FlexAlign.Center)
Stack({ alignContent: Alignment.Top }) {
List({ scroller: this.scroller, space: 10 }) {
LazyForEach(this.data1, (item: string, index: number) => {
ListItem() {
Text("item" + item)
.fontSize(16)
}.listCard()
.onAppear(() => {
console.log('新数据', index)
})
}, (item: string) => item)
}.width("100%")
.backgroundColor(Color.Blue)
.edgeEffect(EdgeEffect.None)
.margin({ top: this.top })
.onReachStart(() => {
console.log('start')
if (this.swiperOffset === -180) {
this.XiDing = false
}
})
// 黄色区域滑到一半,手指松开后黄色区域全部弹出
.onScrollStop(() => {
if (this.swiperOffset > -230 && this.swiperOffset && this.XiDing === true) {
this.swiperOffset = -180
}
})
.onScrollFrameBegin((offset: number, state: ScrollState) => {
// console.log(`${offset}`)
if (this.swiperOffset < -80) {
this.visible = true
this.visible1 = Visibility.None
}
if (this.swiperOffset > -80 && offset < 0) {
this.visible = false
this.visible1 = Visibility.Visible
}
if (this.swiperOffset - offset >= 0) {
this.swiperOffset = 0
} else {
this.swiperOffset = this.swiperOffset - offset
}
// 第一次回滑正常后 this.XiDing 的值变成了false,会导致第二次及以后的回滑效果异常
if (this.swiperOffset < -280) {
this.swiperOffset = -280
this.XiDing = true
}
// 这里不设 this.swiperOffset < 0 的话,初次进入页面下拉就会出现页面布局异常
if (this.swiperOffset > -180 && offset < 0 && this.XiDing === true) {
// console.log('不准动!!!')
this.swiperOffset = -180
}
if (this.swiperOffset != -280 && this.swiperOffset != 0 && this.swiperOffset != -180) {
return {
offsetRemain: 0
}
}
return {
offsetRemain: offset
}
})
// 上滑需要回滑的部分
Column() {
Row({ space: 20 }) {
Text('销量')
Text('价格')
Text('筛选')
}
.width('100%')
.height(50)
.justifyContent(FlexAlign.Center)
.backgroundColor(Color.Yellow)
Row({ space: 20 }) {
// Text('筛选')
// Text('春节不打烊')
Text('swiper:' + `${this.swiperOffset}`)
Text('XiDing:' + `${this.XiDing}`)
}
.backgroundColor(Color.Red)
.width('100%')
.height(50)
.justifyContent(FlexAlign.Center)
}
.offset({
y: this.textOffset
})
.margin({top: this.textMargin})
}.width("100%").height('100%')
}
}
}
.backgroundColor(Color.Pink)
}
aboutToAppear() {
let list: number[] = []
for (let i = 1; i <= 10; i++) {
list.push(i);
}
this.data = new MyDataSource(list)
let list1: number[] = []
for (let i = 0; i <= 30; i++) {
list1.push(i);
}
this.data1 = new MyDataSource(list1)
}
}
class MyDataSource implements IDataSource {
private list: number[] = []
constructor(list: number[]) {
this.list = list
}
totalCount(): number {
return this.list.length
}
getData(index: number): number {
return this.list[index]
}
registerDataChangeListener(listener: DataChangeListener): void {
}
unregisterDataChangeListener() {
}
}
在对应模块中的oh-package.json5中添加依赖,如:entry/oh-package.json5
"dependencies": {
"@hms-paf/ui-widget-base": "14.0.1-103",
"@hms-paf/ui-widget-consent": "14.0.1-103",
"@hms-paf/ui-widget-permission": "14.0.1-103",
"@hms-security/consent": "6.12.0-313",
"@network/grs": "^7.0.6-300"
}
在项目的入口文件中,进行初始化,如:EntryAbility.ets
// 导入Paf UiWidget包
import { PafUiWidget } from '@hms-paf/ui-widget-base';
// 导入GRS包,用于初始化GRS
import { GrsFileUtil } from '@network/grs';
// 导入consent相关包
import { AgreementCallBack, PafAgreement, PafClientInfo } from '@hms-paf/ui-widget-consent';
// 业务自己适配的接口
import { AgreementConfig } from '../Component/AgreementConfig';1
在项目的入口文件中,进行初始化,如:EntryAbility.ets
async onWindowStageCreate(windowStage: window.WindowStage) {
// Paf UiWidget 初始化
PafUiWidget.init(windowStage)
// Grs初始化
GrsFileUtil.copyGrsConfigFile(this.context, false);
// 业务自己适配的接口初始化paf
AgreementConfig.context = this.context;
AgreementConfig.windowStage = windowStage;
let agreementCallBack: AgreementCallBack = {
loadWelcomePage: async () => {
windowStage.loadContent('pages/permissionNormal');
},
loadMainPage: async () => {
windowStage.loadContent('pages/index');
},
signCallBack: new AgreementConfig.SignCallBack(),
revokeCallBack: new AgreementConfig.RevokeCallBack(),
queryRecordsCallBack: new AgreementConfig.QueryCallBack(),
}
let clientInfoIn: PafClientInfo = await AgreementConfig.clientInfo();
let popupPermission: boolean = false;
// 开关,控制协议签署方式(目前switchToNew 属性测试代码,先用init,initAsync等正式版本后再使用)
let switchToNew: boolean = AppStorage.get<boolean>('Paf.UseNewConsentWay') || false;
if (switchToNew) {
popupPermission = await PafAgreement.initAsync(this.context, clientInfoIn, AgreementConfig.userAccount(),
AgreementConfig.getAgreementTypes(), agreementCallBack);
} else {
// clientInfoIn仅在初始化使用一次
popupPermission = PafAgreement.init(this.context, clientInfoIn, AgreementConfig.userAccount(),
AgreementConfig.getAgreementTypes(), agreementCallBack);
}
if (popupPermission) {
// 拉起权限启动页
} else {
// 应用业务首页
}
}
// 监听语言变化
onConfigurationUpdate(newConfig: Configuration) {
PafUiWidget.configurationUpdate(newConfig)
}
权限启动页示例 - 字符串拼接
import I18n from '@ohos.i18n';
import router from '@ohos.router';
import { PafSpan, PafText } from '@hms-paf/ui-widget-base';
import {
PafPermission,
PafPermissionItem,
PafPopPermissionCancel,
PafPopPermissionDesc
} from '@hms-paf/ui-widget-permission';
class DeclareDemo {
format: string | Resource = ''
args: PafSpan[] = []
}
@Entry
@Component
struct Permission {
@State basicTitle: string = ''
@State fullTitle: string = ''
@State declares: Array<PafText> = []
@State dialogDeclare: Array<PafText> = []
declareDemo1: DeclareDemo = {
format: `本应用需%1$s,调用%2$s、%3$s权限,获取XX信息,以为您提供XX服务。我们仅在您使用具体功能业务时,才会触发上述行为收集使用相关的个人信息。详情请参阅%4$s、%5$s。`,
args: [
new PafSpan($r('app.string.paf_text_arg1')).emphasis(),
new PafSpan('XX').emphasis(),
new PafSpan('XX').emphasis(),
new PafSpan($r('app.string.paf_text_arg4')).hyperlink(() => {
router.pushUrl({ url: 'pages/privacyStatement' });
}),
new PafSpan('权限使用说明').hyperlink(() => {
this.permissionDescDlg.open()
})
]
}
declareDemo2: DeclareDemo = {
format: `请您仔细阅读上述声明,点击“同意”,即表示您知悉并同意我们向您提供本应用服务。`,
args: []
}
dialogDeclareDemo1: DeclareDemo = {
format: `全量模式下,本应用需%1$s,调用%2$s、%3$s权限,获取XX信息,以为您提供XX服务。我们仅在您使用具体功能业务时,才会触发上述行为收集使用相关的个人信息。详情请参阅%4$s。`,
args: [
new PafSpan($r('app.string.paf_text_arg1')).emphasis(),
new PafSpan('XX').emphasis(),
new PafSpan('XX').emphasis(),
new PafSpan($r('app.string.paf_text_arg4')).hyperlink(() => {
router.pushUrl({ url: 'pages/privacyStatement' });
})
]
}
dialogDeclareDemo2: DeclareDemo = {
format: `请您仔细阅读上述声明,点击“同意基本(全量)模式”,即表示您知悉并同意我们向您提供本应用服务。`,
args: []
}
permissionDescDlg: CustomDialogController = new CustomDialogController({
builder: PafPopPermissionDesc({
title: $r('app.string.paf_permission_desc_title'),
desc: $r('app.string.paf_permission_desc_desc'),
items: [new PafPermissionItem("权限名称", "包括xx(子权限),用于XXXX"),
new PafPermissionItem("权限名称2", "用于XXXX"),
new PafPermissionItem("权限名称3", "用于XXXX"),
new PafPermissionItem("权限名称4", "用于XXXX"),
]
}),
alignment: DialogAlignment.Bottom,
autoCancel: true,
customStyle: true
})
permissionCancelDlg: CustomDialogController = new CustomDialogController({
builder: PafPopPermissionCancel({
basicTitle: this.basicTitle,
fullTitle: this.fullTitle,
fullDesc: this.dialogDeclare,
fullService: () => {
console.log(`PafAgreement popPermissionCancel fullService`);
router.replaceUrl({ url: 'pages/index' });
}
}),
alignment: DialogAlignment.Bottom,
autoCancel: true,
customStyle: true
})
aboutToAppear() {
this.basicTitle = "您可以选择“同意基本模式”以使用华为XX基本服务(播放本地歌曲),该服务需联网,调用存储权限。"
this.fullTitle = "您可以选择“同意全量模式”以使用更多功能(如音乐推荐、歌单等)。"
this.declares = [
new PafText().format(this.declareDemo1.format, this.declareDemo1.args),
new PafText().format(this.declareDemo2.format, this.declareDemo2.args)
]
this.dialogDeclare = [
new PafText().format(this.dialogDeclareDemo1.format, this.dialogDeclareDemo1.args),
new PafText().format(this.dialogDeclareDemo2.format, this.dialogDeclareDemo2.args)
]
}
cancel() {
this.permissionCancelDlg.open()
}
confirm() {
router.replaceUrl({ url: 'pages/index' });
}
@Builder
payloadBuilder() {
PafPermission({
appImg: $r('app.media.icon'),
appName: $r('app.string.app_name'),
appDesc: "声明文本使用PafText().format,支持字符串和资源字符串",
permissionDeclare: $declares,
confirm: () => {
this.confirm()
},
cancel: () => {
this.cancel()
},
//仅处理影响账号登陆的准备工作
beforeSign:() => {
}
})
}
build() {
Row() {
this.payloadBuilder()
}
.height('100%')
}
}
隐私声明页示例
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
*/
import { PafPrivacyStatement } from '@hms-paf/ui-widget-permission';
import { GlobalVariable } from '../Component/GlobalVariable';
import { PafWebViewController } from '@hms-paf/ui-widget-base';
@Entry
@Component
struct Index {
// 使用 PafPrivacyStatement 组件,需要在@Entry页面中定义 PafWebViewController ,并重写onBackPress,以达到逐个返回网页的效果,而不是一下全部返回多层网页
@Provide('Paf.WebViewController') controller: PafWebViewController = new PafWebViewController()
onBackPress(): void | boolean {
return this.controller.onBackPress()
}
@Builder
payloadBuilder() {
PafPrivacyStatement({
// 协议类型id,从协议配置导出来的兜底文件中agreement_config.json获取 agrType 字段
agreementType: 11,
})
}
build() {
Row() {
this.payloadBuilder()
}
}
}
权限使用说明弹窗示例
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
*/
import { PafPermissionItem, PafPopPermissionDesc } from '@hms-paf/ui-widget-permission';
@Entry
@Component
struct PermissionDescDlg {
//创建弹出框,引入PafPopPermissionDesc组件
permissionDescDlg: CustomDialogController = new CustomDialogController({
builder: PafPopPermissionDesc({
title: $r('app.string.paf_permission_desc_title'),
desc: $r('app.string.paf_permission_desc_desc'),
confirm: () => {
},
customColor: Color.Blue,
items: [new PafPermissionItem("权限名称", "包括xx(子权限),用于XXXX"),
new PafPermissionItem("权限名称2", "用于XXXX"),
new PafPermissionItem("权限名称3", "用于XXXX"),
new PafPermissionItem("权限名称4", "用于XXXX")
]
}),
alignment: DialogAlignment.Bottom,
autoCancel: true,
customStyle: true
})
build() {
Row() {
}
.height('100%')
.width('100%')
.onAppear(() => {
this.permissionDescDlg.open()
})
}
}
挽留弹窗示例 - 字符串拼接
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
*/
import router from '@ohos.router';
import I18n from '@ohos.i18n';
import { PafSpan, PafText } from '@hms-paf/ui-widget-base';
import { PafPopPermissionCancel } from '@hms-paf/ui-widget-permission';
@Entry
@Component
struct PermissionCancelDlg {
basicTitle: string = "如不同意上述隐私条款,可以电视”仅使用基础服务“,您将只能使用本地歌曲播放功能。"
fullTitle: string = "如需体验更多功能(如音乐推荐、歌单等),可电视”使用完整服务“。"
// 监听系统语言切换,重新获取隐私申明文档
@StorageProp('Paf.language') @Watch('getDeclare') private language: string = I18n.System.getSystemLanguage()
@State dialogDeclare: Array<PafText> = []
permissionCancelDlg: CustomDialogController = new CustomDialogController({
builder: PafPopPermissionCancel({
basicTitle: this.basicTitle,
fullTitle: this.fullTitle,
fullDesc: $dialogDeclare,
customColor: '',
alwaysDarkMode: false
}),
alignment: DialogAlignment.Bottom,
autoCancel: true,
customStyle: true
})
getDeclare() {
let format1: string | Resource = $r('app.string.paf_text_format')
let args1: PafSpan[] = [
new PafSpan($r('app.string.paf_text_arg1')).emphasis(),
new PafSpan($r('app.string.paf_text_arg4')).hyperlink(() => {
router.pushUrl({ url: 'pages/privacyStatement' });
}),
new PafSpan($r('app.string.paf_text_arg5')).hyperlink(() => {
})
]
this.dialogDeclare = [new PafText().format(format1, args1)]
let format2: string | Resource = $r('app.string.paf_text_agree')
let args2: PafSpan[] = [
new PafSpan(`${this.language}`).normal()
]
this.dialogDeclare.push(new PafText().format(format2, args2))
}
aboutToAppear() {
this.getDeclare()
}
build() {
Row() {
}
.width('100%')
.height('100%')
.onAppear(() => {
this.permissionCancelDlg.open()
})
}
}
更多关于HarmonyOS 鸿蒙Next 限启动页、权限使用说明、权限管理、嵌套滚动Demo请求的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
关于HarmonyOS 鸿蒙Next的启动页、权限使用说明、权限管理及嵌套滚动Demo的请求,以下是专业回复:
启动页:
HarmonyOS鸿蒙Next的启动页通常用于展示应用Logo或欢迎界面。开发者可在应用中设置启动页,确保用户在打开应用时获得良好的第一印象。
权限使用说明:
应用需明确所需权限,并判断这些权限是否涉及用户敏感信息。对于敏感信息权限,需通过用户授权方式获得,并在应用运行时动态请求。开发者应遵循权限申请最小化原则,提供清晰的权限使用理由。
权限管理:
HarmonyOS基于TokenID管理应用权限,确保应用访问系统资源时遵循预先设定的规则。开发者可利用此机制实现应用权限的精细化管理。
嵌套滚动Demo:
对于嵌套滚动,开发者需对接ArkUI框架的NestedScrollMode枚举类型。通过设置nestedScroll接口的scrollForward和scrollBackward属性,可实现Web组件与上下层组件的嵌套滚动关系。具体Demo可参考官方文档或开发者社区提供的示例代码。
如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html