Android自定義View 仿QQ側(cè)滑菜單的實現(xiàn)代碼
先看看QQ的側(cè)滑效果

分析一下
先上原理圖(不知道能否表達的清楚 ==)
-首先這里使用了 Android 的HorizontalScrollView 水平滑動布局作為容器,當然我們需要繼承它自定義一個側(cè)滑視圖
- 這個容器里面有一個父布局(一般用LinerLayout,本demo用的是),這個父布局里面有且只有兩個子控件(布局),初始狀態(tài)菜單頁的位置在Y軸上存在偏移這樣可以就可以形成主頁疊在菜單頁的上方的視覺效果;然后在滑動的過程程中 逐漸修正偏移,最后菜單頁和主頁并排排列。原理搞清了實現(xiàn)起來就不是事兒了……
具體實現(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);
/**此處因為 把側(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 從默認偏移量到偏移量 為零
*實現(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è)置縮放時的 軸心點**//*
//此處軸心為右邊界的中點
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);*/
}
}
擴展
添加之定義屬性 讓用戶配置菜單距離右邊的邊距的值;
首先在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源碼點擊下載

總結(jié)
以上所述是小編給大家介紹的Android自定義View 仿QQ側(cè)滑菜單的實現(xiàn)代碼,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
Android Studio 2020新版本卡在Gradle downloading/sync failed/下載緩慢/
Android Studio 2020新版本 卡在Gradle downloading / sync failed / 下載緩慢 / 下載超時 親測有效解決辦法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2020-12-12
Android實現(xiàn)修改狀態(tài)欄背景、字體和圖標顏色的方法
本篇文章主要介紹了Android實現(xiàn)修改狀態(tài)欄背景、字體和圖標顏色的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-09-09
Android Studio自定義萬能注釋模板與創(chuàng)建類,方法注釋模板操作
這篇文章主要介紹了Android Studio自定義萬能注釋模板與創(chuàng)建類,方法注釋模板操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03
Kotlin協(xié)程低級api startCoroutine與ContinuationInterceptor
這篇文章主要為大家介紹了Kotlin協(xié)程低級api startCoroutine與ContinuationInterceptor示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-01-01
Android中控件GridView實現(xiàn)設(shè)置行列分割線的方法示例
這篇文章主要介紹了利用Android中控件GridView實現(xiàn)設(shè)置行列分割線的方法,文中給出了詳細的介紹與示例代碼,相信對大家具有一定的參考價值,有需要的朋友們下面來一起看看吧。2017-01-01
Android應用設(shè)置獨立的多語言實戰(zhàn)技巧詳解
這篇文章主要為大家介紹了Android應用設(shè)置獨立的多語言實戰(zhàn)技巧詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12


