HarmonyOS鸿蒙Next中圆形列表渐隐效果适配
HarmonyOS鸿蒙Next中圆形列表渐隐效果适配 在使用scale对组件进行缩小后,缩小前的位置会仍然占有,导致循环列表的每一项都会有不均匀的间隙,无法紧挨到一起,如果直接对组件的宽高进行控制的话,组件里面的字又不会跟着一起缩小,而且有抖动,体验不好。
interface ScaleRange {
MIN: number,
MAX: number
}
interface ScaleZone {
TOP: number[], // 顶部渐隐区
CENTER: number[], // 中心区域
BOTTOM: number[] // 底部渐隐区
}
@Entry
@Component
struct Index {
@State yOffset: number = 0
@State maxScrollOffset: number = 0
@State viewportHeight: number = 0
@State listItemScale: number[] = []
private listScroller: ListScroller = new ListScroller()
@State
array: Array<string> =
['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']
// 在组件顶部新增常量
private readonly SCALE_RANGE: ScaleRange = {
MIN: 0.5, // 渐隐最小比例
MAX: 1.0 // 最大比例
};
private readonly SCROLL_ZONE: ScaleZone = {
TOP: [0, 86.5], // 顶部渐隐区(0-86.5)
CENTER: [86.5, 146.5], // 中心区域
BOTTOM: [146.5, 233] // 底部渐隐区(146.5-233)
};
build() {
List({
scroller: this.listScroller,
}) {
ListItem() {
Column() {
Text('12:00')
.fontColor(Color.White)
Blank().height(8)
Text('今日状态')
.fontSize(17)
.fontWeight(FontWeight.Bold)
.fontColor('#ADA7F6')
}.padding({
top: 10, bottom: 10
})
}
ListItem()
.width('100%')
.height(82)
.backgroundColor('#1FFFFFFF')
.borderRadius(41)
ForEach(this.array, (item: string, index: number) => {
ListItem() {
// 列表项内容...
CommonListItem({
icon: $r('sys.media.return_home_fill'),
text: '项目' + item,
slot: calorieLeftDataItem,
slotValue1: 150,
})
}
.width('100%')
.height(60)
.scale({ x: this.listItemScale[index], y: this.listItemScale[index] })
.onAreaChange((oldValue, newValue) => {
const ITEM_HEIGHT = newValue.height as number; // 列表项原始高度
const childCenter = (newValue.position.y as number) + ITEM_HEIGHT / 2;
console.log(`项目${index + 1}: ` + (newValue.position.y as number))
let scale = this.SCALE_RANGE.MAX;
// 处理顶部区域(0-86.5)
if (childCenter <= this.SCROLL_ZONE.TOP[1]) {
const start = this.SCROLL_ZONE.TOP[0];
const end = this.SCROLL_ZONE.TOP[1];
const progress = Math.min(1, (childCenter - start) / (end - start));
// 缩放比例从0.5到1.0
scale = this.SCALE_RANGE.MIN + (this.SCALE_RANGE.MAX - this.SCALE_RANGE.MIN) * progress;
}
// 处理底部区域(146.5-233)
else if (childCenter >= this.SCROLL_ZONE.BOTTOM[0]) {
const start = this.SCROLL_ZONE.BOTTOM[0];
const end = this.SCROLL_ZONE.BOTTOM[1];
const progress = Math.min(1, (childCenter - start) / (end - start));
// 缩放比例从1.0到0.5
scale = this.SCALE_RANGE.MAX - (this.SCALE_RANGE.MAX - this.SCALE_RANGE.MIN) * progress;
}
// 中心区域(86.5-146.5)保持最大值
else {
scale = this.SCALE_RANGE.MAX;
}
this.listItemScale[index] = Math.min(
this.SCALE_RANGE.MAX,
Math.max(this.SCALE_RANGE.MIN, scale)
);
})
})
}
.height('100%')
.width('100%')
.padding({ left: 4, right: 4 })
.scrollSnapAlign(this.yOffset > 0 ? ScrollSnapAlign.CENTER : ScrollSnapAlign.START)
.scrollBar(BarState.Off)
.alignListItem(ListItemAlign.Center)
.defaultFocus(true)
.onAreaChange((oldValue, newValue) => {
if (newValue.height > 0) {
this.viewportHeight = newValue.height as number
const contentHeight = 65.5 + this.array.length * 60 + 90
this.maxScrollOffset = Math.max(0, contentHeight - this.viewportHeight)
}
console.info('onAreaChange: ' + JSON.stringify(vp2px(newValue.height as number)))
})
.onWillScroll(() => {
this.yOffset = this.listScroller.currentOffset().yOffset
})
}
}
@Component
export struct CommonListItem {
@Builder
CustomBuildFunction() {
}
icon?: Resource
text?: string
slotValue1?: number | string
slotValue2?: number | undefined
@BuilderParam
slot: (value1: number | string, value2?: number | undefined) => void = this.CustomBuildFunction
build() {
Row({ space: 4 }) {
Image(this.icon)
.width(20)
.height(20)
.fillColor(Color.White)
Text(this.text)
.fontColor(Color.White)
.fontSize(13)
.fontWeight(600)
.lineHeight(19)
.layoutWeight(1)
.textAlign(TextAlign.Start)
if (!this.slotValue2) {
this.slot(this.slotValue1!)
} else {
this.slot(this.slotValue1!, this.slotValue2!)
}
}
.width('100%')
.height('100%')
.padding({
left: 11,
right: 11,
// top: 10,
// bottom: 10
})
.backgroundColor('#1FFFFFFF')
.borderRadius(30)
}
}
@Builder
export function calorieLeftDataItem(value1: number | string) {
Text() {
Span(`${value1 || '--'}`)
.fontColor(Color.White)
.fontSize(15)
.fontWeight(700)
Span('xxxx')
.fontColor(Color.White)
.fontSize(10)
.fontWeight(600)
}
}
更多关于HarmonyOS鸿蒙Next中圆形列表渐隐效果适配的实战教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS鸿蒙Next中实现圆形列表渐隐效果,可以通过使用ArkUI框架中的组件和动画特性来完成。首先,使用List
组件创建圆形列表布局,结合Flex
或Grid
实现圆形排列。接着,通过Canvas
或Shape
组件绘制圆形,并设置渐隐效果。
渐隐效果可以通过Animation
组件实现。定义@State
变量控制透明度,使用animateTo
方法在列表滚动时动态改变透明度。例如:
@State opacity: number = 1.0;
animateTo({ duration: 500 }, () => {
this.opacity = 0.0;
});
在List
的onScroll
事件中触发动画,根据滚动位置调整透明度。确保渐隐效果平滑过渡,避免卡顿。
此外,可以使用LinearGradient
或RadialGradient
设置渐变色,增强视觉层次感。通过合理布局和动画参数,实现流畅的圆形列表渐隐效果。
更多关于HarmonyOS鸿蒙Next中圆形列表渐隐效果适配的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS鸿蒙Next中实现圆形列表的渐隐效果,可以通过自定义RecyclerView
的ItemDecoration
来实现。首先,在onDrawOver
方法中绘制渐隐效果,使用LinearGradient
或RadialGradient
创建渐变,结合Canvas
绘制。然后,在getItemOffsets
中设置列表项的间距,确保渐隐效果与列表项布局协调。最后,通过RecyclerView.addItemDecoration
将自定义的ItemDecoration
应用到列表中。此方法适用于需要动态调整渐隐效果的场景,确保UI的流畅性和美观性。