空手擼一個Android閱讀器,無第三方支持

開篇


幾個月前,晚上夢到在研究翻頁動畫,次日上班居然想起了昨天晚上的夢。search了相關信息,大概要用到數學計算、canvas繪圖等相關內容。對我來說手動繪圖這方面的實踐還是0,想想短時間內應該搞不定,便將此事記在了待做清單內。(公司電腦一個單子,自己Mac一個單子,增加行數的速度遠比刪除的速度快。)

十一長假前夕手頭沒什么事情,看著清單頂部的第一項(時間排序),便照著例文開始繪圖。畫到后面,想想就一張圖片多無聊。算了!加點功能做個帶翻頁動畫的閱讀器吧!

preview1
preview2
preview3

項目地址:GitHub
覺得好的話star一下

文章順序:

  • 翻頁
  • 內容
  • 工具欄

翻頁

主要是按照
Android自定義View——從零開始實現書籍翻頁效果
的邏輯,自己手敲了一遍完成的翻頁動畫,并對代碼進行了調整。
期間也學習了
各個擊破搞明白PorterDuff.Mode
一起看畫布Android Canvas
對代碼理解和調整起到了很大幫助。

這里就不贅述以上文章的內容,直接說明調整后的代碼邏輯。

自定義控件繼承自View,通過重寫

  • onMeasure 來獲取控件的寬高,取得紙張各點的初始值
  • onDraw 用來繪制紙張、陰影、內容
  • onTouchEvent 獲取用戶的手勢事件,重計算各點并繪制,達到翻頁的動效
  • computeScroll 用到了Scroller,來執行手勢事件后的翻頁、恢復效果

初始化

因為視圖是通過Canvas繪制出來的,因此控件初始化時要將

  • Point 書頁運動的關鍵點,用于完成翻頁動畫
  • Paint 內容畫筆
  • Path A、B、C區域的路徑,用于翻頁時路徑的裁剪
  • Gradient 陰影

初始化,并打開setClickable(true),用以接收手勢事件

測量

按View的生命周期,到了onMeasure

設置BookPageView的寬高后,便有了關鍵點的初始值。通過寬高值,初始化A、B兩個不同區域的Bitmap。

繪制

具備了Point、Paint、Path、Gradient、Bitmap,便可以開始繪制Canvas。

將準備好的紙圖片,繪制到Canvas當全局背景,用以填充裁剪所漏出的區域。

具體的繪制過程需要根據翻頁的方向進行區分,因為翻頁的方向不同,導致各關鍵點的計算公式、陰影位置不同。

觸點

區域劃分

ACTION_DOWN時判斷翻頁的位置,預先加載前一頁or后一頁的內容到Bitmap上,并計算各點坐標。

正常狀況下滑動不予翻頁,避免突兀到翻頁效果。

翻頁結束,根據預設條件判斷翻頁還是恢復,并調用Scroller.startScroll。

內容

由于翻頁相關的內容主體邏輯已經在引用中有了詳細的解釋,所以沒必要用篇幅再去講解一遍。

但內容相關的代碼會詳細介紹,涉及到字體大小所影響的頁面顯示、TXT內容的讀取策略等

根據最少知識原則設計內部類ContentController,用以讀取文件、緩存內容、獲取當前內容。

根據TXT小說的大體估計,平均一行約500漢字,共占1000字節約1K。

每頁約1~3行,由每行字數多少決定。

緩存策略為緩存50頁:當前頁的前10頁、包括當前頁的后40頁。

獲取指定頁內容(待優化)

從緩存中取,若指定頁為閥值,則更新緩存。

待優化點:

  • 未預先緩存數據,現在顯示正常是因為onMeasure的多次執行,導致initBitmapA多次執行,從而代替了預先緩存。如果內容不變的話initBitmapA不應該多次執行。

更新指定頁前后的內容(待優化)

根據當前頁計算,需緩存的前后頁碼。

待優化點:

  • 重復內容并沒有重用,(現緩存1~50,需緩存37~87,則37~50內容重復)。但限于讀取的方式,暫沒想到好的解決辦法,見下。

獲取指定范圍的內容(重點)

初始數組,獲取輸入流

標記第一頁,根據字體大小計算每頁及每行可容納的字數。

標準IO操作,讀取每行內容,計算當前行長度+當前頁內容長度,是否超過當頁容量,超過則放到下一頁。當這頁已滿,stringBuffer.toString()放入result數組,頁數加一。

由于每次讀取都是從第1頁開始,若緩存30~80頁,則先讀取前30頁的內容并拋棄,然后才存到數組緩存。

所以要判斷

待優化點:

  • 現讀取的是raw中的文件,可優化選擇文件功能
  • 每次讀文件都是從第一行開始讀,讀字節的話又會造成,前后頁之間的文字亂碼。(暫未想到解決辦法)
  • 當一頁的第一行只有1個或很少的字數并換行,且接下來的段落每行字數都很滿,則會造成最后一行繪出屏幕

工具欄

一個完整的書頁,需要有工具欄來設置字體、字號、背景色等多種功能。這里只提供了工具欄,至于具體的工具待填充。

由于沒有工具,所以


這里完全可以如上所說代碼布局,我省個事!!

在onFinishInflate,獲取對應控件。不必擔心回調優先執行導致控件空指針,此處控件已初始化完成,并setText,在onMeasure和onLayout中也只會對控件進行拉伸顯示

對控件進行測量,切記注意EXACTLY、AT_MOST與實際xml中填寫項的對應。

這里布局子View,需要注意layout時,不要只在乎左上角的點,右下角同樣重要,否則控件會被拉伸。

動畫效果采用了Animator,屬性動畫,通過改變自定義屬性,不停的layout達到效果

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容