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

转载请注明出处:http://blog.csdn.net/allen315410/article/details/39397445

当我们打开某些应用的时候,总是会出现“侧滑菜单”这样的效果,至于这种侧滑菜单是谁首先创造出来的,已经不重要,但是侧滑菜单确实功能新颖,用户体验极好,以至于市面上很多很多的应用也纷纷加入侧滑菜单的效果,以下是我从应用市场上下载来的几个应用,随时截图发在这里,看看别人(大型互联网公司)都做这种效果,那么我们自己在没有很好的“创意”下,是不是可以选择“山寨”(自定义)一下呢?!

     
    

怎么样?相信你们都在各大App中已经领教过其“风采”了,感觉这种效果确实不错!那么,我们怎样去“山寨”呢?别急,在Java或者Android这样的开源世界里,这种常用常见的事物,早就有“开源勇士”为我铺好了道路。老外的技术确实牛逼,早就已经写好了这些,而且功能强大,易于项目集成,没错,就是大名鼎鼎的SlidingMenu,在GitHub中可以找到,SlidingMenu的github链接在这里https://github.com/jfeinstein10/SlidingMenu 不过,我们今天不是要讨论这个开源的SlidingMenu的,毕竟这个开源的代码在使用起来也不一定就方便,因为首先项目中需要导包,如果项目要求严格的话,某些代码就需要修改了,就避免不了看“老外大神”的源码,这是一件比较痛苦的事情,而且SlidingMenu同时又引用了另外一个开源项目ActionBarSherlock,使得代码结构更加难以阅读,关于SlidingMenu,我会在下一篇博客中进行讲解。

接下来,我们就自己动手来实现一个自定义的SlidingMenu,以下是我画的一份草图,能够大致分析出侧滑菜单的一些细节:

如果觉得感官不强烈,那废话不说,先上我做好后运行的效果,针对这个效果后,再慢慢讲解

好,效果如上图所示的样子,可以看到,整个侧滑菜单其实还是使用了Android给我们提供的各种组件组合而成的,没有必须制造一个“从无到有”的过程,这里必须使用android已有控件的基础上构建一个自定控件,既然如此,整个的自定义控件就没必要继承View类了,而是选择继承ViewGroup类。为什么要继承ViewGroup呢?原因是,ViewGroup下提供了一个onLayout方法,这个方法是用来为自定义组件下各个子元素显示做排版的,当然ViewGroup下还有例如getChildXXX()的方法,用来获取子元素,单独对子元素进行控制,这些都是View做不到的。

仔细看图会发现,其实该自定义的滑动菜单界面就是两个不同的布局,组合起来放在一个视图下,进行来回切换而已,那么关于这些布局的代码如下:

内容界面slidemenu_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/top_bar_bg"
        android:orientation="horizontal" >

        <ImageButton
            android:id="@+id/ib_back"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/main_back" />

        <View
            android:layout_width="1dip"
            android:layout_height="fill_parent"
            android:layout_margin="5dip"
            android:background="@drawable/top_bar_divider" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="10dip"
            android:text="网易新闻"
            android:textColor="@android:color/white"
            android:textSize="28sp" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/ll_content"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >
    </LinearLayout>

</LinearLayout>

菜单界面slidemenu_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="240dip"
    android:layout_height="match_parent" >

    <LinearLayout
        android:layout_width="240dip"
        android:layout_height="match_parent"
        android:background="@drawable/menu_bg"
        android:orientation="vertical" >

        <TextView
            style="@style/tab_style"
            android:background="#33663300"
            android:drawableLeft="@drawable/tab_news"
            android:text="新闻" />

        <TextView
            style="@style/tab_style"
            android:drawableLeft="@drawable/tab_read"
            android:text="订阅" />

        <TextView
            style="@style/tab_style"
            android:drawableLeft="@drawable/tab_local"
            android:text="本地" />

        <TextView
            style="@style/tab_style"
            android:drawableLeft="@drawable/tab_ties"
            android:text="跟帖" />

        <TextView
            style="@style/tab_style"
            android:drawableLeft="@drawable/tab_pics"
            android:text="图片" />

        <TextView
            style="@style/tab_style"
            android:drawableLeft="@drawable/tab_focus"
            android:text="话题" />

        <TextView
            style="@style/tab_style"
            android:drawableLeft="@drawable/tab_vote"
            android:text="投票" />

        <TextView
            style="@style/tab_style"
            android:drawableLeft="@drawable/tab_ugc"
            android:text="聚合阅读" />
    </LinearLayout>

</ScrollView>

需要用到的Style:

<style name="tab_style">
        <item name="android:layout_width">fill_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:background">@drawable/tab_background</item>
        <item name="android:drawablePadding">20dip</item>
        <item name="android:gravity">center_vertical</item>
        <item name="android:padding">20dip</item>
        <item name="android:textColor">@android:color/white</item>
        <item name="android:textSize">25sp</item>
        <item name="android:onClick">tabClick</item>
        <item name="android:clickable">true</item>
    </style>

主界面activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <com.example.slidingmenu.view.SlideMenu
        android:id="@+id/slidemenu"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >

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

        <include layout="@layout/slidemenu_main" />
    </com.example.slidingmenu.view.SlideMenu>

</RelativeLayout>

以下是侧滑菜单实现的主要两个步骤:

SlideMenu extends ViewGroup

1. 测量宽和高(测量菜单和主界面的宽和高)

2. 布置viewgroup中子控件的位置

3. 触摸事件的处理:

按下: x轴的最后一次偏移量

移动: 当前最新的x轴偏移量, x轴的最后一次偏移量

1. 计算增量值

增量值 = x轴的最后一次偏移量 -  当前最新的x轴偏移量;

2. 根据增量值, 更新屏幕显示的位置

scrollBy(增量值, 0);

3. x轴的最后一次偏移量 = 当前最新的x轴偏移量;

抬起: 获取当前移动到的X轴的位置,与菜单的中心点坐标进行对比

当前移动的X轴位置 < 菜单中心点,切换到菜单

当前移动的X轴位置 > 菜单中心点,切换到主界面

4,当手指抬起的时候,判断中心线坐标实现左右滑动切换的时候,明显切换速度过快了,没有一个渐变的过程,这样给用户体验就差了。那么,我们该怎么实现这个渐渐切换菜单和主界面的效果呢?实现的方式肯定不是唯一的,但是在这里,我推荐使用Android为我们提供好的一个Helper类——Scroller。

Android里Scroller类是为了实现View平滑滚动的一个Helper类。通常在自定义的View时使用,在View中定义一个私有成员mScroller = new Scroller(context)。设置mScroller滚动的位置时,并不会导致View的滚动,通常是用mScroller记录/计算View滚动的位置,再重写View的computeScroll(),完成实际的滚动。

ViewGroup.java

 protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
        return child.draw(canvas, this, drawingTime);
    }

接着触发View下的相关方法:

boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
	...
	...
	computeScroll();
	...
}

看看computeScroll();这个方法:

public void computeScroll() {
    }

通过翻阅Android的相关源码会发现,在自定义控件里调用了父类的invalidate();方法刷新界面时,会触发ViewGroup下drawChild方法,而这个方法会触发View下的draw方法,在draw方法又触发了computeScroll()方法,再继续看这个computeScroll()方法,是个空方法,需要我们在子类中去实现这个方法,提供给刷新界面时被调用相关的逻辑,在这里当然是怎么实现渐变过程的逻辑了。以下是Scroller类的相关方法:

mScroller.getCurrX()    //获取mScroller当前水平滚动的位置

mScroller.getCurrY()    //获取mScroller当前竖直滚动的位置

mScroller.getFinalX()   //获取mScroller最终停止的水平位置

mScroller.getFinalY()     //获取mScroller最终停止的竖直位置

mScroller.setFinalX(int newX)    //设置mScroller最终停留的水平位置,没有动画效果,直接跳到目标位置

mScroller.setFinalY(int newY)    //设置mScroller最终停留的竖直位置,没有动画效果,直接跳到目标位置

mScroller.startScroll(int startX, int startY, int dx, int dy)   //滚动,startX, startY为开始滚动的位置,dx,dy为滚动的偏移量

mScroller.startScroll(int startX, int startY, int dx, int dy, int duration)    //滚动,startX, startY为开始滚动的位置,dx,dy为滚动的偏移量, duration为完成滚动的时间

mScroller.computeScrollOffset()   //返回值为boolean,true说明滚动尚未完成,false说明滚动已经完成。这是一个很重要的方法,通常放在View.computeScroll()中,用来判断是否滚动是否结束。

主要代码如下,SlideMenu.java

package com.example.slidingmenu.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Scroller;

public class SlideMenu extends ViewGroup {

	/** 记录上一次移动的位置 */
	private int mMostRecentX;
	/** 标记菜单界面 */
	private final int MENU_VIEW = 1;
	/** 标记主界面 */
	private final int MAIN_VIEW = 2;
	/** 标记当前屏幕显示的界面 */
	private int currentView = MAIN_VIEW;
	/** 模拟数据 */
	private Scroller scroller;
	/** 向左滑动菜单隐藏的一定距离 */
	private int mTouchSlop;

	public SlideMenu(Context context, AttributeSet attrs) {
		super(context, attrs);
		scroller = new Scroller(context);
		mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// TODO Auto-generated method stub
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);

		// 初始化菜单和主界面的宽和高
		initView(widthMeasureSpec, heightMeasureSpec);
	}

	/**
	 * 测量菜单和主界面的宽和高
	 *
	 * @param widthMeasureSpec
	 * @param heightMeasureSpec
	 */
	private void initView(int widthMeasureSpec, int heightMeasureSpec) {
		// 获取菜单并且测量宽高
		View menuView = this.getChildAt(0);
		// menuView.getLayoutParams().width拿到布局参数 heightMeasureSpec屏幕高度
		menuView.measure(menuView.getLayoutParams().width, heightMeasureSpec);

		// 获取主界面并且测量宽高
		View mainView = this.getChildAt(1);
		mainView.measure(widthMeasureSpec, heightMeasureSpec);
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		// 菜单
		View menuView = this.getChildAt(0);
		menuView.layout(-menuView.getMeasuredWidth(), 0, 0, b);
		// 主界面
		View mainView = this.getChildAt(1);
		mainView.layout(l, t, r, b);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN: // 手指按下
			mMostRecentX = (int) event.getX();
			break;
		case MotionEvent.ACTION_MOVE: // 手指移动
			// 1. 计算增量值 增量值 = x轴的最后一次偏移量 - 当前最新的x轴偏移量;
			int currentX = (int) event.getX();
			int delta = mMostRecentX - currentX;

			// 2. 根据增量值, 更新屏幕显示的位置 scrollBy(增量值, 0);
			// 判断是否超出左右边界
			int scrollX = getScrollX() + delta; // 移动后的x轴偏移量
			if (scrollX < -this.getChildAt(0).getWidth()) {
				// 超出左边界
				scrollTo(-this.getChildAt(0).getWidth(), 0);
			} else if (scrollX > 0) {
				// 超出右边界
				scrollTo(0, 0);
			} else {
				scrollBy(delta, 0);
			}

			// 3. x轴的最后一次偏移量 = 当前最新的x轴偏移量;
			mMostRecentX = currentX;

			break;
		case MotionEvent.ACTION_UP: // 手指抬起
			// 菜单的中心点
			int menuCenter = -this.getChildAt(0).getWidth() / 2;
			// 当前移动到的X轴坐标
			int _x = getScrollX();
			if (_x < menuCenter) {
				// 切换到菜单界面
				// scrollTo(-this.getChildAt(0).getWidth(), 0);
				currentView = MENU_VIEW;
			} else {
				// 切换到主界面
				// scrollTo(0, 0);
				currentView = MAIN_VIEW;
			}
			switchView();
			break;
		default:
			break;
		}

		return true;
	}

	@Override
	public void computeScroll() {
		// 更新当前的X轴偏移量
		if (scroller.computeScrollOffset()) { // 返回true代表正在模拟数据,false 已经停止模拟数据
			scrollTo(scroller.getCurrX(), 0); // 更新X轴的偏移量

			invalidate();
		}
	}

	/**
	 * 菜单和主界面切换
	 */
	private void switchView() {
		int startX = getScrollX();
		int dx = 0;
		if (currentView == MAIN_VIEW) {
			dx = 0 - startX;
		} else if (currentView == MENU_VIEW) {
			dx = -getChildAt(0).getWidth() - startX;
		}

		// 开始模拟数据
		scroller.startScroll(startX, 0, dx, 0, Math.abs(dx) * 5);
		invalidate(); // 刷新界面,会触发ViewGroup下drawChild-->child.draw-->computeScroll
	}

	/**
	 * 事件分发机制,处理菜单向左滑动时,时间消费事件
	 */
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			mMostRecentX = (int) ev.getX();
			break;
		case MotionEvent.ACTION_MOVE:
			int moveX = (int) ev.getX();
			int diff = moveX - mMostRecentX;
			if (Math.abs(diff) > mTouchSlop)
				return true; // 认为是横向移动,消耗掉此事件
			break;
		case MotionEvent.ACTION_UP:

			break;
		default:
			break;
		}
		return super.onInterceptTouchEvent(ev);
	}

	/**
	 * 判断菜单是否显示
	 *
	 * @return
	 */
	public boolean isShowMenu() {
		return currentView == MENU_VIEW;
	}

	/**
	 * 隐藏菜单
	 */
	public void hideMenu() {
		currentView = MAIN_VIEW;
		switchView();
	}

	/**
	 * 显示菜单
	 */
	public void showMenu() {
		currentView = MENU_VIEW;
		switchView();
	}

}

再看菜单的布局文件,细心会发现菜单布局中含有ScrollView,该组件上下滑动,会阻碍菜单键的左右滑动,描述的不太好,即ScrollView会消耗掉在菜单视图上的滑动事件,ScrollView的抢占焦点能力较强,为了解决这个问题,我们必须得了解一下Android下的事件分发机制,Android下的事件分发机制并不是一句话两句话就可以讲清楚的,所以我暂时画了一个草图,简单的研究一下事件分发机制

如上图,右边显示的是某一个布局,该布局分为三层,外ViewGroup,内ViewGroup和View,那么想象一下,当用户手指按下屏幕的时候,Android对于这样一个事件是怎样处理的呢?首先请参考左边的示意图。

1,当事件被触发时,首先接收到事件的是外ViewGroup,事件传入时,外ViewGroup会调用自身的onDispatchTouchEvent方法用来处理事件分发,接着调用onInterceptTouchEvent方法,这个方法会判断事件是否由调用者(外ViewGroup)消耗掉?若返回true,需要消耗,则接下来调用onTouchEvent方法处理事件;若返回false,不需要消耗这个事件,则该事件会向下继续传递给内ViewGroup。

2,内ViewGroup得到此次事件,同样效仿外ViewGroup,会先调用onDispatchTouchEvent方法处理事件分发,接着调用onInterceptTouchEvent判断事件消耗,若返回true,需要消耗,接下来执行onTouchEvent方法处理这个事件;若返回false,不需要消耗这个事件,则该事件继续向下传递,传递给了View。

3,当View接收到了这个事件的时候,注意,因为View是最后一级组件,或许是某一具体的组件如TextView,在View里是没有onInterceptTouchEvent方法的。所以,当View接收到这个事件时,先会onDispatchTouchEvent分发这个事件,接下来就是onTouchEvent出来这个事件。返回值为boolean类型。若View消耗此事件,返回true,若不处理,就返回false或者调用父类返回值,不处理的这事件。

4,若View不消耗此事件,Android事件分发机制会采取事件回传,即此事件再次被传给内ViewGroup,依次类推,内ViewGroup会向上传给外ViewGroup,最后直接传给屏幕,事件消失。

不知道这样粗略的描述,是不是能理解呢?!Android下的事件分发机制比较复杂,想要认真学习这个知识点的话,我在这里提供两篇网上一些“大牛”写过的一些博客,写的很详尽,大家可以做一个深入的了解。

Android事件分发机制完全解析,带你从源码的角度彻底理解(上)

   Android事件分发机制完全解析,带你从源码的角度彻底理解(下)

   Android编程下Touch事件的分发和消费机制

以下是简单引用该SlidingMenu的方法,看MainActivity.java

package com.example.slidingmenu;

import com.example.slidingmenu.view.SlideMenu;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.app.Activity;

public class MainActivity extends Activity implements OnClickListener {

	private ImageButton backBtn;
	private SlideMenu slideMenu;
	private LinearLayout ll_content;
	private View view;
	private LayoutInflater inflater;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		slideMenu = (SlideMenu) findViewById(R.id.slidemenu);
		// 初始化首页
		ll_content = (LinearLayout) findViewById(R.id.ll_content);
		inflater = LayoutInflater.from(this);
		view = inflater.inflate(R.layout.frag_news, null);
		ll_content.removeAllViews();
		ll_content.addView(view);

		backBtn = (ImageButton) findViewById(R.id.ib_back);
		backBtn.setOnClickListener(this);

		findViewById(R.id.tab_news).setOnClickListener(this);
		findViewById(R.id.tab_read).setOnClickListener(this);
		findViewById(R.id.tab_local).setOnClickListener(this);
		findViewById(R.id.tab_ties).setOnClickListener(this);
		findViewById(R.id.tab_pics).setOnClickListener(this);
		findViewById(R.id.tab_focus).setOnClickListener(this);
		findViewById(R.id.tab_vote).setOnClickListener(this);
		findViewById(R.id.tab_ugc).setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.ib_back:
			if (slideMenu.isShowMenu()) {
				slideMenu.hideMenu();
			} else {
				slideMenu.showMenu();
			}
			break;
		case R.id.tab_news: // 新闻
			view = inflater.inflate(R.layout.frag_news, null);
			switchView();
			break;
		case R.id.tab_read: // 订阅
			view = inflater.inflate(R.layout.frag_read, null);
			switchView();
			break;
		case R.id.tab_local: // 本地
			view = inflater.inflate(R.layout.frag_local, null);
			switchView();
			break;
		case R.id.tab_ties: // 跟帖
			view = inflater.inflate(R.layout.frag_ties, null);
			switchView();
			break;
		case R.id.tab_pics: // 图片
			view = inflater.inflate(R.layout.frag_pics, null);
			switchView();
			break;
		case R.id.tab_focus: // 话题
			view = inflater.inflate(R.layout.frag_focus, null);
			switchView();
			break;
		case R.id.tab_vote: // 投票
			view = inflater.inflate(R.layout.frag_vote, null);
			switchView();
			break;
		case R.id.tab_ugc: // 聚合阅读
			view = inflater.inflate(R.layout.frag_ugc, null);
			switchView();
			break;
		}
	}

	private void switchView() {
		if (view != null) {
			ll_content.removeAllViews();
			ll_content.addView(view);
			if (slideMenu.isShowMenu()) {
				slideMenu.hideMenu();
			} else {
				slideMenu.showMenu();
			}
		}
	}
}

引用这个自定义SlidMenu组件的时候,需要注意的是怎么在内容主界面添加我们需要的界面展示。大家回头看看,我在slidemenu_main.xml这个内容布局的下方放置了一个LinearLayout线性布局,为什么呢?大家看看LinearLayout或者RelativeLayout的继承结构,诚然它们都继承自ViewGroup,大家都知道ViewGroup里面提供了很多用操作子元素的方法,于是,我们可以找到这样的一些方法,addView(View child)和removeAllViews()。我们可以非常轻松的将某个布局文件渲染成视图View后,通过这两个方法来替换主界面的视图,这样就达到了菜单和主界面交互的效果。

以上,由于篇幅有限,涉及到的知识比较多比较深的地方做了些简洁描述,时间仓促,难免有疏忽的地方,敬请指正。

源码请在这里下载

时间: 09-21

Android自定义控件——侧滑菜单的相关文章

Android UI-SlidingMenu侧滑菜单效果

Android UI-SlidingMenu侧滑菜单效果 本篇博客给大家分享一个效果比较好的侧滑菜单的Demo,实现点击左边菜单切换Fragment. 效果如下: 主Activity代码: package com.infzm.slidingmenu.demo; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.View; import android.view.View.On

android官方侧滑菜单DrawerLayout详解

drawerLayout是Support Library包中实现了侧滑菜单效果的控件,可以说drawerLayout是因为第三方控件如MenuDrawer等的出现之后,google借鉴而出现的产物.drawerLayout分为侧边菜单和主内容区两部分,侧边菜单可以根据手势展开与隐藏(drawerLayout自身特性),主内容区的内容可以随着菜单的点击而变化(这需要使用者自己实现). drawerLayout的使用很方便,使用drawerLayout的要点如下: 1.drawerLayout其实是

【转】android官方侧滑菜单DrawerLayout详解

原文网址:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/0925/1713.html drawerLayout是Support Library包中实现了侧滑菜单效果的控件,可以说drawerLayout是因为第三方控件如MenuDrawer等的出现之后,google借鉴而出现的产物.drawerLayout分为侧边菜单和主内容区两部分,侧边菜单可以根据手势展开与隐藏(drawerLayout自身特性),主内容区的内容可以随着

ViewDragHelper实践之仿Android官方侧滑菜单NavigationDrawer效果

相信经常使用移动应用的用户都很熟悉侧滑菜单栏, 下拉, 下弹, 上弹等应用场景, 几乎主流的移动应用无论IOS 还是Android都能看到. 2.3以前的时候, 很多第三方比如SlidingMenu, MenuDrawer, ActionbarSherlock等等都很大程度的丰富和深化了这种交互理念.能让小小的屏幕, 容纳更多的交互接口. 也是这种趋势, Android官方在v4终于推出了DrawerLayout. 表示对侧滑的重视与肯定. 唠叨到这了. 去看了DrawerLayout的源码和官

android 实现侧滑菜单

1.主布局 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:background="@drawable/img_frame_background&qu

Android组件——使用DrawerLayout仿网易新闻v4.4侧滑菜单

转载请注明出处:http://blog.csdn.net/allen315410/article/details/42914501 概述 今天这篇博客将记录一些关于DrawerLayout的基本用法,我想关于DrawerLayout的用法也许有不少不够了解,这也是比较正常的事情,因为DrawerLayout作为Android组件是Google后来在android中添加的,在android.support.v4包下.那么,DrawerLayout是一个怎么的组件呢?我们知道,当我们使用Androi

Android自定义控件——开源组件SlidingMenu的项目集成

转载请注明出处:http://blog.csdn.net/allen315410/article/details/39611355  在实际项目开发中,定制一个菜单,能让用户得到更好的用户体验,诚然菜单的样式各种各样,但是有一种菜单--滑动菜单,是被众多应用广泛使用的.关于这种滑动菜单的实现,我在前面的博文中也介绍了如何自定义去实现,请参考Android自定义控件--侧滑菜单,这篇博文描述的是如何从无到有创建一个侧滑菜单的控件,里面的代码不多,但是处理的逻辑和各种效果比较复杂,如果稍有不慎,这种

Android自定义控件 开源组件SlidingMenu的项目集成

在实际项目开发中,定制一个菜单,能让用户得到更好的用户体验,诚然菜单的样式各种各样,但是有一种菜单——滑动菜单,是被众多应用广泛使用的.关于这种滑动菜单的实现,我在前面的博文中也介绍了如何自定义去实现,请参考Android自定义控件——侧滑菜单,这篇博文描述的是如何从无到有创建一个侧滑菜单的控件,里面的代码不多,但是处理的逻辑和各种效果比较复杂,如果稍有不慎,这种自定义控件就要BUG不断,难以在项目中使用,而且实现的效果比较单一. 好在有开源力量的存在,在开源世界里,一切常用的实用的东西,都会有

Android 实现形态各异的双向侧滑菜单 自定义控件来袭

1.概述 关于自定义控件侧滑已经写了两篇了~~今天决定把之前的单向改成双向,当然了,单纯的改动之前的代码也没意思,今天不仅 会把之前的单向改为双向,还会多添加一种侧滑效果,给大家带来若干种形态各异的双向侧滑菜单,不过请放心,代码会很简单~~然后根据这若干种,只要你喜 欢,相信你可以打造任何绚(bian)丽(tai)效果的双向侧滑菜单~~ 首先回顾一下,之前写过的各种侧滑菜单,为了不占据篇幅,就不贴图片了: 1.最普通的侧滑效果,请参考:Android 自定义控件打造史上最简单的侧滑菜单 2.仿Q