摘要:但由于這里僅僅是實現一個,因此存儲功能僅通過一個單例類來模擬實現。
本文旨在通過重寫GridView,配合系統彈窗實現仿今日頭條的頻道編輯頁面
注:由于代碼稍長,本文僅列出關鍵部分,完整工程請參見【https://github.com/G9YH/YHChannelEdit】
在開始講解盜版的實現方案前,讓我們先來看看正版與盜版的實際使用效果對比,首先是正版
接下來是盜版
當然,在部分視圖的設計方面還是存在著不小的差異的,但這一頁面大部分基本功能已然實現了。那么接下來,就讓我們開始我們的模仿秀
實現思想事實上,我的頻道列表中,如何實現長按拖拽并交換頻道位置是整個頁面的核心難點。大致實現思路如下
長按某個頻道后,在該頻道上方生成一個與之相同的彈窗,同時隱藏該頻道視圖
當手指按下時,該彈窗跟隨觸摸點移動
彈窗移動過程中,根據觸摸點交換其他頻道位置
當手指抬起時,在觸摸點當前對應的位置處生成一個與彈窗相同的頻道視圖
拋開這一問題,其余部分的實現邏輯都較為簡單,這里不再贅述,下文將更會有具體實現的介紹
實現要點 我的頻道正如前文所言,這一部分的核心在于重寫GridView以及系統彈窗,那么,首先自然是系統彈窗權限的開啟
接下來即是GridView的重寫。首先定義了兩個常量用戶標識當前的模式,即編輯模式和普通模式
private static final int MODE_EDIT = 1; private static final int MODE_NORMAL = 2;
然后實現了OnItemLongClickListener接口
@Override public boolean onItemLongClick(AdapterView> adapterView, View view, int i, long l) { // 已處于移動模式 if (mode == MODE_EDIT) { return false; } textEdit.setText("完成"); .... // 推薦標簽無法移動或刪除 if (i == 0) { return false; } // 判斷并獲取彈窗權限 permissionGetter.alertWindowPermissionRequest(); .... // 初始化彈窗 initWindow(); return true; }
這里需要注意到的是PermissionGetter類,我們知道,盡管在manifests中定義了系統彈窗的權限,但通常而言手機是需要用戶手動為app開啟相關權限的。PermissionGetter類的作用即在于此,該類通過分別處理小米、魅族以及華為等幾個較為特殊的Android系統,基本實現了大部分機型的彈窗權限申請功能
/** * 判斷系統是否已為應用開啟某項權限 * * @param num 權限編號 * @return 已開啟則返回0,否則返回1 */ private int checkPermission(int num) { int version = Build.VERSION.SDK_INT; if (version >= 19) { .... } return -1; } .... /** * Android 6.0之后的手機需要進行彈窗權限的申請 * 其中小米、魅族以及華為三種機型需要特殊處理 */ public void alertWindowPermission() { if (this.checkPermission(24) == 1) { Toast toast = Toast.makeText( context, "請先為您的手機開啟懸浮窗權限", Toast.LENGTH_SHORT); toast.show(); // 處理小米手機權限 if ("Xiaomi".equals(Build.MANUFACTURER)) { .... } } // 處理魅族手機權限 else if ("Meizu".equals(Build.MANUFACTURER)) { .... } // 處理華為手機權限 else if ("Huawei".equals(Build.MANUFACTURER)) { .... } // 處理其他手機權限 else if (Build.VERSION.SDK_INT >= 23) { .... } } }
在長按接口中實現了彈窗的初始化后,將模式mode設置為MODE_EDIT。此時即可通過重寫onTouchEvent(MovtionEvent motionEvent)方法來判斷何時進行彈窗的更新以及關閉等工作
@Override public boolean onTouchEvent(MotionEvent motionEvent) { switch (motionEvent.getAction()) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: if (mode == MODE_EDIT) { updateWindow(motionEvent); } break; case MotionEvent.ACTION_UP: if (mode == MODE_EDIT) { closeWindow(); } break; } return super.onTouchEvent(motionEvent); }
當手指按下時,持續更新彈窗位置,并根據其位置交換其他頻道的位置,當然不要忘記了交換動作相應的動畫
當手指抬起時,將模式mode設置為MODE_NORMAL,并在彈窗當前對應的頻道處生成一個與彈窗相同的視圖,同時移除該彈窗視圖即可
頻道推薦這一部分的實現就較為簡單了,只需利用GridView展示頻道,然后實現OnItemClickListener接口,點擊時將該item移除并添加至我的頻道視圖中即可
@OnItemClick(R.id.grid_recommend) void gridRecommend(int position) { String string = listHolder.getRecommendList().get(position); // 我的頻道中增加標簽 listHolder.getMineList().add(string); // 頻道推薦中刪除標簽 listHolder.getRecommendList().remove(position); // 更新各頻道數據 mineAdapter.moveNotifyDataSetChanged(false, -1); recommendAdapter.notifyDataSetChanged(); }列表緩存
事實上,在實際開發中,通常可以采用SharedPreferences配合服務器端來實現我的頻道以及頻道推薦兩個列表內容的持久化存儲。但由于這里僅僅是實現一個demo,因此存儲功能僅通過一個單例類ListHolder來模擬實現。其中ListHolder單例的實現方式如下,參考了我之前的一篇博客《單例模式的終極實現方案》
public class ListHolder { private List優化改進mineList = new ArrayList<>(); private List recommendList = new ArrayList<>(); private static class Instance { private static ListHolder instance = new ListHolder(); } private ListHolder() { } public static ListHolder getInstance() { return Instance.instance; } public get() & set() }
盡管到目前為止,我們已經實現了大部分的基本功能,但仍與正版有部分差異,例如頻道列表內容的存儲、部分動畫的實現以及視圖設計的差別等等,這一系列問題都將在之后的開發工作中繼續優化
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/67820.html
摘要:在下沒有該問題。解決辦法部分這里隨意,需要用設定部分問題懶加載解決方法稍后補充參考文獻組件按需加載路由懶加載項目中使用將多個組件合并打包并實現按需加載 vue 仿今日頭條 為了增加移動端項目的經驗,近一周通過 vue 仿寫今日頭條,以下就項目實現過程中遇到的問題以及解決方法給出總結,有什么不正確的地方,懇請大家批評指正^?_?^!,代碼倉庫地址為 github 一、實現功能 首頁展示...
閱讀 1485·2021-10-14 09:43
閱讀 1450·2021-10-09 09:58
閱讀 1945·2021-09-28 09:42
閱讀 3736·2021-09-26 09:55
閱讀 1760·2021-08-27 16:23
閱讀 2763·2021-08-23 09:46
閱讀 912·2019-08-30 15:55
閱讀 1428·2019-08-30 15:54