Android自定义View 仿QQ侧滑菜单的实现代码

时间:2022-07-28
本文章向大家介绍Android自定义View 仿QQ侧滑菜单的实现代码,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

先看看QQ的侧滑效果

分析一下

先上原理图(不知道能否表达的清楚 ==)

-首先这里使用了 Android 的HorizontalScrollView 水平滑动布局作为容器,当然我们需要继承它自定义一个侧滑视图

– 这个容器里面有一个父布局(一般用LinerLayout,本demo用的是),这个父布局里面有且只有两个子控件(布局),初始状态菜单页的位置在Y轴上存在偏移这样可以就可以形成主页叠在菜单页的上方的视觉效果;然后在滑动的过程程中 逐渐修正偏移,最后菜单页和主页并排排列。原理搞清了实现起来就不是事儿了……

具体实现

布局代码

<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 

自定义的侧滑视图

最核心的部分

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) {
//获取子布局 并设置宽度
//如果菜单在左边 用LinearLayout就行
//      LinearLayout layout = (LinearLayout) this.getChildAt(0);
/**此处因为 把侧边拉出页面设置在了右边 所有用 FrameLayout
* 不然在设置偏移量时 隐藏的侧边菜单会跑到主页面的上面*/
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;
}
/**
* 关闭菜单栏
*/
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;
/**
* 抽屉式侧滑
* scaleLeft 从默认偏移量到偏移量 为零
*实现
* */
float scaleLeft = 0.4f - 0.4f * scale;
/**设置 X 轴方向的偏移量**/
ViewHelper.setTranslationX(bluetooth, -(mBluetoothWidth * scaleLeft));
Log.e("TAG", "mBluetoothWidth+" + mBluetoothWidth);
Log.e("TAG", "=============" + mBluetoothWidth * scale + "scale" + scale);
/*
*//**设置缩放时的 轴心点**//*
//此处轴心为右边界的中点
ViewHelper.setPivotY(home, mScreenWidth);
ViewHelper.setPivotX(home, home.getHeight() / 2);
*//**设置 XY轴方向的 缩放动画(从 1 到 0.9)**//*
float pivoXY = 1 - 0.4f * scale;
ViewHelper.setScaleX(home, pivoXY);
ViewHelper.setScaleY(home, pivoXY);*/
/*
*//**设置透明度**//*
//从 1 到 0.6;
float alpha = 1 - 0.4f * scale;
ViewHelper.setAlpha(home, alpha);*/
}
}

扩展

添加之定义属性 让用户配置菜单距离右边的边距的值; 首先在values文件夹下新建一个attr.xml,写入以下内容:

<resources 
<declare-styleable name="MyScrollView" 
<attr name="rightPanding" format="dimension" / 
<attr name="leftPanding" format="dimension" / 
</declare-styleable 
</resources 

在布局里设置边距

<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源码点击下载

总结

以上所述是小编给大家介绍的Android自定义View 仿QQ侧滑菜单的实现代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对ZaLou.Cn网站的支持!