如果是iOS 或者android 上实现,可以用Scollview 的contentOffset 来实现,然而在鸿蒙ets中该如何实现?废话不多说开始撸代码
第一步、实现一个header
// 创建header,准备一张背景图片
@Builder
HeaderBuilder(){
Column() {
Row() {
Image($r('app.media.back'))
.width(25)
.height(25)
.onClick(() => {
router.back();
})
Text(this.distance == 0 ? 'test1' : "")
.fontColor(Color.Black)
.fontSize(20)
.margin({ left: 5 })
Blank()
Image($r('app.media.share'))
.width(25)
.height(25)
Image($r('app.media.more'))
.width(25)
.height(25)
}
.width('100%')
.padding(20)
.margin({ top: 20 })
Row() {
Text(this.distance > 0 ? 'test2' : '')
.fontColor(Color.Red)
.fontSize(30)
.margin({ left: 5 })
}
.width("100%")
.height(35)
.alignItems(VerticalAlign.Center)
.justifyContent(FlexAlign.Start)
}
.height(this.ImHeight)
.width(this.ImWidth)
.align(Alignment.Center)
.backgroundImage($r('app.media.banner'))
.backgroundImageSize(ImageSize.Cover)
}
第二步、创建header下方的内容部分,通过下拉下面的部分来实现header 背景图放大,松开后复原
这里小编通过TouchEvent 事件来实现具体代码如下:
.onTouch((event: TouchEvent) => {
var y = event.touches[0].y
if (event.type === TouchType.Down) {
this.duration = 1000;
this.startY = y;
}
if (event.type === TouchType.Up) {
this.duration = 500;
this.ImHeight = 200
this.ImWidth = "100%"
this.distance = 0
}
if (event.type === TouchType.Move) {
this.distance = event.touches[0].y - this.startY
if (Math.abs(this.distance) <= 100) {
console.log("height=>"+ this.ImHeight + "distance= ", this.distance)
var height = 200 + this.distance
if (height <= 0) {
height = 0
}else {
var scale = this.distance / 200;
this.ImHeight = height
console.log("height=>"+ this.ImHeight + "distance= ", this.distance)
var imgWidth = 100 + scale * 100 + '%'
if (100 + scale * 100 < 100){
imgWidth = '100%'
this.offX = -25 + this.distance
}else {
this.offX = -25
}
this.ImWidth = imgWidth
}
}else{
this.distance = 0
}
}
})
然而只有手势虽然能实现滑动,但是效果不好,没有bounce 感!如何让他有bounce 感?需要使用动画,具体代码如下:
.animation({
duration: this.duration,
curve: Curve.FastOutSlowIn,
delay: 0,
iterations: 1,
playMode: PlayMode.Normal
})
以上代码基本上是实现本功能的核心部分,完整的代码如下:
// 可拖动子组件,动画,圆弧
Column() {
Row() {
Text('当点击此场景卡片时:')
.fontSize(16)
Blank()
Image($r('app.media.menu'))
.width(30)
.height(30)
}
.width('100%')
.margin({ top: 10, left: 10, right: 10, bottom: 20 })
}
.offset({y: this.offX})
.borderRadius(35)
.padding(20)
.onTouch((event: TouchEvent) => {
var y = event.touches[0].y
if (event.type === TouchType.Down) {
this.duration = 1000;
this.startY = y;
}
if (event.type === TouchType.Up) {
this.duration = 500;
this.ImHeight = 200
this.ImWidth = "100%"
this.distance = 0
}
if (event.type === TouchType.Move) {
this.distance = event.touches[0].y - this.startY
if (Math.abs(this.distance) <= 100) {
console.log("height=>"+ this.ImHeight + "distance= ", this.distance)
var height = 200 + this.distance
if (height <= 0) {
height = 0
}else {
var scale = this.distance / 200;
this.ImHeight = height
console.log("height=>"+ this.ImHeight + "distance= ", this.distance)
var imgWidth = 100 + scale * 100 + '%'
if (100 + scale * 100 < 100){
imgWidth = '100%'
this.offX = -25 + this.distance
}else {
this.offX = -25
}
this.ImWidth = imgWidth
}
}else{
this.distance = 0
}
}
})
.height('100%')
.animation({
duration: this.duration,
curve: Curve.FastOutSlowIn,
delay: 0,
iterations: 1,
playMode: PlayMode.Normal
})
.linearGradient(
{
direction: GradientDirection.Top,
angle: 180,
colors: [['#c7e2eb', 0.01], ["#F7F7F7", 0.05], ["#F7F7F7", 1]]
})
}
.justifyContent(FlexAlign.Start)
下面是本案列的全部代码,仅供参考:
@Preview
@Entry
@Component
struct DetailPage {
@State duration: number = 1000
@State ImHeight: number = 200
@State ImWidth: string = '100%'
@State distance: number = 0
@State offX: number = -25
private startY = 0
// 创建header,准备一张背景图片
@Builder
HeaderBuilder(){
Column() {
Row() {
Image($r('app.media.back'))
.width(25)
.height(25)
.onClick(() => {
router.back();
})
Text(this.distance == 0 ? 'test1' : "")
.fontColor(Color.Black)
.fontSize(20)
.margin({ left: 5 })
Blank()
Image($r('app.media.share'))
.width(25)
.height(25)
Image($r('app.media.more'))
.width(25)
.height(25)
}
.width('100%')
.padding(20)
.margin({ top: 20 })
Row() {
Text(this.distance > 0 ? 'test2' : '')
.fontColor(Color.Red)
.fontSize(30)
.margin({ left: 5 })
}
.width("100%")
.height(35)
.alignItems(VerticalAlign.Center)
.justifyContent(FlexAlign.Start)
}
.height(this.ImHeight)
.width(this.ImWidth)
.align(Alignment.Center)
.backgroundImage($r('app.media.banner'))
.backgroundImageSize(ImageSize.Cover)
}
build() {
Column() {
// header
this.HeaderBuilder()
// 可拖动子组件,动画,圆弧
Column() {
Row() {
Text('当点击此场景卡片时:')
.fontSize(16)
Blank()
Image($r('app.media.menu'))
.width(30)
.height(30)
}
.width('100%')
.margin({ top: 10, left: 10, right: 10, bottom: 20 })
}
.offset({y: this.offX})
.borderRadius(35)
.padding(20)
.onTouch((event: TouchEvent) => {
var y = event.touches[0].y
if (event.type === TouchType.Down) {
this.duration = 1000;
this.startY = y;
}
if (event.type === TouchType.Up) {
this.duration = 500;
this.ImHeight = 200
this.ImWidth = "100%"
this.distance = 0
}
if (event.type === TouchType.Move) {
this.distance = event.touches[0].y - this.startY
if (Math.abs(this.distance) <= 100) {
console.log("height=>"+ this.ImHeight + "distance= ", this.distance)
var height = 200 + this.distance
if (height <= 0) {
height = 0
}else {
var scale = this.distance / 200;
this.ImHeight = height
console.log("height=>"+ this.ImHeight + "distance= ", this.distance)
var imgWidth = 100 + scale * 100 + '%'
if (100 + scale * 100 < 100){
imgWidth = '100%'
this.offX = -25 + this.distance
}else {
this.offX = -25
}
this.ImWidth = imgWidth
}
}else{
this.distance = 0
}
}
})
.height('100%')
.animation({
duration: this.duration,
curve: Curve.FastOutSlowIn,
delay: 0,
iterations: 1,
playMode: PlayMode.Normal
})
.linearGradient(
{
direction: GradientDirection.Top,
angle: 180,
colors: [['#c7e2eb', 0.01], ["#F7F7F7", 0.05], ["#F7F7F7", 1]]
})
}
.justifyContent(FlexAlign.Start)
}
}