主頁 > 移動端開發 > 小程式仿instagram互動(附帶長串列性能優化處理)

小程式仿instagram互動(附帶長串列性能優化處理)

2021-11-08 10:18:30 移動端開發

原文鏈接

傳送門

需求

最近幾天在忙著搞公司專案的一個新的需求,原因是這樣的:公司準備開發一個偏向于社交娛樂項的小程式,其中首頁是可以看到用戶發的話題帖子之類的,每個帖子都至少包含一張圖片或者一個視頻, 然后產品那邊希望首頁可以實作instagram的互動效果,效果圖如下:

instagram效果圖

嗯,大致上這個就是需求的背景,然后就是每個帖子的高度是不確定的,高度大概在500~600px之間,

實作思路

一開始接到這個需求,其實我心里還是有點慌的,畢竟有一段時間不怎么接觸小程式,也不知道小程式更新到什么程度,檔案更新到什么程度,仔細分析一下專案需求,大致上可以歸類為兩個:互動 和 性能優化,

性能優化

因為首頁是一個長串列,眾所周知,頁面一旦渲染的節點過多,就會卡頓,更何況是小程式,并且小程式是分為邏輯層和渲染層,兩者通過setData鏈接,所以處理的時候需要注意兩點:
1. setData的資料量不能太大,記得好像是有個大小限制,,忘了是多少,你們可以自己在官方檔案上找一下;
2. 頁面能夠渲染的帖子數量是有限的,在這里,我是控制為最多渲染25個帖子,
針對于長串列的優化,官方也有相應的組件-[recycle-view](https://github.com/wechat-miniprogram/recycle-view),但是貌似并不符合專案需求,所以被我pass掉了,
雖然沒用官方的組件,但是在組件的檔案里面把對于長串列得性能優化解釋一遍,這里摘抄一下重點:
>? 核心的思路就是只渲染顯示在螢屏的資料,基本實作就是監聽 scroll 事件,并且重新計算需要渲染的資料,不需要渲染的資料留一個空的 div 占位元素,

其實也就是設定一個變數控制該資料是否可以渲染,如果是不能夠渲染得話,那我們就用一個空的view取代它,需要注意的失敗的是:空的框架高度需要設定為帖子的高度,這樣子才不會閃屏,

針對這種思路,我們就可以確定其中一種長串列的性能優化的解決思路:
1. 將資料分為二維陣列,這樣子就可以限制每次setData的資料量,等待資料渲染完成之后,獲取每組資料所占用的總高度,這里的高度是為了在改組資料不渲染時設定占位框的高度,

/**
 * 獲取 有渲染,但是高度還沒獲取到的分組 的高度
 */
_getGroupListHeight() {
    this.data.list.forEach((item, index) => {
        if (item.show && !item.height) {
            const id = 'XXXXXXXX' // 組的id
            let query = wx.createSelectorQuery()

            query.select(id).boundingClientRect(rect => {
                this.data.list[index].height = rect.height
            }).exec();

            this.getTopicHeight(item.data, index) // 獲取串列中每個話題的高度,用于計算滑動時要滾動的距離
        }
    })
}
上面就是一個簡單獲取每組的高度的代碼實體,當該組資料有被渲染但是高度不明的情況下,就會去獲取,加一步判斷是為了防止重獲獲取組的資料,造成不必要的浪費,在獲取每組資料的高度時,還會對應去
獲取該組的每個帖子的高度,這樣子是為了后面實作 仿instagram 互動做準備,

2. 獲取到了每組資料的高度,接下來,我們就可以監聽頁面滾動的高度,從而控制需要渲染的資料,需要注意的一點是,我們需要在該組的資料基礎上,多渲染上兩組和下兩組資料,目的是防止用戶快速滑動的時候出現白屏的不友好體驗,當然也可以根據自己的需要多渲染幾組,
/**
 * 頁面滾動
 * @param e
 */
onPageScroll(e) {
    // android頁面滑動處理(非仿instagram版本)
    if (!this.data.isIos && !this.data.scrollBoxInfo.canUseScrollBox) {
        // 1. 處理當前頁面正在播放的視頻
        if (this.data.currentPlayingId && Math.abs(e.scrollTop - this.data.scrollTop) > 100) {
            this.selectComponent(this.data.currentPlayingId).pauseVideo()
            this.data.currentPlayingId = ''
        }

        // 2. 處理 Andorid 渲染的分組資料
        this._dealAndroidScroll(e)

        // 3. 處理視頻自動播放
        if (this.timer) {
            clearTimeout(this.timer)
        }
        this.timer = setTimeout(() => {
            this.data.scrollTop = e.scrollTop // 記錄下當前的滾動距離,滑動暫停視頻播放的時候需要用到
            this.handleAutoPlay(e) // 視頻自動播放
        }, 300)
    }
}


/**
 * Android 監聽滾動,動態設定分組
 * @param {Object} e
 */
_dealAndroidScroll(e) {
    let max_height = 0 // 最大高度

    for (let i = 0; i <= this.data.topicScroll.show_index; i++) {
        max_height += this.data.list[i].height
    }
    let min_height = max_height - this.data.list[this.data.topicScroll.show_index].height // 最小高度

    // 超過,+1
    if (e.scrollTop > max_height && this.data.topicScroll.show_index < this.data.list.length - 1) {
        ++this.data.topicScroll.show_index
        this._dealListShow(this.data.topicScroll.show_index)
    }

    // 小于,-1
    if (e.scrollTop < min_height) {
        --this.data.topicScroll.show_index
        this._dealListShow(this.data.topicScroll.show_index)
    }
}
這里沒有對代碼進行過濾,代碼實作的效果就是監聽滾動到的位置,并且設定渲染分組資料,因為有些是視頻帖子,所以需要在滾動完成之后實作自動播放視頻的功能,這段代碼只是處理anroid平滑滾動的情況,因為代碼涉及到 instagram 互動的實作,
對于長串列性能優化的思路大致上就這樣:資料分為二位陣列,渲染指定分組的資料,減少渲染的資料量和需要渲染的節點數量,
不需要渲染的資料就用指定高度的空的view替代,指定高度是為了防止閃屏,

仿instagram互動實作

從上面的 instagram 互動視頻可以看出來,我們需要監聽用戶的手勢滑動從而控制帖子的切換,并且每次切換只是切換一個帖子,知道了互動的詳情,我們就可以展開想象了,大致上可以給個基本的實作思路:
1. 監聽手指點擊和手指離開的事件,記錄下手指點擊的高度 && 手指離開的高度,用來判斷用戶滑動的距離和方向;記錄下手指點擊 和 手指離開的時間,可以粗略用來判斷用戶當前的滑動行為是快滑還是慢滑,根據上面的得到的資訊,我們基本上實作滑動切換帖子的操作:
/**
 * 監聽手指點擊操作
 * @param e
 */
touchStart(e) {
    this.data.topicScroll.startTimeStamp = new Date().getTime() // 記錄下當前手指點擊事件
    this.data.topicScroll.startPosition = e.changedTouches[0].clientY // 記錄下手指開始點擊的位置
},

/**
 * 手指離開螢屏
 * @param e
 */
touchEnd(e) {
    const diffTime = new Date().getTime() - this.data.topicScroll.startTimeStamp // 手指離開的時候的時間戳
    const clientY = e.changedTouches[0].clientY // 手指離開螢屏的位置
    const diffY = Math.abs(clientY - this.data.topicScroll.startPosition) // 手指滑動的距離
    const direction = this.data.topicScroll.startPosition - clientY > 0 // 手指滑動的方向,true為向上滑,false為向下滑
    const scrollInfo = this.data.topicScroll

    // 1. 第一個節點手指向下滑動 && 最后一個節點手指向上滑動 不做操作
    if (!scrollInfo.parent_index && !scrollInfo.child_index && !direction) {
        return
    } // 第一個節點向下滑動不做操作
    if (scrollInfo.parent_index === (this.data.list.length - 1) && scrollInfo.child_index === (this.data.list[scrollInfo.parent_index].data.length - 1) && direction) {
        return
    } // 最后一個節點向上滑動不做操作


    // 2. 根據滑動的方向,判斷需要滾動到哪個節點下
    const can_move = (diffTime < 100 && diffY > 50) || (diffTime >= 100 && diffY > 80) // 是否可以滑動,手勢滑動判斷依據
    if (can_move) {
        if (direction) {
            if (scrollInfo.child_index === 4) {
                ++scrollInfo.parent_index
                scrollInfo.child_index = 0
            } else {
                ++scrollInfo.child_index
            }
        } else {
            if (scrollInfo.child_index === 0) {
                --scrollInfo.parent_index
                scrollInfo.child_index = 4
            } else {
                --scrollInfo.child_index
            }
        }
    }

    // 3. 處理滾動
    this._dealScroll(can_move ? pausePlayId : '', can_move)
}
根據監聽到資訊,可以判斷是否切換以及切換到那個帖子的操作,所以我們只需要根據面已經獲取到的帖子高度就可以計算出來要滾動的高度,
2. 根據第一點的操作,我們就可以實作 仿Instagram 互動效果,但是忽略了致命的一點:頁面的慣性滾動,也正是因為這個所謂的“慣性滾動”,我多花了幾天的時間去研究互動的實作:boom:
眾所周知,為了使得頁面的滑動更加流暢,當我們滑動停止的時候,頁面就像會產生慣性一般,自動的滑動一定距離才停下,
安卓下默認有慣性滾動,而在 iOS 下需要額外設定-webkit-overflow-scrolling: touch的樣式
而第一點方案實作的大前提是頁面不能擁有慣性滾動,否則的話頁面無法準確滾動到指定位置,

解決思路

1. ios的解決方案比較簡單,我們只需要設定 -webkit-overflow-scrolling: auto 的樣式即可,
2. 比較麻煩的是android的實作,一開始我是上網找了不少的資料去實作取消頁面的慣性滾動,畢竟頁面滾動的性能是最好的,不過很可惜,我沒有找到可行的方案,所以我選擇退而求其次,模擬手指的滑動,經過對小程式檔案的瀏覽,我選擇可兩種比較可能實作的方案:①使用wxs實作手指滑動的效果;②使用scroll-view的fast-deceleration
屬性,顯而易見,使用wxs方案實作比較復雜,所以我一開始選擇scroll-view這個方案,
scroll-view方案實作的思路與ios類似,比較不同的是頁面的滾動,因為ios是可以直接使用頁面滾動的,即wx.pageScrollTo,而scroll-view則是使用scroll-into-view 或者 scroll-top,為了減少操作,我是直接使用了scroll-top這個屬性,正當我信心滿滿的時候,做出來的效果卻是打了我的臉:每次滾動到指定位置的時候都會抖動一下,雖然沒有仔細去查明原因,不過
我猜想是頁面滾動依然存在一定的慣性滾動,當我們設定了scroll-top的時候,慣性滾動的存在會使得串列偏移位置,最后在偏移回來,這樣子看起來就像是抖動了一下,

正當我準備放棄scroll-view這個方案的時候,無意中讓我發現了scroll-view的api介面,本著想試一下新介面的心態,我嘗試一下使用官方的api介面控制scroll-view滾動,神奇的是,成了!!!!


既然scroll-view做出來的效果勉強還可以,我就直接pass后面的wxs方案,畢竟那一塊的邏輯應該會比較復雜,

因為時使用了scroll-view的api介面,支持的版本庫比較高,是2.14.4,雖然大部分的用戶可以支持,但還是要兼容少部分的用戶,所以android部分我是搞了一個scroll-view版本和平滑滾動版本 fast-deceleration這個特性在開發者工具那里貌

demo

說了這么多,也不一定有人看得下去,demo呈上

結尾

在除錯這個效果的時候,遇到不少的坑,其中有一個坑印象巨深,在此記錄一下:
 touch 期間 touchstart 的目標節點被移除,則對應的 touchend 事件會因為沒有目標節點而缺失,
遇到這個坑是因為小程式同個頁面不允許存在多個視頻,所以需要將沒有播放的視頻使用圖片替換,需要播放的視頻的時候就替換回來,這樣子,就會出現上面的情況,導致無法監聽到touchend事件,整個串列停在原地,沒有滾動到指定位置,

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/352254.html

標籤:其他

上一篇:Android Studio在build.gradle定義全域變數,release、debug版本區分

下一篇:《Android開發藝術探索》第7章- Android 影片深入分析讀書筆記

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more