HarmonyOS鸿蒙Next中Scroll如何添加如下这种动画效果:
HarmonyOS鸿蒙Next中Scroll如何添加如下这种动画效果: 代码如下
- 进入页面首次从模块三展示,
- scroll内容右滑50vp后,控制scroller滑动到模块一,这期间有一个动画效果,
- 在模块一这里滑动,使得scroll中的内容左滑50vp,再回到模块三,这期间也有一个动画效果。
请问这种效果如何实现?
@Entry
@Component
struct RefreshPage {
scroller: Scroller = new Scroller()
build() {
Column {
Scroll(this.scroller) {
Row({ space: 10 }) {
Text('模块一').textBor()
Text('模块二').textBor()
Text('模块三').textBor()
Text('模块四').textBor()
Text('模块五').textBor()
Text('模块六').textBor()
Text('模块七').textBor()
Text('模块八').textBor()
Text('模块九').textBor()
}
}
.width('100%')
.height(100)
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.Off)
.onAppear(() => {
this.scroller.scrollTo({ xOffset: 220, yOffset: 0 })
})
}
}
}
@Extend(Text)
function textBor() {
.width(100).height('80%').textAlign(TextAlign.Center).border({ width: 1, color: '#FF5500' })
}
更多关于HarmonyOS鸿蒙Next中Scroll如何添加如下这种动画效果:的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
解决:内容滑动到最右边后,左滑一点距离,就会自动滑到模块三,
新问题:在模块三这里,左滑一定距离,不松开手指,再右滑一定距离,模块二会漏出来一块,
期望:模块一和模块二要么完全展示,要么全不展示
@Entry
@Component
struct RefreshPage {
scroller: Scroller = new Scroller()
@State isShow: boolean = false
@State scrollDirection: number = -1
build() {
Column() {
Scroll(this.scroller) {
Row({ space: 10 }) {
Row({ space: 10 }) {
Text('模块一').textBor
Text('模块二').textBor
}
.onTouch((event: TouchEvent) => {
})
.onVisibleAreaChange([0.3, 0.7], (isVisible: boolean, currentRatio: number) => {
if (isVisible) {
this.isShow = true
this.scroller.scrollTo({ xOffset: 0, yOffset: 0, animation: { duration: 500, curve: Curve.Linear, canOverScroll: false } })
} else {
this.isShow = false
this.scroller.scrollTo({ xOffset: 220, yOffset: 0, animation: { duration: 500, curve: Curve.Linear, canOverScroll: false } })
}
})
Text('模块三').textBor
Text('模块四').textBor
Text('模块五').textBor
Text('模块六').textBor
Text('模块七').textBor
Text('模块八').textBor
Text('模块九').textBor
}
}
.width('100%')
.height(100)
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.Off)
.onAppear(() => {
this.scroller.scrollTo({ xOffset: 220, yOffset: 0 })
})
.onWillScroll((x: number, y: number, scrollState: ScrollState, scrollSource: ScrollSource) => {
if (x > 0) {
this.scrollDirection = 1
} else {
this.scrollDirection = 2
}
})
.onTouch((event: TouchEvent) => {
if (event.type == TouchType.Up) { // 手指抬起时判断
if (this.isShow) {
this.scroller.scrollTo({ xOffset: 0, yOffset: 0, animation: { duration: 500, curve: Curve.Linear, canOverScroll: false } })
} else {
if (this.scrollDirection == 2 && this.scroller.currentOffset().xOffset <= 220) {
this.scroller.scrollTo({ xOffset: 220, yOffset: 0, animation: { duration: 500, curve: Curve.Linear, canOverScroll: false } })
}
}
}
})
}
}
}
@Extend(Text)
function textBor() {
.width(100).height('80%').textAlign(TextAlign.Center).border({ width: 1, color: '#FF5500' })
}
在项目中使用到了onWillScroll和onDidScroll冲突了,所以换了一种方式
@Entry
@Component
struct RefreshPage {
scroller: Scroller = new Scroller()
@State isShow: boolean = false
@State scrollDirection: number = -1
build() {
Column() {
Scroll(this.scroller) {
Row({ space: 10 }) {
Row({ space: 10 }) {
Text('模块一').textBor()
Text('模块二').textBor()
}
.onTouch((event: TouchEvent) => {
})
.onVisibleAreaChange([0.3, 0.7], (isVisible: boolean, currentRatio: number) => {
if (isVisible) {
this.isShow = true
this.scroller.scrollTo({ xOffset: 0, yOffset: 0, animation: { duration: 500, curve: Curve.Linear, canOverScroll: false } })
} else {
this.isShow = false
this.scroller.scrollTo({ xOffset: 220, yOffset: 0, animation: { duration: 500, curve: Curve.Linear, canOverScroll: false } })
}
})
Text('模块三').textBor()
Text('模块四').textBor()
Text('模块五').textBor()
Text('模块六').textBor()
Text('模块七').textBor()
Text('模块八').textBor()
Text('模块九').textBor()
}
}
.width('100%')
.height(100)
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.Off)
.onAppear(() => {
this.scroller.scrollTo({ xOffset: 220, yOffset: 0 })
})
.onWillScroll((x: number, y: number, scrollState: ScrollState, scrollSource: ScrollSource) => {
if (x > 0) {
this.scrollDirection = 1
} else {
this.scrollDirection = 2
}
})
.onTouch((event: TouchEvent) => {
if (event.type == TouchType.Up) { // 手指抬起时判断
if (this.isShow) {
this.scroller.scrollTo({ xOffset: 0, yOffset: 0, animation: { duration: 500, curve: Curve.Linear, canOverScroll: false } })
} else {
if (this.scrollDirection == 2) {
this.scroller.scrollTo({ xOffset: 220, yOffset: 0, animation: { duration: 500, curve: Curve.Linear, canOverScroll: false } })
}
}
}
})
}
}
}
@Extend(Text)
function textBor() {
.width(100).height('80%').textAlign(TextAlign.Center).border({ width: 1, color: '#FF5500' })
}
解决办法如下:
@Entry
@Component
struct RefreshPage {
scroller: Scroller = new Scroller()
@State isShow: boolean = false
build() {
Column() {
Scroll(this.scroller) {
Row({ space: 10 }) {
Row({ space: 10 }) {
Text('模块一').textBor
Text('模块二').textBor
}
.onTouch((event: TouchEvent) => {
})
.onVisibleAreaChange([0.3, 0.7], (isVisible: boolean, currentRatio: number) => {
if (isVisible) {
this.isShow = true
this.scroller.scrollTo({ xOffset: 0, yOffset: 0, animation: { duration: 500, curve: Curve.Linear, canOverScroll: false } })
} else {
this.isShow = false
this.scroller.scrollTo({ xOffset: 220, yOffset: 0, animation: { duration: 500, curve: Curve.Linear, canOverScroll: false } })
}
})
Text('模块三').textBor
Text('模块四').textBor
Text('模块五').textBor
Text('模块六').textBor
Text('模块七').textBor
Text('模块八').textBor
Text('模块九').textBor
}
}
.width('100%')
.height(100)
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.Off)
.onAppear(() => {
this.scroller.scrollTo({ xOffset: 220, yOffset: 0 })
})
.onDidScroll((xOffset: number, yOffset: number, scrollState: ScrollState) => {
if (scrollState == ScrollState.Idle) {
if (this.isShow) {
this.scroller.scrollTo({ xOffset: 0, yOffset: 0, animation: { duration: 500, curve: Curve.Linear, canOverScroll: false } })
} else {
this.scroller.scrollTo({ xOffset: 220, yOffset: 0, animation: { duration: 500, curve: Curve.Linear, canOverScroll: false } })
}
}
})
}
}
}
@Extend(Text)
function textBor() {
.width(100).height('80%').textAlign(TextAlign.Center).border({ width: 1, color: '#FF5500' })
}
使用onVisibleAreaChange实现了这种动画效果,但是感觉不够完善,而且,
模块一和模块二是不可以只展示一半的,要么全展示出来,要么不展示
还要计算具体的偏移量,来区分
大家还有什么更好的办法吗?
@Entry
@Component
struct RefreshPage {
scroller: Scroller = new Scroller()
build() {
Column() {
Scroll(this.scroller) {
Row({ space: 10 }) {
Row({ space: 10 }) {
Text('模块一').textBor
Text('模块二').textBor
}.onVisibleAreaChange([0.3, 0.7], (isVisible: boolean, currentRatio: number) => {
if (isVisible) {
this.scroller.scrollTo({ xOffset: 0, yOffset: 0, animation: { duration: 1000, curve: Curve.Linear, canOverScroll: false } })
} else {
this.scroller.scrollTo({ xOffset: 220, yOffset: 0, animation: { duration: 1000, curve: Curve.Linear, canOverScroll: false } })
}
})
Text('模块三').textBor
Text('模块四').textBor
Text('模块五').textBor
Text('模块六').textBor
Text('模块七').textBor
Text('模块八').textBor
Text('模块九').textBor
}
}
.width('100%')
.height(100)
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.Off)
.onAppear(() => {
this.scroller.scrollTo({ xOffset: 220, yOffset: 0 })
})
}
}
}
@Extend(Text)
function textBor() {
.width(100).height('80%').textAlign(TextAlign.Center).border({ width: 1, color: '#FF5500' })
}
在HarmonyOS鸿蒙Next中,Scroll组件可以通过自定义动画效果实现。使用@ohos.animator
模块创建动画,结合Scroll
的滚动事件,动态调整子组件的属性。例如,可以在onScroll
回调中根据滚动位置计算动画进度,通过Animator
的update
方法实时更新组件的透明度、位置等属性。具体实现步骤如下:
- 创建
Animator
对象,定义动画的起始值和结束值。 - 在
Scroll
的onScroll
事件中,根据滚动距离计算动画进度。 - 通过
Animator
的update
方法,将计算出的值应用到目标组件的属性上。
示例代码片段如下:
import { Animator, Scroll } from '@ohos.animator';
const scroll = new Scroll();
const animator = new Animator({
startValue: 0,
endValue: 1,
duration: 300
});
scroll.onScroll((scrollOffset) => {
const progress = calculateProgress(scrollOffset);
animator.update(progress);
});
function calculateProgress(offset) {
// 根据滚动偏移量计算动画进度
return offset / maxScrollOffset;
}
在HarmonyOS鸿蒙Next中,可以通过Scroll
组件结合Animation
来实现滚动时的动画效果。首先,使用Scroll
组件包裹需要滚动的内容,然后通过onScroll
事件监听滚动位置。在onScroll
回调中,根据滚动位置动态调整目标组件的属性(如透明度、缩放、位移等),并利用Animation
对象创建平滑的过渡效果。例如,可以通过animateTo
方法实现渐隐渐现或缩放动画。具体实现时,建议使用@State
或@Prop
装饰器管理动画状态,确保UI的响应性和流畅性。