Android 自定义View修炼-打造完美的自定义侧滑菜单/侧滑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蒙层下:

 

下面是对上面这张图的解释:

1、DecorView为整个Window界面的最顶层View。

2、DecorView只有一个子元素为LinearLayout。代表整个Window界面,包含通知栏,标题栏,内容显示栏三块区域。

3、LinearLayout里有两个FrameLayout子元素。

  (20)为标题栏显示界面。只有一个TextView显示应用的名称。也可以自定义标题栏,载入后的自定义标题栏View将加入FrameLayout中。

  (21)为内容栏显示界面。就是setContentView()方法载入的布局界面,加入其中。

 

有了上面的DecorVIew知识背景,现在就来说说 怎么添加蒙层View和将自定义侧滑View添加到Activity的DecorView中,首先把蒙层View添加到

(31)customView中去,然后将自定义侧滑View添加到 (21)FrameLayout中去,至于为什么要这样,是因为考虑到自定义侧滑View不一定是宽度为

屏幕宽度,所以才这么做,而且也方面处理有无标题栏,有无采用沉浸式状态栏设计等情况。

二、自定义侧滑View的实现

根据上面的概述,大家应该知道大概的思路了,下面我就给出自定义侧滑View类的核心代码:

1、自定义侧滑View用到的变量:

//侧滑方向-从哪侧滑出
    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:

**
     * 创建侧滑菜单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中去

/**
     * 创建 蒙层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)中

/**
     * 设置侧滑菜单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的侧滑滑动和隐藏效果:

/**
     * 显示侧滑菜单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()方法滑出来就可以啦,使用起来是不是很方便?

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();
            }
        });

四、源码下载:

源码下载http://download.csdn.net/detail/jczmdeveloper/9119423

http://www.cnblogs.com/JczmDeveloper/p/4821148.html

 

时间: 2024-08-23 15:34:50

Android 自定义View修炼-打造完美的自定义侧滑菜单/侧滑View控件(转)的相关文章

Android控件View打造完美的自定义侧滑菜单

一.概述 在App中,经常会出现侧滑菜单,侧滑滑出View等效果,虽然说Android有很多第三方开源库,但是实际上咱们可以自己也写一个自定义的侧滑View控件,其实不难,主要涉及到以下几个要点: 1.对Android中Window类中的DecorView有所了解 2.对Scroller类实现平滑移动效果 3.自定义ViewGroup的实现 首先来看看效果图吧: 下面现在就来说说这里咱们实现侧滑View的基本思路吧,这里我采用的是自定义一个继承于RelativeLayout的控件叫做XCSlid

Android使用自定义控件HorizontalScrollView打造史上最简单的侧滑菜单_Android

侧滑菜单在很多应用中都会见到,最近QQ5.0侧滑还玩了点花样~~对于侧滑菜单,一般大家都会自定义ViewGroup,然后隐藏菜单栏,当手指滑动时,通过Scroller或者不断的改变leftMargin等实现:多少都有点复杂,完成以后还需要对滑动冲突等进行处理~~今天给大家带来一个简单的实现,史上最简单有点夸张,但是的确是我目前遇到过的最简单的一种实现~~~ 1.原理分析 既然是侧滑,无非就是在巴掌大的屏幕,塞入大概两巴掌大的布局,需要滑动可以出现另一个,既然这样,大家为啥不考虑使用Android

Android使用自定义控件HorizontalScrollView打造史上最简单的侧滑菜单

侧滑菜单在很多应用中都会见到,最近QQ5.0侧滑还玩了点花样~~对于侧滑菜单,一般大家都会自定义ViewGroup,然后隐藏菜单栏,当手指滑动时,通过Scroller或者不断的改变leftMargin等实现:多少都有点复杂,完成以后还需要对滑动冲突等进行处理~~今天给大家带来一个简单的实现,史上最简单有点夸张,但是的确是我目前遇到过的最简单的一种实现~~~ 1.原理分析 既然是侧滑,无非就是在巴掌大的屏幕,塞入大概两巴掌大的布局,需要滑动可以出现另一个,既然这样,大家为啥不考虑使用Android

android viewpager根据数组的长度动态加载布局,隐藏控件无效。

问题描述 android viewpager根据数组的长度动态加载布局,隐藏控件无效. 布局文件 android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <android.support.v4.view.ViewPager android:id="@+id/viewpag

Android实现在列表List中显示半透明小窗体效果的控件用法详解_Android

本文实例讲述了Android实现在列表List中显示半透明小窗体效果的控件用法.分享给大家供大家参考,具体如下: Android 在列表List中显示半透明小窗体效果的控件,多的不多直接上代码,要说的都在注释里了: import com.hiapk.market.R; import android.content.Context; import android.graphics.PixelFormat; import android.os.Handler; import android.view

新浪微博android客户端 底部导航消息一栏是否是用的viewpager控件展示的?

问题描述 新浪微博android客户端 底部导航消息一栏是否是用的viewpager控件展示的? 如标题... 每个页面的数据 异步加载是如何进行的 ... .. 解决方案 私认为是通过Fragment结合TabHost实现的.每个页面用一个Fragment管理. 解决方案二: 猜ViewPage+Fragment

图片-Android要实现这种类似ViewPager左右切换功能应该用什么控件或者方法

问题描述 Android要实现这种类似ViewPager左右切换功能应该用什么控件或者方法 有什么开源项目或者方法实现这种功能么? 解决方案 JazzyViewPager github上有,他有多重效果,你可以改造一下 解决方案二: Android使用ViewPager实现左右切换(转)Android使用ViewPager实现左右切换02(转)android viewpager 实现左右无限循环---------------------- 解决方案三: tabhost可以试试 解决方案四: Ga

view类中怎么访问属性栏上的属性网格控件?

问题描述 view类中怎么访问属性栏上的属性网格控件? 小弟在做一个MFC绘图的程序,需要在绘图区中点击相应的图形,如直线,在右侧的属性栏上显示对应图形的参数,使用成员变量的形式访问会出现内存冲突的问题,求高手解答,O(∩_∩)O谢谢! 解决方案 可以通过主框架窗口来中转,在View中很容易访问主框架窗口(比如通过AfxGetMainWnd() SDI程序),在CMainFrame类中肯定定义了相关的属性类的对象成员.

JQuery FlexiGrid的asp.net完美解决方案 dotNetFlexGrid-.Net原生的异步表格控件_jquery

dotNetFlexGrid是一款asp.net原生的异步表格控件,他的前身是Jquery FlexiGrid插件,我们重构了FlexiGrid的大部分Javascript代码,使其工作的更有效率,BUG更少:同时将其封装为dotNet控件,提供了简单易用的使用方式. dotNetFlexGrid扩展和优化了FlexiGrid原有的功能,并提供了更多具有针对性的功能,使用dotNetFlexGrid,您的用户可以轻松拥有如下功能 提供简易的方式自行调整表格列宽 根据实际情况调整表格的大小 针对合