仿QQ5.0侧滑菜单——自定义属性

转载 2015年11月21日 15:11:55

在上一篇文章中,尝试了仿QQ5.0的侧滑菜单,但是,菜单展开时距离屏幕右侧的宽度(mMenuRightPadding)是在SlidingMenu.java中设定,现在,就来尝试把它设置成自定义属性,可以直接在布局文件中直接设定。

有关于自定义属性,可以参考:http://wujiandong.iteye.com/blog/1184921


第一步:书写xml文件(在res/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>

format=”dimension” 中的dimension表示支持dp、sp等格式(如果只需要int类型,可将dimension改成int即可)

declare-styleable是给自定义控件添加自定义属性用的,相当于一个包含自定义属性元素的集合,在这里,只添加了一个元素


第二步:在布局文件中的根布局下定义命名空间,再进行使用
xmls:自定义空间名=”http://schemas.android.com/apk/res/+当前应用的包名”定义命名空间
接着,就可以像使用android:layout_width=”match_parent”(android为命名空间)一样使用自己的定义的属性了

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:test="http://schemas.android.com/apk/res/com.example.sideslipfollowqq5_0"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <!-- SlidingMenu继承自HorizontalScrollView -->
    <com.example.sideslipfollowqq5_0.SlidingMenu 
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        test:rightPadding="150dp" > <!-- 使用自定义的属性,在这里设置为150dp-->

        <LinearLayout 
           android:layout_width="wrap_content"
           android:layout_height="match_parent"
           android:orientation="horizontal" >

           <include layout="@layout/left_menu"/>

           <LinearLayout
               android:layout_width="match_parent"
               android:layout_height="match_parent" 
               android:background="@drawable/qq" >
           </LinearLayout>

        </LinearLayout>

    </com.example.sideslipfollowqq5_0.SlidingMenu>

</RelativeLayout>

注意:
如果仿照attr.xml在values下写一个attr2.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="rightPadding2" format="dimension" ></attr>

    <declare-styleable name="SlidingMenu2">
        <attr name="rightPadding2" ></attr>
    </declare-styleable>
</resources>

那么在布局文件中,可以依托上一个自定义的命名空间(test)来使用该属性,当然,也可以新定义一个命名空间,比如test2,然后test:rightPadding2="150dp"


第三步:在SlidingMenu.java的构造方法(含3个形参的)中获得在布局文件中设置的自定义属性的值,同时还要改写含1个形参以及含2个形参的构造函数

public class SlidingMenu extends HorizontalScrollView {
    private LinearLayout mWapper;//activity_main.xml中com.example.sideslipfollowqq5_0.SlidingMenu布局
    private ViewGroup mMenu;//activity_main.xml中include的布局
    private ViewGroup mContent;//activity_main.xml中第二个LinearLayout布局

    private int mScreenWidth;//屏幕的宽度

    private int mMenuRightPadding;//菜单完全显示时与屏幕右侧的距离(在SlidingMenu中设置成一个固定值)

    private boolean isOnce=true;//因为onMeasure又可能会多次调用(影响效率),这里用于判断onMeasure是否是第一次调用

    private int mMenuWidth;//代表mMenu的宽度

//  /**
//   * 未使用自定义属性时调用
//   * @param context
//   * @param attrs
//   */
//  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);//getMetrics将会为传入的outMetrics赋值
//      mScreenWidth=outMetrics.widthPixels;
//      
//      //将50dp转化成相应的px
//      //因为dp是相对于分辨率的,而px就是一个像素点,是固定大小的
//      //为了在不同分辨率的屏幕上显示的效果相同,应该将mMenuRightPadding依据不同的分辨率而变换
//      mMenuRightPadding=(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics());
//  }

    public SlidingMenu(Context context) {
        this(context,null);//改写构造参数,调用含2个形参的构造函数
    }

    public SlidingMenu(Context context, AttributeSet attrs) {
        this(context, attrs,0);//改写构造参数,调用含3个形参的构造函数
    }

    /**
     * 当自定义了属性时且使用时,会调用该方法
     * @param context
     * @param attrs
     * @param defStyle
     */
    public SlidingMenu(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);//注意,这里显示的调用父类的构造函数应该放在第一行,因为如果不这样,系统或自动调用一个父类的无参构造函数,而这是不存在的

        //获取自己定义的属性,使用TypeArray类之后要用recycle释放
        TypedArray a=context.getTheme().obtainStyledAttributes(attrs, R.styleable.SlidingMenu, defStyle, 0);//获得attr.xml中<declare-styleable></declare-styleable>下<attr></attr>组成的数组
        int n=a.getIndexCount();//Return the number of indices in the array that actually have data.即获得数组中元素的个数
        for(int i=0;i<n;i++) {
            int attr = a.getIndex(i);//Return an index in the array that has data.即得到数组中第i个具有数据的元素的索引(下标识从0开始)
            switch (attr) {
            case R.styleable.SlidingMenu_rightPadding:  
                //SlidingMenu_rightPadding:"_"前面的为attr.xml中<declare-styleable></declare-styleable>的name,"_"后面的为<attr></attr>的name
                //所以SlidingMenu_rightPadding表示名字为"SlidingMenu"的<declare-styleable></declare-styleable>中名字为"rightPadding"的<attr></attr>

                //getDimensionPixelSize的第一个参数为attr,因为attr同时具有rightPadding设置的值的索引,传入该方法后会根据索引获取rightPadding设置的值
                //getDimensionPixelSize的第二个参数是设置一个默认的值,这里是为了给mMenuRightPadding设置了默认的值50以后
                mMenuRightPadding=a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()));
                break;
            default:
                break;
            }
        }

        a.recycle();//释放资源

        //获取屏幕的宽度
        WindowManager wm=(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics=new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);//getMetrics将会为传入的outMetrics赋值
        mScreenWidth=outMetrics.widthPixels;

        //给mMenuRightPadding设置了默认的值50以后,这一步就不需要了
        //将50dp转化成相应的px
        //因为dp是相对于分辨率的,而px就是一个像素点,是固定大小的
        //为了在不同分辨率的屏幕上显示的效果相同,应该将mMenuRightPadding依据不同的分辨率而变换
        //mMenuRightPadding=(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics());
    }

    /**
     * 设置子View的宽和高以及自己的宽和高
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (isOnce) {
            mWapper = (LinearLayout) getChildAt(0);// 得到activity_main.xml中SlidingMenu布局下的第一个元素,即activity_main.xml中第一个LinearLayout
            mMenu = (ViewGroup) mWapper.getChildAt(0);
            mContent = (ViewGroup) mWapper.getChildAt(1);

            mMenuWidth=mMenu.getLayoutParams().width = mScreenWidth - mMenuRightPadding;// 设置mMenu的宽度
            mContent.getLayoutParams().width = mScreenWidth;
            isOnce = false;
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    /**
     * 通过设置偏移量,将menu隐藏
     */
    @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);// 当第一个参数为正时,滚动条向左移动,内容区域向右移动
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        int action=ev.getAction();//通过action判断用户的操作,是按下、抬起、还是在移动
        switch (action) {
        case MotionEvent.ACTION_UP:
            int scrollX=(int) getScrollX();//得到未在屏幕显示出的内容的左侧区域宽度(即左侧隐藏的宽度),动态变化的
            if(scrollX>=mMenuWidth/2) {
                this.smoothScrollTo(mMenuWidth, 0);
                //this.scrollTo(mMenuWidth, 0);
                //如果内容隐藏的区域>=菜单的一半,隐藏菜单
                //smoothScrollTo方法与scroolTo相似,只不过scroolTo是瞬间完成,而该方法有一个缓冲的效果
            }
            else {
                this.smoothScrollTo(0, 0);
            }
            return true;
        default:
            break;
        }
        return super.onTouchEvent(ev);
    }
}

getDimension
获取某个dimen的值,如果是dp或sp的单位,将其乘以density,如果是px,则不乘 返回float

getDimensionPixelOffset
获取某个dimen的值,如果是dp或sp的单位,将其乘以density,如果是px,则不乘 返回int

getDimensionPixelSize
则不管写的是dp还是sp还是px,都会乘以denstiy.

在类TypedArray和类Resources中都有这三个函数,功能类似,TypedArray中的函数是获取自定义属性的,Resources中的函数是获取android预置属性的


最后,就可以运行看看效果了

源码:http://download.csdn.net/download/qq_22804827/9288579

修改slidingmenu仿QQ5.0侧滑菜单

转自:http://blog.csdn.net/manoel/article/details/39013095/#plain 本文由 孙国威 原创。如需转载,请注明出处! 为了...
  • huweijian5
  • huweijian5
  • 2015年02月28日 20:04
  • 844

ym——Android仿QQ5.0侧滑菜单ResideMenu源码分析

原创博客地址:点击传送 AndroidResideMenu github:https://github.com/SpecialCyCi/AndroidResideMenu  csdn:http:/...
  • cym492224103
  • cym492224103
  • 2014年09月10日 09:23
  • 21230

仿QQ侧滑菜单效果

之前使用过SlideMenu,感觉是一个不错的UI交互方式,在最新的QQ6.1里看到最新的侧滑菜单,滑动主屏幕菜单才显示出来,因此就参考SlideMenu模拟了一个侧滑菜单,同时实现了底部设置按钮的点...
  • TOYOTA11
  • TOYOTA11
  • 2016年01月05日 08:17
  • 1670

高仿QQ6.0侧滑菜单之滑动优化(二)

1、高仿QQ6.0侧滑 2、加上平滑效果 3、github地址:https://github.com/wuyinlei/QQ6.0
  • wuyinlei
  • wuyinlei
  • 2016年02月01日 10:51
  • 4020

Android 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/39257409,本文出自【张鸿洋的博客】上一篇博客带大家实现了:Android 自...
  • lmj623565791
  • lmj623565791
  • 2014年09月15日 09:19
  • 134027

Android使用DrawerLayout仿qq6.6版本侧滑效果

一讲到侧滑菜单,我相信大家都会想到一个开源控件SlidingMenu,在google还没有出来DrawerLayout的时候几乎都是使用Slidingmenu来实现侧滑效果,可以说是效果很不错,自从g...
  • u014741977
  • u014741977
  • 2016年12月29日 14:46
  • 3124

DrawableLayout实现仿QQ侧滑菜单

由于移动设备的屏幕限制,在主界面同时显示很多东西是不大显示的事,因而很多时候我们都会把一些功能选项放在菜单。但传统的菜单界面比较单调,而且交互体验并不是很好,因此,侧滑菜单也因此应运而生。实现侧滑菜单...
  • eyckwu
  • eyckwu
  • 2017年03月06日 13:32
  • 852

Android自定义View之仿QQ侧滑菜单实现

最近,由于正在做的一个应用中要用到侧滑菜单,所以通过查资料看视频,学习了一下自定义View,实现一个类似于QQ的侧滑菜单,顺便还将其封装为自定义组件,可以实现类似QQ的侧滑菜单和抽屉式侧滑菜单两种菜单...
  • bingjianIT
  • bingjianIT
  • 2016年10月28日 17:23
  • 3180

Android自定义控件——侧滑菜单

当我们打开某些应用的时候,总是会出现“侧滑菜单”这样的效果,至于这种侧滑菜单是谁首先创造出来的,已经不重要,但是侧滑菜单确实功能新颖,用户体验极好,以至于市面上很多很多的应用也纷纷加入侧滑菜单的效果,...
  • lee_tianya
  • lee_tianya
  • 2014年09月22日 11:41
  • 7932

仿QQ5.0的侧滑菜单

仿照QQ5.0写的简单的侧滑菜单
  • qq_22804827
  • qq_22804827
  • 2015年11月20日 11:58
  • 208
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:仿QQ5.0侧滑菜单——自定义属性
举报原因:
原因补充:

(最多只允许输入30个字)