Android 自定义View修炼-仿QQ5.0 的侧滑菜单效果的实现
有一段时间没有写博客了,最近比较忙,没什么时间写,刚好今天有点时间,
我就分享下,侧滑菜单的实现原理,一般android侧滑的实现原理和步骤如下:(源码下载在下面最后给出哈)
1.使用ViewGroup 放2个view,一个是menu菜单,一个是content内容
2.监听onTouchEvent事件
处理ACTION_MOVE中的leftMargin位置,从而改变menu菜单的滑动位置
当ACTION_UP时,根据显示菜单的宽度,决定将其显示或隐藏动画效果:
(1)使用Scroller这个辅助类实现动画效果
(2)单起一个Thread(或Task)来改变leftMargin的大小来实现动画效果
上面这种方法,当监听ACTION_MOVE时候,当菜单里有listview等view到时候容易引起手势监听的冲突。
为了避免这种问题,我们采用新的方法来做侧滑。主要是做以下两个处理:
1.不继承ViewGroup,而是继承HorizontalScrollView,这样做的好处是HorizontalScrollView已经帮我们做了相关的监听滑动手势冲突的处理,我们不用操心和处理这些问题。
2.计算Menu菜单的大小,并显示与隐藏menu
3.显示和隐藏menu的动画效果,使用nineoldandroids这个android属性动画开源库。
侧滑菜单的效果截图如下:


上面介绍了原理和效果图,下面来看看侧滑菜单类的实现:
1.布局文件的实现:
(1)左侧菜单布局实现:
<?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"
android:background="#00000000" > <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_centerInParent="true"
> <RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" > <TextView
android:id="@+id/menu1"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:gravity="center_vertical"
android:layout_centerVertical="true"
android:textColor="#ffffff"
android:textSize="25sp"
android:text="第一个item1" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" > <TextView
android:id="@+id/menu2"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:gravity="center_vertical"
android:layout_centerVertical="true"
android:textColor="#ffffff"
android:textSize="25sp"
android:text="第二个item2" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" > <TextView
android:id="@+id/menu3"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:gravity="center_vertical"
android:layout_centerVertical="true"
android:textColor="#ffffff"
android:textSize="25sp"
android:text="第三个item3" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" > <TextView
android:id="@+id/menu4"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:gravity="center_vertical"
android:layout_centerVertical="true"
android:textColor="#ffffff"
android:textSize="25sp"
android:text="第四个item4" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" > <TextView
android:id="@+id/menu5"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:gravity="center_vertical"
android:layout_centerVertical="true"
android:textColor="#ffffff"
android:textSize="25sp"
android:text="第五个item5" />
</RelativeLayout>
</LinearLayout> </RelativeLayout>
(2)总布局实现:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
> <com.czm.xcslidemenu.view.XCSlideMenu
android:id="@+id/slideMenu"
android:layout_width="match_parent"
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_menu" /> <LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/qihu" > <TextView
android:id="@+id/btnSwitch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/btn_bg"
android:padding="5dp"
android:textSize="16sp"
android:textColor="#FFF"
android:layout_margin="10dp"
android:text="切换菜单" />
</LinearLayout>
</LinearLayout>
</com.czm.xcslidemenu.view.XCSlideMenu> </RelativeLayout>
2.侧滑菜单类的实现:
package com.czm.xcslidemenu.view; import com.nineoldandroids.view.ViewHelper; import android.animation.FloatEvaluator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
/**
* 自定义侧滑菜单View
* @author caizhiming
*
*/
public class XCSlideMenu extends HorizontalScrollView{ private LinearLayout mWapper;
private ViewGroup mMenu;
private ViewGroup mContent;
private int mScreenWidth;
private int mMenuRightPadding;
private int mMenuWidth = 0; private boolean once = false;
//Menu是否处于显示状态
private boolean isSlideOut; public static final int RIGHT_PADDING = 100; public XCSlideMenu(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(metrics);
mScreenWidth = metrics.widthPixels;
//将dp转化为px
mMenuRightPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, XCSlideMenu.RIGHT_PADDING, context.getResources().getDisplayMetrics());
} /**
* 设置子View的宽和高
* 设置自己的宽和高
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
if(!once){
mWapper = (LinearLayout) getChildAt(0);
mMenu = (ViewGroup) mWapper.getChildAt(0);
mContent = (ViewGroup) mWapper.getChildAt(1); mMenuWidth = mMenu.getLayoutParams().width = mScreenWidth - mMenuRightPadding;
mContent.getLayoutParams().width = mScreenWidth;
once = true;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
/**
* 通过设置偏移量将Menu隐藏
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
super.onLayout(changed, l, t, r, b);
if(changed){
this.scrollTo(mMenuWidth, 0);
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
// TODO Auto-generated method stub
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_UP:
//隐藏在左边宽度
int scrollX = getScrollX();
if(scrollX >= mMenuWidth /2){
//Menu 左滑隐藏起来
this.smoothScrollTo(mMenuWidth, 0);
isSlideOut = false;
}else{
//Menu 右滑 显示出来
this.smoothScrollTo(0, 0);
isSlideOut = true;
}
return true;
}
return super.onTouchEvent(ev);
}
/**
* 向右滑出菜单显示出来
*/
public void slideOutMenu(){
if(!isSlideOut){
this.smoothScrollTo(0, 0);
isSlideOut = true;
}else{
return;
}
}
/**
* 向左滑出菜单隐藏起来
*/
public void slideInMenu(){
if(isSlideOut){
this.smoothScrollTo(mMenuWidth, 0);
isSlideOut = false;
}else{
return;
}
}
/**
* 切换菜单向右滑出显示或向左滑出隐藏的状态
*/
public void switchMenu(){
if(isSlideOut){
slideInMenu();
}else{
slideOutMenu();
}
}
/**
* 滚动发生时
*/
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
// TODO Auto-generated method stub
super.onScrollChanged(l, t, oldl, oldt);
//实现抽屉式滑动
float scale = l * 1.0f /mMenuWidth ;//1 ~ 0
float menuScale = 1.0f - scale * 0.3f;
float menuAlpha = 0.0f + 1.0f * (1 - scale);
float contentScale = 0.8f + 0.2f * scale;
//调用属性动画,设置TranslationX
ViewHelper.setTranslationX(mMenu, mMenuWidth*scale*0.8f); //左侧菜单的缩放
ViewHelper.setScaleX(mMenu, menuScale);
ViewHelper.setScaleY(mMenu, menuScale);
//左侧菜单的透明度缩放
ViewHelper.setAlpha(mMenu, menuAlpha); //右侧内容的缩放
ViewHelper.setPivotX(mContent, 0);
ViewHelper.setPivotY(mContent, mContent.getHeight() / 2);
ViewHelper.setScaleY(mContent, contentScale);
ViewHelper.setScaleX(mContent, contentScale);
} }
最后,如何使用该侧滑菜单类呢?很简单,请看下面实例代码:
package com.czm.xcslidemenu; import com.czm.xcslidemenu.view.XCSlideMenu; import android.app.Activity;
import android.app.ActionBar;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
import android.os.Build; public class MainActivity extends Activity { private XCSlideMenu xcSlideMenu;
private TextView btnSwitch;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
xcSlideMenu = (XCSlideMenu) findViewById(R.id.slideMenu);
btnSwitch = (TextView)findViewById(R.id.btnSwitch);
btnSwitch.setClickable(true);
btnSwitch.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
// TODO Auto-generated method stub
xcSlideMenu.switchMenu();
}
}); } }
最后给出源码的下载:http://download.csdn.net/detail/jczmdeveloper/8286307
真题园网:http://www.zhentiyuan.com
Android 自定义View修炼-仿QQ5.0 的侧滑菜单效果的实现的更多相关文章
- Android 自定义View修炼-仿360手机卫士波浪球进度的实现
像360卫士的波浪球进度的效果,一般最常用的方法就是 画线的方式,先绘sin线或贝塞尔曲线,然后从左到右绘制竖线,然后再裁剪圆区域. 今天我这用图片bitmap的方式,大概的方法原理是: (1)首先用 ...
- Android 自定义View修炼-打造完美的自定义侧滑菜单/侧滑View控件
一.概述 在App中,经常会出现侧滑菜单,侧滑滑出View等效果,虽然说Android有很多第三方开源库,但是实际上 咱们可以自己也写一个自定义的侧滑View控件,其实不难,主要涉及到以下几个要点: ...
- android自定义View之仿通讯录侧边栏滑动,实现A-Z字母检索
我们的手机通讯录一般都有这样的效果,如下图: OK,这种效果大家都见得多了,基本上所有的android手机通讯录都有这样的效果.那我们今天就来看看这个效果该怎么实现. 一.概述 1.页面功能分析 整体 ...
- Android DrawerLayout 高仿QQ5.2双向侧滑菜单
1.概述 之前写了一个Android 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭 ,恰逢QQ5.2又加了一个右侧菜单,刚好看了下DrawerLayout,一方面官方的东西,我都比较感兴趣:另一方面 ...
- Android 自定义View,仿微信视频播放按钮
闲着,尝试实现了新版微信视频播放按钮,使用的是自定义View,先来个简单的效果图...真的很简单哈. 由于暂时用不到,加上时间原因,加上实在是没意思,加上……,本控件就没有实现自定义属性,有兴趣的朋友 ...
- Android 自定义View修炼-Android 实现自定义的卫星式菜单(弧形菜单)View
一.总述 Android 实现卫星式菜单也叫弧形菜单的主要要做的工作如下:1.动画的处理2.自定义ViewGroup来实现卫星式菜单View (1)自定义属性 a. 在attrs.xml中 ...
- Android 自定义View修炼-【2014年最后的分享啦】Android实现自定义刮刮卡效果View
一.简介: 今天是2014年最后一天啦,首先在这里,我祝福大家在新的2015年都一个个的新健康,新收入,新顺利,新如意!!! 上一偏,我介绍了用Xfermode实现自定义圆角和椭圆图片view的博文& ...
- Android 自定义View修炼-自定义View-带百分比进度的圆形进度条(采用自定义属性)
很多的时候,系统自带的View满足不了我们功能的需求,那么我们就需要自己来自定义一个能满足我们需求的View,自定义View我们需要先继承View,添加类的构造方法,重写父类View的一些方法,例如o ...
- Android 自定义View修炼-自定义可动画展开收缩View的实现
有时候需要点击一个view可以动画展开和收缩折叠一个View这样的效果,这样就可以直接自定义View来实现. 本例中,采用继承FrameLayout来实现自定义的ExpandView.下面将详细介绍各 ...
随机推荐
- [HDU 4433]locker[DP]
题意: 给出密码做的现状和密码, 每次可以移动连续的最多3列, 向上或向下, 求将密码调出来所需要的最少步数. 思路: 首先应看出,恢复的过程中, 调每一位的时间顺序是不影响的, 不妨就从左到右一位位 ...
- Bamboo简介
前言 前面介绍了JIRA管理平台,那么本篇就来介绍关于自动编译项目的工具-Bamboo. 正题 1.简介 Atlassian Bamboo 是一款持续集成构建服务器软件(Build Serve ...
- Shell编程学习---第五篇:Shell的输入和输出
在shell脚本中,可以用几种不同的方式读入数据:可以使用标准输入—缺省为键盘,或 者指定一个文件作为输入.对于输出也是一样:如果不指定某个文件作为输出,标准输出总 是和终端屏幕相关联.如果所使用命令 ...
- [Hadoop源码解读](二)MapReduce篇之Mapper类
前面在讲InputFormat的时候,讲到了Mapper类是如何利用RecordReader来读取InputSplit中的K-V对的. 这一篇里,开始对Mapper.class的子类进行解读. 先回忆 ...
- 设置oracle11g空表exp导出
1.Oracle11g默认对空表不分配segment,故使用exp导出Oracle11g数据库时,空表不会导出. 2.设置deferred_segment_creation 参数为FALSE后,无论是 ...
- linux 系统获取网络ip, mask, gateway, dns信息小程序
net_util.c #define WIRED_DEV "eth0" #define WIRELESS_DEV ...
- Dim Loop 出现结果不同
(1)结果是:循环1次 Dim counter,num counter = 0 'num = 9 Do Until num = 10 num = num - 1 counter = c ...
- [摘]selenium-ide命令
关于,selenium 命令这一部分,为了便于像我一样的菜鸟理解,我采用通过例子讲命令的方式. 菜鸟Selenium 命令通常被称为selenese,有一系列运行测试案例所需的命令构成. ----// ...
- SQL Server查询性能优化——覆盖索引(二)
在SQL Server 查询性能优化——覆盖索引(一)中讲了覆盖索引的一些理论. 本文将具体讲一下使用不同索引对查询性能的影响. 下面通过实例,来查看不同的索引结构,如聚集索引.非聚集索引.组合索引等 ...
- makefile 中 $@ $^ %< 使用
这篇文章介绍在LINUX下进行C语言编程所需要的基础知识.在这篇文章当中,我们将会学到以下内容: 源程序编译 Makefile的编写 程序库的链接 程序的调试 头文件和系统求助 1.源程序的编译 在L ...