• 自己实现android側滑菜单



    当今的android应用设计中。一种主流的设计方式就是会拥有一个側滑菜单,以图为证:



        实现这种側滑效果,在5.0曾经我们用的最多的就是SlidingMenu这个开源框架,而5.0之后。google推出了自己的側滑实现库。那就是DrawerLayout,它的使用方法比SlidingMenu更简单,并且由于是google的亲生儿子,所以如今人们更倾向于使用DrawerLayout,可是再怎么说,这些都是别人实现好的东西,我们仅仅是拿来用用而已。对于内部的原理。非常多程序猿却不怎么明确,在接下来的文章中我会通过android中的一些基础控件来实现于此相似的效果,当然,或许还有非常多种实现方式,可是主要的原理是类似的。

        首先,我们会用到一个控件:HorizontalScrollView  从名字我们就能够了解到。这是一种水平滑动的控件,也就是当内容大于屏幕的宽度的时候,能够左右滑动来使超出屏幕的内容显示在屏幕上


    第一步:把菜单的布局简单的写出来

    <span style="font-size:18px;"><span style="font-family:KaiTi_GB2312;font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent" android:layout_height="match_parent">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:layout_centerInParent="true"
            >
            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                >
                <ImageView
                    android:id="@+id/img1"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@drawable/ic_launcher"
                    />
                <TextView
                    android:id="@+id/text1"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="item1"
                    android:layout_toRightOf="@id/img1"
                    android:layout_centerVertical="true"
                    />
    
    
            </RelativeLayout>
    
    
            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                >
                <ImageView
                    android:id="@+id/img2"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@drawable/ic_launcher"
                    />
                <TextView
                    android:id="@+id/text2"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="item1"
                    android:layout_toRightOf="@id/img2"
                    android:layout_centerVertical="true"
                    />
    
    
            </RelativeLayout>
    
    
            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                >
                <ImageView
                    android:id="@+id/img3"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@drawable/ic_launcher"
                    />
                <TextView
                    android:id="@+id/text3"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="item1"
                    android:layout_toRightOf="@id/img3"
                    android:layout_centerVertical="true"
                    />
    
    
            </RelativeLayout>
    
    
            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                >
                <ImageView
                    android:id="@+id/img4"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@drawable/ic_launcher"
                    />
                <TextView
                    android:id="@+id/text4"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="item1"
                    android:layout_toRightOf="@id/img4"
                    android:layout_centerVertical="true"
                    />
    
    
            </RelativeLayout>
    
    
            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                >
                <ImageView
                    android:id="@+id/img5"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@drawable/ic_launcher"
                    />
                <TextView
                    android:id="@+id/text5"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="item1"
                    android:layout_toRightOf="@id/img5"
                    android:layout_centerVertical="true"
                    />
    
    
            </RelativeLayout>
        </LinearLayout>
    </RelativeLayout></span></span>



    第二步:写出总体布局

    <span style="font-size:18px;"><span style="font-family:KaiTi_GB2312;font-size:14px;"><?xml version="1.0" encoding="utf-8"?

    > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" > <googleplay.xiaokai.com.qq.SlidMenu android:id="@+id/horscrview" android:layout_width="wrap_content" android:layout_height="match_parent" android:background="@drawable/img_frame_background" android:scrollbars="none" > <LinearLayout android:layout_width="wrap_content" android:layout_height="match_parent" android:orientation="horizontal" > <include layout="@layout/left_menulayout"/> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/qq" > </LinearLayout> </LinearLayout> </googleplay.xiaokai.com.qq.SlidMenu> </LinearLayout></span> </span>




    注意:此时的googplay.xiaokai.com.qq.SlidMenu就是我们要实现的控件。


    第三步:继承HorizontalScrollView实现自己定义控件
    <span style="font-size:18px;">package googleplay.xiaokai.com.qq;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.util.DisplayMetrics;
    import android.util.TypedValue;
    import android.view.MotionEvent;
    import android.view.ViewGroup;
    import android.view.WindowManager;
    import android.widget.HorizontalScrollView;
    import android.widget.LinearLayout;
    
    
    /**
     * Created by 孙晓凯 on 2016/3/27.
     */
    public class SlidMenu extends HorizontalScrollView {
        int mScreenWit;//屏幕宽度
        int mRightWithScr;
        LinearLayout mWrap;
        ViewGroup mMenu;
        ViewGroup mContent;
        int mMenuWidth ;
        private boolean flag;
    
    
        public SlidMenu(Context context, AttributeSet attrs) {
            super(context, attrs);
            //得到屏幕的宽度
            WindowManager winmana = (WindowManager) context.getSystemService(context.WINDOW_SERVICE);
            DisplayMetrics metris = new DisplayMetrics();
            winmana.getDefaultDisplay().getMetrics(metris);
            mScreenWit = metris.widthPixels;//得到的是像素
            //把50dp转换成像素
            mRightWithScr = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics());
    
    
        }
    
    
        public SlidMenu(Context context) {
            super(context);
    
    
        }
    
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    
    
            if (!flag) {
                mWrap = (LinearLayout) getChildAt(0);//得到此空间中的第一个子控件
                mMenu = (ViewGroup) mWrap.getChildAt(0);//得到menu
                mContent = (ViewGroup) mWrap.getChildAt(1);//得到内容控件
    
    
                mMenuWidth = mMenu.getLayoutParams().width = mScreenWit - mRightWithScr;//側滑菜单的宽度为屏幕宽度减去50dp
                mContent.getLayoutParams().width = mScreenWit;//设置内容控件宽度
                flag = true;
            }
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    
    
        /*
        实现的功能是将menu隐藏,通过设置偏移量
         */
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
    
    
            if(changed) {
                this.scrollTo(mMenuWidth, 0);//向左移动
            }
            super.onLayout(changed, l, t, r, b);
        }
    
    
        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            int action = ev.getAction();
            switch (action){
                case MotionEvent.ACTION_UP:
                    int scx = getScrollX(); //就是当前view的左上角相对于母视图的左上角的X轴偏移量
                    if(scx>=mMenuWidth/2){
                        this.smoothScrollTo(mMenuWidth,0);
                    }else{
                        this.smoothScrollTo(0,0);
                    }
                return true;
            }
            return super.onTouchEvent(ev);
        }
    }</span>



        此时程序还不够灵活,比方假设想让让菜单距离屏幕右边的距离是能够自己调控的,应该怎么办呢?
    此时我们能够自己定义一个属性。

    自己定义属性第一步:
        在values目录中创建一个attr.xml文件;

    第二步:在文件里定义属性
    <span style="font-size:18px;"><?

    xml version="1.0" encoding="utf-8"?

    > <resources> <declare-styleable name="SlidMenu"> <attr name="RithtPadding" format="dimension"> </attr> </declare-styleable> </resources> RithtPadding就是自己定义的属性的名称; <?xml version="1.0" encoding="utf-8"?

    > <LinearLayout xmlns:my="http://schemas.android.com/apk/res-auto" <!--注意。要使用自己的命名空间--!> xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" > <googleplay.xiaokai.com.qq.SlidMenu android:id="@+id/horscrview" android:layout_width="wrap_content" android:layout_height="match_parent" android:background="@drawable/img_frame_background" android:scrollbars="none" my:RithtPadding="100dp" <!--自己定义的控件--!> > <LinearLayout android:layout_width="wrap_content" android:layout_height="match_parent" android:orientation="horizontal" > <include layout="@layout/left_menulayout"/> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/qq" > </LinearLayout> </LinearLayout> </googleplay.xiaokai.com.qq.SlidMenu> </LinearLayout></span>





    第三步:在代码中得到布局文件里的属性的值。并进行对应的操作
    <span style="font-size:18px;">public SlidMenu(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            //得到屏幕的宽度
            WindowManager winmana = (WindowManager) context.getSystemService(context.WINDOW_SERVICE);
            DisplayMetrics metris = new DisplayMetrics();
            winmana.getDefaultDisplay().getMetrics(metris);
            mScreenWit = metris.widthPixels;//得到的是像素
    
    
            <span style="color:#3366ff;">TypedArray array = context.getTheme().obtainStyledAttributes(attrs,R.styleable.SlidMenu,defStyleAttr,0);
            int n = array.getIndexCount();
            for(int i=0;i<n;i++){
               int attr = array.getIndex(i);
                switch (attr){
                    case R.styleable.SlidMenu_RithtPadding:
                        mRightWithScr = array.getDimensionPixelSize(attr,(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics()));
                        break;
                }
            }
            array.recycle();//</span>
        }</span>



       嗯。这次好像比較完美了。诶?不正确,人家的側滑都是在左上角有一个点击button的,一点,菜单就能够出来,再一点,菜单就会进去。好吧,我们来实现它!

        仅仅须要两步就可以:

    第一步:在自己定义控件中加入下面三个方法:
     
    <span style="font-size:18px;">/*
        打开菜单
         */
        public void openMenu(){
            if(isOpen)return;
            else {
                this.smoothScrollTo(0,0);//打开
                isOpen = true;
            }
        }
    
    
        /*
        关闭菜单
         */
        public void closeMenu(){
            if(!isOpen){
                return ;
            }else{
                this.smoothScrollTo(mMenuWidth,0);
                isOpen = false;
            }
        }
    
    
        /*
        切换菜单
         */
        public void toggle(){
            if(isOpen){
                closeMenu();
            }else{
                openMenu();
            }
        }</span>



    第二步:在布局文件里定义一个button(这个都会,我就不贴代码了),然后在使用控件的时候在点击方法中直接调用就可以
    <span style="font-size:18px;">public class MainActivity extends AppCompatActivity {
        private SlidMenu slidmenu;
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
    
    
            super.onCreate(savedInstanceState);
            supportRequestWindowFeature(Window.FEATURE_NO_TITLE);<span style="font-family: Arial, Helvetica, sans-serif;">//</span><span style="font-family: Arial, Helvetica, sans-serif;">假设继承的是ActionBarActivity或者是AppCompatActivity就会报错,</span><span style="font-family: Arial, Helvetica, sans-serif;">假设你执意要用这种方法,请继承Activity。</span>
    //        假设你继承的是AppCompatActivity或ActionBarActivity请调用以下的方法取代上面的方法
    //        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
            setContentView(R.layout.activity_main);
            slidmenu = (SlidMenu) findViewById(R.id.horscrview);
        }
        public void toggle(View view){
            slidmenu.toggle();
        }
    
    
    }
    </span>



        OK,大功告成,这次总能够了吧! 嗯,看似还行。可是我们还能够做成更绚丽的效果!

    实现这样的效果也非常easy。主要通过属性动画来实现,在自己定义控件中加入例如以下代码:
    <span style="font-size:18px;">/**
         * 滚动发生时
         */
        @Override
        protected void onScrollChanged(int l, int t, int oldl, int oldt)
        {
            super.onScrollChanged(l, t, oldl, oldt);
    
            /**
             * 差别1:内容区域1.0~0.7 缩放的效果 scale : 1.0~0.0 0.7 + 0.3 * scale
             *
             * 差别2:菜单的偏移量须要改动
             *
             * 差别3:菜单的显示时有缩放以及透明度变化 缩放:0.7 ~1.0 1.0 - scale * 0.3 透明度 0.6 ~ 1.0
             * 0.6+ 0.4 * (1- scale) ;
             *
             */
            float rightScale = 0.7f + 0.3f * scale;
            float leftScale = 1.0f - scale * 0.3f;
            float leftAlpha = 0.6f + 0.4f * (1 - scale);
    
    
            // 调用属性动画。设置TranslationX
            ViewHelper.setTranslationX(mMenu, mMenuWidth * scale * 0.8f);
    
    
            ViewHelper.setScaleX(mMenu, leftScale);
            ViewHelper.setScaleY(mMenu, leftScale);
            ViewHelper.setAlpha(mMenu, leftAlpha);
            // 设置content的缩放的中心点
            ViewHelper.setPivotX(mContent, 0);
            ViewHelper.setPivotY(mContent, mContent.getHeight() / 2);
            ViewHelper.setScaleX(mContent, rightScale);
            ViewHelper.setScaleY(mContent, rightScale);
    
    
        }</span>




        嗯,这次才是大功告成!

    图:


        想要源代码的同学,这是源代码地址:https://github.com/anxiaokai/seslidmenu.git

    參考资料:慕课网

  • 相关阅读:
    Input标签与图片按钮水平对齐解决方法
    下载网页流
    GTD
    Eclipse 运行多个Tomcat实例
    Tomcat启动超时
    Javascript:谈谈JS的全局变量跟局部变量
    影响一生的习惯
    OpenSUSE 安装并启动Tomcat
    ExtJS实战 01——HelloWorld
    eclipse快捷键
  • 原文地址:https://www.cnblogs.com/liguangsunls/p/7205522.html
Copyright © 2020-2023  润新知