介紹
本示例使用滑動手勢監(jiān)聽沙咏,實(shí)時調(diào)整左右兩側(cè)內(nèi)容顯示區(qū)域大小和效果。通過綁定gesture事件中的PanGesture平移手勢班套,實(shí)時獲取拖動距離肢藐。當(dāng)拖動時,實(shí)時地調(diào)節(jié)左右兩個Image組件的寬度吱韭,從而成功實(shí)現(xiàn)左右拖動切換圖片效果的功能吆豹。
效果圖預(yù)覽
使用說明
- 點(diǎn)擊中間按鈕進(jìn)行左右拖動切換圖片。
實(shí)現(xiàn)思路
本例涉及的關(guān)鍵特性和實(shí)現(xiàn)方案如下:
- 創(chuàng)建三個Stack組件理盆,用來展示裝修前后對比圖痘煤,第一個和第三個Stack分別存放裝修前的圖片和裝修后的圖片,zIndex設(shè)置為1猿规。第二個Stack存放按鈕的圖片衷快,zIndex設(shè)置為2,這樣按鈕的圖片就會覆蓋在兩張裝修圖片之上姨俩。 源碼參考DragToSwitchPicturesView.ets蘸拔。
Row() {
Stack() {...}
.zIndex(CONFIGURATION.ZINDEX1)
.width(this.leftImageWidth) // z序設(shè)為1,為了使按鈕圖片浮在裝修圖片上环葵。
Stack() {...}
.width($r('app.integer.drag_button_stack_width'))
.zIndex(CONFIGURATION.ZINDEX2) // z序設(shè)為2调窍,為了使按鈕圖片浮在裝修圖片上。
Stack() {...}
.zIndex(CONFIGURATION.ZINDEX1) // z序設(shè)為1张遭,為了使按鈕圖片浮在裝修圖片上陨晶。
.width(this.rightImageWidth)
}
.justifyContent(FlexAlign.Center)
.width($r('app.string.full_size'))
- 將Image組件放在Row容器里,將Row容器的寬度設(shè)置為狀態(tài)變量帝璧,再利用clip屬性對于Row容器進(jìn)行裁剪。 源碼參考DragToSwitchPicturesView.ets湿刽。
Row() {
Image($r('app.media.before_decoration'))
.width($r('app.integer.decoration_width'))// Image的width固定的烁,Row的寬度變化,通過裁剪實(shí)現(xiàn)布局效果诈闺。
.height($r('app.integer.decoration_height'))
.draggable(false) // 設(shè)置Image不能拖動渴庆,不然長按Image會被拖動。
}
.width(this.leftImageWidth) // 將左側(cè)Row的width設(shè)置為leftImageWidth,這樣左側(cè)Row的width隨leftImageWidth的變化而變化襟雷。
.clip(true) // clip屬性設(shè)置為true刃滓,裁剪超出Row寬度的圖片。
.zIndex(CONFIGURATION.ZINDEX1) // z序設(shè)為1耸弄,為了使水印浮在裝修圖片上咧虎。
.borderRadius({
topLeft: $r('app.integer.borderradius'),
bottomLeft: $r('app.integer.borderradius')
}) // 將Row的左上角和左下角弧度設(shè)為10實(shí)現(xiàn)效果。
- 右邊的Image組件與左邊同樣的操作计呈,但是新增了一個direction屬性砰诵,使元素從右至左進(jìn)行布局,為的是讓Row從左側(cè)開始裁剪捌显。 源碼參考DragToSwitchPicturesView.ets茁彭。
Row() {
Image($r('app.media.after_decoration'))
.width($r('app.integer.decoration_width'))
.height($r('app.integer.decoration_height'))
.draggable(false)
}
.width(this.rightImageWidth)
.clip(true)
.zIndex(CONFIGURATION.ZINDEX1) // z序設(shè)為1,為了使水印浮在裝修圖片上扶歪。
// TODO: 知識點(diǎn):左邊Row使用clip時從右邊開始裁剪理肺,加了Direction.Rtl后,元素從右到左布局善镰,右邊Row使用clip時從左邊開始裁剪妹萨,這是實(shí)現(xiàn)滑動改變視圖內(nèi)容大小的關(guān)鍵。
.direction(Direction.Rtl)
.borderRadius({
topRight: $r('app.integer.borderradius'),
bottomRight: $r('app.integer.borderradius')
}) // 將Row的右上角和右下角弧度設(shè)為10實(shí)現(xiàn)效果媳禁。
- 中間的Image組件通過手勢事件中的滑動手勢對Image組件滑動進(jìn)行監(jiān)聽眠副,對左右Image組件的寬度進(jìn)行計(jì)算從而重新布局渲染。 源碼參考DragToSwitchPicturesView.ets竣稽。
Image($r('app.media.drag_button'))
.width($r('app.integer.drag_button_image_width'))
.height($r('app.integer.decoration_height'))
.draggable(false)
.gesture( // TODO: 知識點(diǎn):拖動手勢事件設(shè)置一個手指囱怕,滑動的最小距離設(shè)置為1vp,實(shí)現(xiàn)滑動時按鈕跟手動效毫别。
PanGesture({ fingers: CONFIGURATION.PANGESTURE_FINGERS, distance: CONFIGURATION.PANGESTURE_DISTANCE })
.onActionStart(() => {
this.dragRefOffset = CONFIGURATION.INIT_VALUE; // 每次拖動開始時將圖標(biāo)拖動的距離初始化娃弓。
})
// TODO: 性能知識點(diǎn): 該函數(shù)是系統(tǒng)高頻回調(diào)函數(shù),避免在函數(shù)中進(jìn)行冗余或耗時操作岛宦,例如應(yīng)該減少或避免在函數(shù)打印日志台丛,會有較大的性能損耗。
.onActionUpdate((event: GestureEvent) => {
// 通過監(jiān)聽GestureEvent事件砾肺,實(shí)時監(jiān)聽圖標(biāo)拖動距離
this.dragRefOffset = event.offsetX;
this.leftImageWidth = this.imageWidth + this.dragRefOffset;
this.rightImageWidth = CONFIGURATION.IMAGE_FULL_SIZE - this.leftImageWidth;
if (this.leftImageWidth >= CONFIGURATION.LEFT_IMAGE_RIGHT_LIMIT_SIZE) { // 當(dāng)leftImageWidth大于等于310vp時挽霉,設(shè)置左右Image為固定值,實(shí)現(xiàn)停止滑動效果变汪。
this.leftImageWidth = CONFIGURATION.LEFT_IMAGE_RIGHT_LIMIT_SIZE;
this.rightImageWidth = CONFIGURATION.RIGHT_IMAGE_RIGHT_LIMIT_SIZE;
} else if (this.leftImageWidth <= CONFIGURATION.LEFT_IMAGE_LEFT_LIMIT_SIZE) { // 當(dāng)leftImageWidth小于等于30vp時侠坎,設(shè)置左右Image為固定值,實(shí)現(xiàn)停止滑動效果裙盾。
this.leftImageWidth = CONFIGURATION.LEFT_IMAGE_LEFT_LIMIT_SIZE;
this.rightImageWidth = CONFIGURATION.RIGHT_IMAGE_LEFT_LIMIT_SIZE;
}
})
.onActionEnd((event: GestureEvent) => {
if (this.leftImageWidth <= CONFIGURATION.LEFT_IMAGE_LEFT_LIMIT_SIZE) {
this.leftImageWidth = CONFIGURATION.LEFT_IMAGE_LEFT_LIMIT_SIZE;
this.rightImageWidth = CONFIGURATION.RIGHT_IMAGE_LEFT_LIMIT_SIZE;
this.imageWidth = CONFIGURATION.LEFT_IMAGE_LEFT_LIMIT_SIZE;
} else if (this.leftImageWidth >= CONFIGURATION.LEFT_IMAGE_RIGHT_LIMIT_SIZE) {
this.leftImageWidth = CONFIGURATION.LEFT_IMAGE_RIGHT_LIMIT_SIZE;
this.rightImageWidth = CONFIGURATION.RIGHT_IMAGE_RIGHT_LIMIT_SIZE;
this.imageWidth = CONFIGURATION.LEFT_IMAGE_RIGHT_LIMIT_SIZE;
} else {
this.leftImageWidth = this.imageWidth + this.dragRefOffset; // 滑動結(jié)束時leftImageWidth等于左邊原有Width+拖動距離实胸。
this.rightImageWidth = CONFIGURATION.IMAGE_FULL_SIZE - this.leftImageWidth; // 滑動結(jié)束時rightImageWidth等于340-leftImageWidth他嫡。
this.imageWidth = this.leftImageWidth; // 滑動結(jié)束時ImageWidth等于leftImageWidth。
}
})
)
工程結(jié)構(gòu)&模塊類型
dragtoswitchpictures // har包
|---common
| |---Constants.ets // 常量類
|---data
| |---DragToSwitchPicturesData.ets // 生成模擬數(shù)據(jù)
|---datasource
| |---BasicDataSource.ets // Basic數(shù)據(jù)控制器
| |---DragToSwitchPicturesDataSource.ets // 左右拖動切換圖片數(shù)據(jù)控制器
|---mainpage
| |---DragToSwitchPictures.ets // 主頁面
|---model
| |---DragToSwitchPicturesModule.ets // 左右拖動切換圖片數(shù)據(jù)模型
|---view
| |---DragToSwitchPicturesView.ets // 左右拖動切換圖片視圖
| |---DesignCattleView.ets // AI設(shè)計(jì)視圖
| |---TabsWaterFlowView.ets // 瀑布流嵌套Tabs視圖
模塊依賴
高性能知識點(diǎn)
本例使用了onActionUpdate函數(shù)庐完。該函數(shù)是系統(tǒng)高頻回調(diào)函數(shù)钢属,避免在函數(shù)中進(jìn)行冗余或耗時操作,例如應(yīng)該減少或避免在函數(shù)打印日志门躯,會有較大的性能損耗淆党。
本示例使用了LazyForEach進(jìn)行數(shù)據(jù)懶加載,WaterFlow布局時會根據(jù)可視區(qū)域按需創(chuàng)建FlowItem組件生音,并在FlowItem滑出可視區(qū)域外時銷毀以降低內(nèi)存占用宁否。
本示例使用了cachedCount設(shè)置預(yù)加載的FlowItem的數(shù)量,只在LazyForEach中生效缀遍,設(shè)置該屬性后會緩存cachedCount個FlowItem慕匠,LazyForEach超出顯示和緩存范圍的FlowItem會被釋放。