Android 打造完美的侧滑菜单/侧滑View控件
概述
详细
一.概述
在App中,经常会出现侧滑菜单,侧滑滑出View等效果,虽然说Android有很多第三方开源库,但是实际上
咱们可以自己也写一个自定义的侧滑View控件,其实不难,主要涉及到以下几个要点:
1.对Android中Window类中的DecorView有所了解
2.对Scroller类实现平滑移动效果
3.自定义ViewGroup的实现
下面现在就来说说这里咱们实现侧滑View的基本思路吧,这里我采用的是自定义一个继承于RelativeLayout的控件叫做XCSlideView类吧。
首先从布局文件中inflater出来一个menuView,然后通过addView的方法,将该侧滑View添加到自定义的控件View中
怎么让XCSlideView 这个侧滑View 隐藏到屏幕之外呢?很简单通过ScrollTo方法,移动一个屏幕宽度的距离即可,这里以
左侧滑出为例吧,只需要这样 XCSlideView.this.scrollTo(mScreenWidth, 0);mScreenWidth是屏幕宽度。下面还要处理的就是底下的
半透明黑色的蒙层效果,这个其实就是一个View,然后设置半透明效果。这个当然简单了,关键是咱们让他显示在咱们的自定义侧滑View的下面呢,
这里咱们先给出DecorView的简单分析,方便下面介绍添加半透明View蒙层下:
二.演示效果图
三.代码实现过程解析
根据上面的概述,大家应该知道大概的思路了,下面我就给出自定义侧滑View类的核心代码:
1、自定义侧滑View用到的变量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | //侧滑方向-从哪侧滑出 public static enum Positon { LEFT, RIGHT } private Context mContext; private Activity mActivity; private Scroller mScroller = null ; //侧滑菜单布局View private View mMenuView; //底部蒙层View private View mMaskView; private int mMenuWidth = 0 ; //屏幕宽度 private int mScreenWidth = 0 ; //是否在滑动中 private boolean mIsMoving = false ; //显示登录界面与否 private boolean mShow = false ; //滑动动画时间 private int mDuration = 600 ; //缺省侧滑方向为左 private Positon mPositon = Positon.LEFT; |
2、初始化创建自定义侧滑View:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ** * 创建侧滑菜单View */ public static XCSlideView create(Activity activity) { XCSlideView view = new XCSlideView(activity); return view; } /** * 创建侧滑菜单View */ public static XCSlideView create(Activity activity, Positon positon) { XCSlideView view = new XCSlideView(activity); view.mPositon = positon; return view; } |
3、创建半透明蒙层View,并添加到contentView中去
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /** * 创建 蒙层View并添加到contentView中 */ private void attachToContentView(Activity activity, Positon positon) { mPositon = positon; ViewGroup contentFrameLayout = (ViewGroup) activity.findViewById(android.R.id.content); ViewGroup contentView = ((ViewGroup) contentFrameLayout.getChildAt( 0 )); mMaskView = new View(activity); mMaskView.setBackgroundColor(mContext.getResources().getColor(R.color.mask_color)); contentView.addView(mMaskView, contentView.getLayoutParams()); mMaskView.setVisibility(View.GONE); mMaskView.setClickable( true ); mMaskView.setOnClickListener( new OnClickListener() { @Override public void onClick(View view) { if (isShow()) { dismiss(); } } }); } |
4、设置侧滑菜单View,并添加到DectorView->LinearLayout->内容显示区域View(FrameLayout)中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | /** * 设置侧滑菜单View,并添加到DectorView->LinearLayout->内容显示区域View中 */ public void setMenuView(Activity activity, View view) { mActivity = activity; mMenuView = view; LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); addView(mMenuView, params); mMenuView.post( new Runnable() { @Override public void run() { // TODO Auto-generated method stub mMenuWidth = mMenuView.getWidth(); switch (mPositon) { case LEFT: XCSlideView. this .scrollTo(mScreenWidth, 0 ); break ; case RIGHT: XCSlideView. this .scrollTo(-mScreenWidth, 0 ); break ; } } }); ViewGroup contentFrameLayout = (ViewGroup) activity.findViewById(android.R.id.content); ViewGroup contentView = contentFrameLayout; contentView.addView( this ); FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) this .getLayoutParams(); switch (mPositon) { case LEFT: layoutParams.gravity = Gravity.LEFT; layoutParams.leftMargin = 0 ; break ; case RIGHT: layoutParams.gravity = Gravity.RIGHT; layoutParams.rightMargin = 0 ; break ; } TextView titleFrameLayout = (TextView) activity.findViewById(android.R.id.title); if ( titleFrameLayout != null ){ layoutParams.topMargin = DensityUtil.getStatusBarHeight(mContext); } int flags = mActivity.getWindow().getAttributes().flags; int flag = (flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); if (flag == WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS){ //说明状态栏使用沉浸式 layoutParams.topMargin = DensityUtil.getStatusBarHeight(mContext); } this .setLayoutParams(layoutParams); } |
5、处理自定义侧滑View的侧滑滑动和隐藏效果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | /** * 显示侧滑菜单View */ public void show(){ if (isShow() && !mIsMoving) return ; switch (mPositon) { case LEFT: startScroll(mMenuWidth, -mMenuWidth, mDuration); break ; case RIGHT: startScroll(-mMenuWidth, mMenuWidth, mDuration); break ; } switchMaskView( true ); mShow = true ; } /** * 蒙层显示开关 */ private void switchMaskView( boolean bShow){ if (bShow){ mMaskView.setVisibility(View.VISIBLE); Animation animation = new AlphaAnimation( 0 .0f, 1 .0f); animation.setDuration(mDuration); mMaskView.startAnimation(animation); } else { mMaskView.setVisibility(View.GONE); } } /** * 关闭侧滑菜单View */ public void dismiss() { // TODO Auto-generated method stub if (!isShow() && !mIsMoving) return ; switch (mPositon) { case LEFT: startScroll(XCSlideView. this .getScrollX(), mMenuWidth, mDuration); break ; case RIGHT: startScroll(XCSlideView. this .getScrollX(), -mMenuWidth, mDuration); break ; } switchMaskView( false ); mShow = false ; } public boolean isShow(){ return mShow; } @Override public void computeScroll() { // TODO Auto-generated method stub if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); // 更新界面 postInvalidate(); mIsMoving = true ; } else { mIsMoving = false ; } super .computeScroll(); } /** * 拖动移动 */ public void startScroll( int startX, int dx, int duration){ mIsMoving = true ; mScroller.startScroll(startX, 0 ,dx, 0 ,duration); invalidate(); } |
四.如何使用该自定义侧滑View控件
使用起来,比较简单,通过create方法创建一个侧滑VIew,然后通过setMenuView方法设置一个侧滑View进去,有需要设置
宽度的话, 通过setMenuWidth方法来设置即可,最后用show()方法滑出来就可以啦,使用起来是不是很方便?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | private XCSlideView mSlideViewLeft; //屏幕宽度 private int mScreenWidth = 0 ; View menuViewLeft = LayoutInflater.from(mContext).inflate(R.layout.layout_slideview, null ); mSlideViewLeft = XCSlideView.create( this , XCSlideView.Positon.LEFT); mSlideViewLeft.setMenuView(MainActivity. this , menuViewLeft); mSlideViewLeft.setMenuWidth(mScreenWidth * 7 / 9 ); Button left = (Button)findViewById(R.id.btn_left); left.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub if (!mSlideViewLeft.isShow()) mSlideViewLeft.show(); } }); |
五.项目代码结构图
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?