仿QQ5.0侧滑菜单实现
2015-08-23 17:18
381 查看
周末两天时间在公司里研究新版QQ的侧滑菜单的实现,在网上也看到一些实例,也看了慕课网上的课程,终于完全搞明白了整个实现过程,现将我的理解和实现写出来。
这样基本的功能已经实现,再添加上按钮实现
如何实现在xml布局文件中动态修改菜单的右边距呢?test:rightPadding="80dp" 第一步:values文件夹下创建attr.xml文件,设置属性的基本信息
第二步:布局文件中,声明xmlns,在eclipse和andr
4000
oid studio中优点不一样,实现的时候要注意一下。eclipse : xmlns:test="http://schemas.android.com/apk/res/com.example.chengyajun.slidingmenu"android studio : xmlns:test="http://schemas.android.com/apk/res-auto"第三步:重写自定义视图的构造方法,获取自定义属性的值
(4)实现属性动画:内容区域的缩放,菜单的偏移、缩放和透明度变化此时需要引入一个jar包 :nineoldandroids-2.4.0.jar,android3.0以下的需要这个jar包需要重写scrollView的onScrollChanged(),在滑动过程中实现动画效果
自定义控件--显示侧滑菜单和内容的horizontalScrollView
需要用到 HorizontalScrollView控件,同时要实现
(1)初始状态是显示内容,隐藏菜单
(2)当滑动超过屏幕一般的响应。(隐藏菜单or显示菜单)
(3)滑动过程中内容区域的缩放,菜单的偏移和缩放以及透明度变化。
(4)点击按钮,切换菜单的显示和隐藏
(1)初始状态是显示内容,隐藏菜单
第一步:重写了自定义控件的两个参数的构造方法,主要目的是得到屏幕宽度和菜单的右边距//未定义属性时使用 public SlidingMenu(Context context, AttributeSet attrs) { super(context, attrs); // //获取屏幕宽度 WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics outMetrics = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(outMetrics); mScreenWidth = outMetrics.widthPixels; //menu右边距,转化为像素值 mMenuRight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()); // this(context, attrs, 0); }第二步:重写onMeasure(),决定菜单区域和内容区域的宽高,这样自定义视图的宽高就决定了
<pre name="code" class="html">//重写onMeasure(),决定内部子view的宽高,并决定该控件的宽高 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (!once) { //获取LinearLayout mWapper = (LinearLayout) getChildAt(0); //获取菜单和内容 mMenu = (ViewGroup) mWapper.getChildAt(0); mContent = (ViewGroup) mWapper.getChildAt(1); //设置菜单和内容的宽高 mMenu.getLayoutParams().width = mScreenWidth - mMenuRight; mMenuWidth = mScreenWidth - mMenuRight; mContent.getLayoutParams().width = mScreenWidth; //决定子view视图的宽高后该视图的宽高就决定了,无需再设定 once = true; } }
第三步:重写onLayout()方法,决定控件的布局,即初始状态只显示内容区域隐藏菜单区域
//重写onLayout(),决定视图的位置 @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); if (changed) { this.scrollTo(mMenuWidth, 0); } }这里使用到scrollTo()方法,设置scrollView的偏移,实现隐藏菜单。
第四步:重写OnTouchEvent()方法,实现滑动之后如果菜单显示超过屏幕一般则全部显示,否则隐藏
//重写TouchEvent(),监听手抬起时的动作 @Override public boolean onTouchEvent(MotionEvent ev) { int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_UP: { //判断此时scrollview滚动的距离与menu宽度比较,如果大于一般则隐藏,如果小于一半则显示 int scrollX = this.getScrollX(); int helfMenuWidth = mMenuWidth / 2; if (scrollX >= helfMenuWidth) { //隐藏menu this.smoothScrollTo(mMenuWidth, 0); isOpen = false; } else { //显示menu this.smoothScrollTo(0, 0); isOpen = true; } return true; } } return super.onTouchEvent(ev); }
这样基本的功能已经实现,再添加上按钮实现
(2)点击按钮,菜单显示隐藏的切换
第一步:按钮设置监听事件btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //切换菜单 slideMenu.changeMenu(); } });第二步:实现切换:
public void changeMenu() { if(isOpen){//如果是开启则关闭 closeMenu(); }else{ openMenu(); } } //打开菜单,设置标志 private void openMenu() { this.smoothScrollTo(0,0); isOpen = true; } //关闭菜单,设置标志 private void closeMenu() { this.smoothScrollTo(mMenuWidth,0); isOpen = false; }菜单的显示隐藏就是使用的scrollView的smoothSrollTo()这样的函数,让滑动更加平滑。切换是定义了一个标志,状态改变时修改标志,同时注意要在onTouchEvent()中显示隐藏也要修改标志。
(3)实现自定义属性
<com.example.chengyajun.slidingmenu.view.SlidingMenu android:id="@+id/slidemenu" android:layout_width="match_parent" test:rightPadding="80dp" android:layout_height="match_parent">
如何实现在xml布局文件中动态修改菜单的右边距呢?test:rightPadding="80dp" 第一步:values文件夹下创建attr.xml文件,设置属性的基本信息
<?xml version="1.0" encoding="utf-8"?> <resources> <attr name="rightPadding" format="dimension"></attr> <declare-styleable name="SlidingMenu"> <attr name="rightPadding"></attr> </declare-styleable> </resources>
第二步:布局文件中,声明xmlns,在eclipse和andr
4000
oid studio中优点不一样,实现的时候要注意一下。eclipse : xmlns:test="http://schemas.android.com/apk/res/com.example.chengyajun.slidingmenu"android studio : xmlns:test="http://schemas.android.com/apk/res-auto"第三步:重写自定义视图的构造方法,获取自定义属性的值
//一个参数的构造方法,代码中只用new来创建对象 public SlidingMenu(Context context) { // super(context); this(context, null); } //未定义属性时使用 public SlidingMenu(Context context, AttributeSet attrs) { // super(context, attrs); // //获取屏幕宽度 // WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); // DisplayMetrics outMetrics = new DisplayMetrics(); // wm.getDefaultDisplay().getMetrics(outMetrics); // mScreenWidth = outMetrics.widthPixels; // // //menu右边距,转化为像素值 // mMenuRight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()); this(context, attrs, 0); } //三个参数的构造方法,使用了自动以属性 public SlidingMenu(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //对右边距进行设置 // 获取我们定义的属性 TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.SlidingMenu, defStyleAttr, 0); int n = a.getIndexCount(); for (int i = 0; i < n; i++) { int attr = a.getIndex(i); switch (attr) { case R.styleable.SlidingMenu_rightPadding: mMenuRight = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, 50, context .getResources().getDisplayMetrics())); break; } } a.recycle(); //获取屏幕宽度 WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics outMetrics = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(outMetrics); mScreenWidth = outMetrics.widthPixels; }分别重写一个参数,两个参数,三个参数的构造方法,一个参数:new一个对象时候两个参数:没有自定义控件三个参数:使用了自定义控件注意:自定义属性值得获取,需要及时的释放资源。
(4)实现属性动画:内容区域的缩放,菜单的偏移、缩放和透明度变化此时需要引入一个jar包 :nineoldandroids-2.4.0.jar,android3.0以下的需要这个jar包需要重写scrollView的onScrollChanged(),在滑动过程中实现动画效果
@Override protected void onScrollChanged(int l, int t, int oldl, int oldt) {//l=getScrollX() float scale = l*1.0f/mMenuWidth; //隐藏的比例1.0~0 //抽屉菜单的实现,菜单在拉动过程中偏移 //当滑动过程中,移动menu,menu的偏移 // ViewHelper.setTranslationX(mMenu,l);//隐藏多少,就让menu偏移多少,这样保证menu的x起点始终在屏幕x起点 //QQ菜单实现 /** * 内容区域的缩放:1.0~0.7 0.7+0.3*scale * 菜单区域的缩放:0.7~1.0 1.0-0.3*scale * 菜单区域的透明度:0.7~1.0 1.0-0.3*scale * */ //内容区域 缩放 ViewHelper.setScaleX(mContent,0.7f+0.3f*scale); ViewHelper.setScaleY(mContent,0.7f+0.3f*scale); //移动到最后发现全部隐藏了,因为当到达最后的80dp后,区域缩放且默认缩放点在中心,导致看不见 //修改区域的缩放点 ViewHelper.setPivotX(mContent,0); ViewHelper.setPivotY(mContent,mContent.getHeight()/2); //菜单区域 //偏移 ViewHelper.setTranslationX(mMenu,l*0.8f); // //缩放 ViewHelper.setScaleX(mMenu, 1.0f-0.3f*scale); ViewHelper.setScaleY(mMenu,1.0f-0.3f*scale); //透明度 ViewHelper.setAlpha(mMenu,1.0f-0.3f*scale); }通过ViewHelper来实现动画,缩放的比例控制需要根据scrollView的滑动比例来决定。在实现过程中开始没有修改内容区域的缩放中心点,发现直接隐藏了,后面才知道原来到最后的80dp后,区域还要缩放,而且默认缩放中心点在区域中心,这样就看不见了,后来修改区域缩放的中心点未左边中间点,这样就是到最后也是停留在80dp的位置。这样整个自定义的视图就写完了,技术难点也解释了。
相关文章推荐
- Ubuntu12.04下QQ完美走起啊!走起啊!有木有啊!
- QQ商业化,如何实现从0到1的破局?
- 十年生死两茫茫,Linux QQ 突然复活!
- VB实现的《QQ美女找茬游戏》作弊器实例
- flex 控件的重要属性
- 路由器端QQ封堵方案
- 交换机升级排障实例
- Delphi控件ListView的属性及使用方法详解
- QQ输入法自动删除其它输入法的解决方法
- 让普通QQ号也能克隆QQ好友
- web下载的ActiveX控件自动更新
- WinForm实现按名称递归查找控件的方法
- VBS取QQ或TM自动登录代码并防止关闭的脚本
- C#中父窗口和子窗口之间控件互操作实例
- sql2008启动代理未将对象应用到实例解决方案
- MFC中动态创建控件以及事件响应实现方法
- WinForm自定义函数FindControl实现按名称查找控件
- WinForm拖拽控件生成副本的解决方法
- php获取QQ头像并显示的方法