Android自定義View 仿QQ側(cè)滑菜單的實(shí)現(xiàn)代碼
先看看QQ的側(cè)滑效果
分析一下
先上原理圖(不知道能否表達(dá)的清楚 ==)
-首先這里使用了 Android 的HorizontalScrollView
水平滑動布局作為容器,當(dāng)然我們需要繼承它自定義一個側(cè)滑視圖
- 這個容器里面有一個父布局(一般用LinerLayout,本demo用的是),這個父布局里面有且只有兩個子控件(布局),初始狀態(tài)菜單頁的位置在Y軸上存在偏移這樣可以就可以形成主頁疊在菜單頁的上方的視覺效果;然后在滑動的過程程中 逐漸修正偏移,最后菜單頁和主頁并排排列。原理搞清了實(shí)現(xiàn)起來就不是事兒了……
具體實(shí)現(xiàn)
布局代碼
<fierce_luk.com.sideslipviewdemo2.SideslipView android:id="@+id/my_veiw" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="none" luk:leftPanding="200dp"> <!--如果菜單在左邊直接用 LinearLayout--> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <TextView android:id="@+id/image2" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@mipmap/homepage" android:gravity="center" android:tag="0" android:text="菜單" android:textColor="@color/colorAccent" android:textSize="60sp" /> <TextView android:id="@+id/image1" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/color1" android:gravity="center" android:tag="1" android:text="主頁面" android:textColor="@color/colorAccent" android:textSize="60sp" /> </FrameLayout> <!--<fragment--> <!--android:name="com.luk.bluetoothapp.fragment.MyBluetoothDevice"--> <!--android:layout_width="match_parent"--> <!--android:layout_height="match_parent"--> <!--android:tag="1" />--> <!--<fragment--> <!--android:name="com.luk.bluetoothapp.fragment.HomeFragment"--> <!--android:layout_width="match_parent"--> <!--android:layout_height="match_parent"--> <!--android:tag="0" />--> </fierce_luk.com.sideslipviewdemo2.SideslipView>
自定義的側(cè)滑視圖
最核心的部分
public class SideslipView extends HorizontalScrollView { private int mScreenWidth;//屏幕寬度 private int mMenuLeftPadding; private int mBluetoothWidth;//菜單的寬度 private int mHalfMenuWidth; View home; View bluetooth; protected boolean isOpen; protected boolean isFirst = true; public SideslipView(Context context) { // super 改 this this(context, null); } public SideslipView(Context context, AttributeSet attrs) { // super 改 this this(context, attrs, 0); } public SideslipView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //測量屏幕寬度 WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics metrics = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(metrics); mScreenWidth = metrics.widthPixels; // mScreenWidth = context.getResources().getDisplayMetrics().widthPixels; Log.e("TAG", "MyScrollView: mScreenWidth" + mScreenWidth); //獲取 自定義的屬性值 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyScrollView); int n = a.length(); for (int i = 0; i < n; i++) { int arrt = a.getIndex(i); switch (arrt) { case R.styleable.MyScrollView_leftPanding: mMenuLeftPadding = (int) a.getDimension(R.styleable.MyScrollView_leftPanding, 0); break; default: break; } } Log.e("TAG", "MyScrollView: mMenuLeftPadding" + mMenuLeftPadding); a.recycle(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (isFirst) { //獲取子布局 并設(shè)置寬度 //如果菜單在左邊 用LinearLayout就行 // LinearLayout layout = (LinearLayout) this.getChildAt(0); /**此處因?yàn)?把側(cè)邊拉出頁面設(shè)置在了右邊 所有用 FrameLayout * 不然在設(shè)置偏移量時 隱藏的側(cè)邊菜單會跑到主頁面的上面*/ FrameLayout layout = (FrameLayout) this.getChildAt(0); home = layout.getChildAt(1); bluetooth = layout.getChildAt(0); LayoutParams params = new LayoutParams(mBluetoothWidth, getResources().getDisplayMetrics().heightPixels); params.setMargins(mScreenWidth, 0, 0, 0); bluetooth.setLayoutParams(params); mBluetoothWidth = mScreenWidth - mMenuLeftPadding; home.getLayoutParams().width = mScreenWidth; bluetooth.getLayoutParams().width = mBluetoothWidth; mHalfMenuWidth = mBluetoothWidth / 2; isFirst = false; } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); //首先隱藏 Bluetooth if (changed) this.scrollTo(0, mBluetoothWidth); } Animation anim; @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_UP: int scrollX = getScrollX(); if (scrollX >= mHalfMenuWidth) { Log.e("TAG", "===="); this.smoothScrollTo(mBluetoothWidth, 0); isOpen = true; } else { this.smoothScrollTo(0, 0); isOpen = false; } //必須消耗事件 return true; } return super.onTouchEvent(ev); //return true; } /** * 打開菜單欄 */ protected void openMenu() { if (isOpen) return; this.smoothScrollTo(mBluetoothWidth, 0); isOpen = true; } /** * 關(guān)閉菜單欄 */ protected void closeMenu() { if (!isOpen) return; this.smoothScrollTo(0, 0); isOpen = false; } /** * 按鈕切換菜單 */ public void toggleMenu() { if (isOpen) closeMenu(); else openMenu(); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); //此處 l 起始值為零(沒有偏移) Log.e("TAG", "l=" + l + " t=" + t); Log.e("TAG", "oldl=" + oldl + " oldt=" + oldt); // scale 在 1 到 0 之間 float scale = l * 1.0f / mBluetoothWidth; /** * 抽屜式側(cè)滑 * scaleLeft 從默認(rèn)偏移量到偏移量 為零 *實(shí)現(xiàn) * */ float scaleLeft = 0.4f - 0.4f * scale; /**設(shè)置 X 軸方向的偏移量**/ ViewHelper.setTranslationX(bluetooth, -(mBluetoothWidth * scaleLeft)); Log.e("TAG", "mBluetoothWidth+" + mBluetoothWidth); Log.e("TAG", "=============" + mBluetoothWidth * scale + "scale" + scale); /* *//**設(shè)置縮放時的 軸心點(diǎn)**//* //此處軸心為右邊界的中點(diǎn) ViewHelper.setPivotY(home, mScreenWidth); ViewHelper.setPivotX(home, home.getHeight() / 2); *//**設(shè)置 XY軸方向的 縮放動畫(從 1 到 0.9)**//* float pivoXY = 1 - 0.4f * scale; ViewHelper.setScaleX(home, pivoXY); ViewHelper.setScaleY(home, pivoXY);*/ /* *//**設(shè)置透明度**//* //從 1 到 0.6; float alpha = 1 - 0.4f * scale; ViewHelper.setAlpha(home, alpha);*/ } }
擴(kuò)展
添加之定義屬性 讓用戶配置菜單距離右邊的邊距的值;
首先在values文件夾下新建一個attr.xml,寫入以下內(nèi)容:
<resources> <declare-styleable name="MyScrollView"> <attr name="rightPanding" format="dimension" /> <attr name="leftPanding" format="dimension" /> </declare-styleable> </resources>
在布局里設(shè)置邊距
<fierce_luk.com.sideslipviewdemo2.SideslipView android:id="@+id/my_veiw" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="none" luk:leftPanding="200dp">
其他的就不贅述了,看看效果
- 源碼下載Demo源碼點(diǎn)擊下載
總結(jié)
以上所述是小編給大家介紹的Android自定義View 仿QQ側(cè)滑菜單的實(shí)現(xiàn)代碼,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
Android 使用Glide加載網(wǎng)絡(luò)圖片等比例縮放的實(shí)現(xiàn)方法
這篇文章主要介紹了Android 使用Glide加載網(wǎng)絡(luò)圖片等比例縮放的實(shí)現(xiàn)方法,需要的朋友可以參考下2018-08-08Android使用BottomTabBar實(shí)現(xiàn)底部導(dǎo)航頁效果
這篇文章主要介紹了Android使用BottomTabBar實(shí)現(xiàn)底部導(dǎo)航頁效果,本文通過實(shí)例代碼結(jié)合文字說明的形式給大家介紹的非常詳細(xì),需要的朋友參考下吧2018-03-03adnroid已安裝應(yīng)用中檢測某應(yīng)用是否安裝的代碼實(shí)例
這篇文章主要介紹了Android怎么檢測一個應(yīng)用是否安裝的方法,大家參考使用吧2013-11-11kotlin實(shí)戰(zhàn)教程之lambda編程
這篇文章主要給大家介紹了關(guān)于kotlin實(shí)戰(zhàn)教程之lambda編程的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用kotlin具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-09-09Android中自定義PopupWindow實(shí)現(xiàn)彈出框并帶有動畫效果
這篇文章主要介紹了Android中自定義PopupWindow實(shí)現(xiàn)彈出框并帶有動畫效果的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-09-09Android底部菜單欄實(shí)現(xiàn)的實(shí)例代碼
這篇文章主要介紹了Android底部菜單欄實(shí)現(xiàn)的實(shí)例代碼,本文通過使用RadioGroup來實(shí)現(xiàn)底部導(dǎo)航菜單欄。現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-05-05Android 圖片存入系統(tǒng)相冊更新顯示實(shí)例詳解
這篇文章主要介紹了Android 圖片存入系統(tǒng)相冊更新顯示實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-06-06Android RecycleView實(shí)現(xiàn)Item拖拽效果
RecyclerView是Android一個更強(qiáng)大的控件,其不僅可以實(shí)現(xiàn)和ListView同樣的效果,還有優(yōu)化了ListView中的各種不足。本文將介紹通過RecyclerView實(shí)現(xiàn)Item拖拽效果以及拖拽位置保存,感興趣的可以參考一下2022-01-01Android6.0編程實(shí)現(xiàn)雙向通話自動錄音功能的方法詳解
這篇文章主要介紹了Android6.0編程實(shí)現(xiàn)雙向通話自動錄音功能的方法,結(jié)合實(shí)例形式分析了Android錄音功能的原理、實(shí)現(xiàn)技巧與相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-07-07