原标題:仿微信朋友圈發表圖檔拖拽和删除功能
中國聯通在香港公布了上市公司2017年中期業績。2017年上半年,公司主要業績名額持續向好,收入穩步回升,服務收入達到人民币1,241.1億元,同比增長3.2%。盈利能力按計劃明顯改善,EBITDA達到人民币435.6億元,同比增長5.5%,EBITDA占服務收入比達到35.1%,同比提升0.8個百分點;權益持有者應占盈利(淨利潤)同比增長68.9%,達到人民币24.2億元。2017上半年資本開支同比大幅下降49.5%,為人民币91.4億元。得益于服務收入逐漸改善以及資本開支大幅下降,公司自由現金流達到人民币375.2億元。
作者簡介
本篇來自senyoung的投稿,分享了一個仿微信朋友圈發表圖檔拖拽和删除功能,希望能對大家有所幫助。
senyoung的部落格位址:
http://my.csdn.net/u01323104
朋友圈實作原理
我們使用 Android Device Monitor 來分析朋友圈釋出圖檔的界面實作原理。如果需要分析其他應用的界面實作也是采用這種方法哦。
打開 Android Device Monitor,選擇DDMS,連接配接上真機,區域2 就會顯示出目前手機正在運作的應用,再點選 區域1,然後新視窗就會顯示出目前頁面分析的結果,點選 區域3 中的相應控件,區域4 中就會選中對應的控件。區域4 中以菜單的層級關系顯示出各控件的關系。
區域4中各參數意義:
eg:(0)FrameLayout[0,0][720,1280]
對應意義:(序号)控件名[x位置,y位置][寬度,高度]
我們這裡主要分析與圖檔拖拽相關的布局實作!通過 4 中的控件層級關系,我們可以畫出這樣一個大概布局圖:
從圖中可以看出,微信團隊使用了自定義的 GridView 實作了圖檔的拖拽和删除功能。
準備
以上分析得出微信使用的是自定義 GridView 實作 item 拖拽和删除功能。xxx,現在都什麼年代了,還使用 GridView 嗎?當然是使用流行的 RecyclerView 實作啦。如果隻是單純地使用 RecyclerView 就能實作的話,那世界就和平。這裡還需要使用 ItemTouchHelper 對拖拽進行處理。
ItemTouchHelper
官方解釋:
This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView
一個讓 RecyclerView 支援滑動删除和拖拽的實用工具類
主要方法
使用
自定義一個類繼承并實作 ItemTouchHelper.Callback 接口,以下方法必須實作:
實作化 ItemTouchHelper 并關聯 RecyclerView
ItemTouchHelper.Callback
ItemTouchHelper 在拖拽和滑動删除的過程中會回調 ItemTouchHelper.Callback 的相關方法:
主要方法
實作過程
先放上最終效果圖:
布局檔案
自定義 MyCallBack 類繼承并實作 ItemTouchHelper.Callbackr 的以下方法:
設定 item 隻能處理拖拽事件,并能夠向左、右、上、下拖拽
重新整理 item
關聯 RecyclerView
調整布局
現在運作程式,界面如下:
手動黑人問号??? 仔細研究布局,原來 recyclerView 的高度設定成了wrap_content,是以無論怎麼拖動,超出recyclerView的邊界的部分就是不會顯示滴!那就把高度設定成match_parent咯,重新調整後的布局如下:
再運作一次,我xx,還是不行。這是什麼鬼,我不是已經設定了match_parent了嗎?這一定有黑科技!經過一番思索,想起了一個不是經常使用的屬性:clipToPadding;設定android:clipToPadding=”false”,果然可以。
居然還有這種操作!
android:clipToPadding
Defines whether the ViewGroup will clip its children and resize (but not clip) any EdgeEffect to its padding, if padding is not zero. This property is set to true by default
設定ViewGroup是否剪切其子View,通俗點講就是:是否允許ViewGroup在padding中繪制子View。預設情況下,此屬性設定為true,即不允許;
另外一個和 clipToPadding 比較相似的屬性是:clipChildren;
android:clipChildren
Defines whether a child is limited to draw inside of its bounds or not. This is useful with animations that scale the size of the children to more than 100% for instance. In such a case, this property should be set to false to allow the children to draw outside of their bounds. The default value of this property is true
一句話概括就是:是否允許子View超出父View
使用場景有:比如說外賣裡的購物車效果
很明顯畫紅色的地方是超出黑色的 View,可以将黑色 View 設定android:clipChildren=”false”,這樣子 View 紅色部分就可以超出父 View 大小。
還發現了一個比較詭異的問題,位址如下:
http://blog.csdn.net/u013231041/article/details/73603891
設定最後一個 item 不能移動
由以上分析可知,ItemTouchHelper.Callback 的 isLongPressDragEnabled() 可以設定是否支援長按拖拽,預設是 true ,即支援長按拖拽。現在我們要自定義指定哪些 item 可以拖拽,哪些不可以,是以我們需要重寫 isLongPressDragEnabled():
取消了支援長按拖拽,就要自己處理 RecyclerView 的觸摸事件,具體實作請參考源代碼。
在長按事件觸發的時候調用以下代碼:
最後還需要在 ItemTouchHelper.Callback 的 onMove() 中添加以下代碼
還有要在 clearView() 方法裡去 notifyDataSetChanged,不然 item 的 position 是沒有交換的
設實作拖拽到底部放手删除功能
item 從拖動到放手的主要處理流程圖如下:
那麼我們應該在哪個地方去判斷item是否到達删除區域呢?在前面介紹的方法,有這麼個方法:onChildDraw,這個方法就會在item拖拽的過程不斷回調并且傳回item的偏移量。有了偏移量之後我們就很容易去判斷item是否到達删除區域了。
偏移量滿足以下條件時,就到達删除區域:
item偏移量>=RecyclerView的高-item底部到RecyclerView頂邊的距離-TextView的高
問題來了,我們怎樣判斷使用者在拖動後放手呢?
我們用 boolean up 來标記,當 up 為 true 時手指擡起,false 為初始狀态。在getAnimationDuration() 中設定其為true。記得需要在 clearView() 中恢複初始值 false ;
還需要在 ItemTouchHelper.Callback 中暴露個接口 DragListener 給外部,用來提示通知外部什麼時候顯示删除區域,以及 item 進入删除區域時的文字提示。
相關代碼由于過長,這裡省略,有興趣的可以通過原文連結去學習。
圖檔相關
一看到圖檔或者說看到 Bitmap,會聯想到什麼?沒錯就是OOM!!!對于Bitmap導緻的OOM要解決它是很有套路可言的。我們都知道圖檔壓縮分為兩種:品質壓縮和尺寸壓縮。可能有些人對這兩個概念不是很清楚!他們的差別是品質壓縮并不會改變圖檔的尺寸,而尺寸壓縮則會改變圖檔的尺寸。當把以檔案形式存在在硬碟上的圖檔,以Bitmap的形式加載到記憶體中的時候,我就必須進行尺寸壓縮,尺寸壓縮可以減少記憶體占用,這樣就解決了OOM。詳細原理參考文章,位址如下:
http://blog.csdn.net/tyk0910/article/details/53462728
對于品質壓縮?主要用在圖檔傳輸上,用于提高傳輸速率,就像我們朋友圈釋出圖檔時,它會對圖檔品質進行壓縮,然後再傳到背景,是以你在朋友圈看到的圖檔都不是原圖檔,都是經過壓縮過的。這裡推薦一個品質壓縮效果和微信差不多的開源庫,位址如下:
https://github.com/Curzibn/Luban
文末demo已實作圖檔尺寸壓縮,即解決了OOM,也解決了拖拽不流暢問題。
總結
有時候我們看到一個覺得酷炫的功能,很想去實作他。這時候不必匆匆下手。我們自己可以先想一下要是我自己會怎樣去實作,然後再用下 Android Device Monitor 大概分析下,更深一步可反編譯一下看下源碼,看他是怎樣實作的,分析兩者的優劣。對于這種情形:一個 View1 根據其他 View2 操作的手勢或狀态的改變而改變的,可以根據這樣的套路去想:這個 View2 是否有提供這種狀态回報的方法什麼的,我是否能把這個回報傳到 View1等。在不确定這個 View2 是否有你想要的方法時,請檢視官方文檔,請檢視官方文檔,請檢視官方文檔,重要的事件說三遍!比如我的删除區域是根據item的拖拽狀态和距離去改變的,那麼你就要去找 ItemTouchHelper.Callback 給我提供了什麼回調啊,哪些方法可以傳回這些東東啊,最後我就寫個接口給通知外部。
demo位址:
https://github.com/kuyue/WeChatPublishImagesDrag
感謝閱讀!歡迎拍磚。
更多
責任編輯: