Android 自定义View修炼-仿QQ5.0 的侧滑菜单效果的实现

时间:2023-02-09 11:33:40

有一段时间没有写博客了,最近比较忙,没什么时间写,刚好今天有点时间,

我就分享下,侧滑菜单的实现原理,一般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属性动画开源库。

侧滑菜单的效果截图如下:

Android 自定义View修炼-仿QQ5.0 的侧滑菜单效果的实现

Android 自定义View修炼-仿QQ5.0 的侧滑菜单效果的实现   Android 自定义View修炼-仿QQ5.0 的侧滑菜单效果的实现   Android 自定义View修炼-仿QQ5.0 的侧滑菜单效果的实现

上面介绍了原理和效果图,下面来看看侧滑菜单类的实现:

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 的侧滑菜单效果的实现的更多相关文章

  1. Android 自定义View修炼-仿360手机卫士波浪球进度的实现

    像360卫士的波浪球进度的效果,一般最常用的方法就是 画线的方式,先绘sin线或贝塞尔曲线,然后从左到右绘制竖线,然后再裁剪圆区域. 今天我这用图片bitmap的方式,大概的方法原理是: (1)首先用 ...

  2. Android 自定义View修炼-打造完美的自定义侧滑菜单&sol;侧滑View控件

    一.概述 在App中,经常会出现侧滑菜单,侧滑滑出View等效果,虽然说Android有很多第三方开源库,但是实际上 咱们可以自己也写一个自定义的侧滑View控件,其实不难,主要涉及到以下几个要点: ...

  3. android自定义View之仿通讯录侧边栏滑动,实现A-Z字母检索

    我们的手机通讯录一般都有这样的效果,如下图: OK,这种效果大家都见得多了,基本上所有的android手机通讯录都有这样的效果.那我们今天就来看看这个效果该怎么实现. 一.概述 1.页面功能分析 整体 ...

  4. Android DrawerLayout 高仿QQ5&period;2双向侧滑菜单

    1.概述 之前写了一个Android 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭 ,恰逢QQ5.2又加了一个右侧菜单,刚好看了下DrawerLayout,一方面官方的东西,我都比较感兴趣:另一方面 ...

  5. Android 自定义View,仿微信视频播放按钮

    闲着,尝试实现了新版微信视频播放按钮,使用的是自定义View,先来个简单的效果图...真的很简单哈. 由于暂时用不到,加上时间原因,加上实在是没意思,加上……,本控件就没有实现自定义属性,有兴趣的朋友 ...

  6. Android 自定义View修炼-Android 实现自定义的卫星式菜单(弧形菜单)View

    一.总述 Android 实现卫星式菜单也叫弧形菜单的主要要做的工作如下:1.动画的处理2.自定义ViewGroup来实现卫星式菜单View (1)自定义属性       a. 在attrs.xml中 ...

  7. Android 自定义View修炼-【2014年最后的分享啦】Android实现自定义刮刮卡效果View

    一.简介: 今天是2014年最后一天啦,首先在这里,我祝福大家在新的2015年都一个个的新健康,新收入,新顺利,新如意!!! 上一偏,我介绍了用Xfermode实现自定义圆角和椭圆图片view的博文& ...

  8. Android 自定义View修炼-自定义View-带百分比进度的圆形进度条(采用自定义属性)

    很多的时候,系统自带的View满足不了我们功能的需求,那么我们就需要自己来自定义一个能满足我们需求的View,自定义View我们需要先继承View,添加类的构造方法,重写父类View的一些方法,例如o ...

  9. Android 自定义View修炼-自定义可动画展开收缩View的实现

    有时候需要点击一个view可以动画展开和收缩折叠一个View这样的效果,这样就可以直接自定义View来实现. 本例中,采用继承FrameLayout来实现自定义的ExpandView.下面将详细介绍各 ...

随机推荐

  1. iOS 事件穿透

    - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typica ...

  2. 【PAT】1029&period; Median &lpar;25&rpar;

    Given an increasing sequence S of N integers, the median is the number at the middle position. For e ...

  3. 谷歌(Chrome)安装Advanced REST Client插件

    进入Extensions(工具——>扩展程序) 点击Get More extensions或新建标签页点击网上应用店 如果加载太慢,出现chrome网上应用店无法打开,显示暂时无法加载该应用的画 ...

  4. Latex:入门教程

    http://blog.csdn.net/pipisorry/article/details/54571521 总的来说,LaTex是一套排版系统,与word那种所见即所得对排版方式不太,用LaTex ...

  5. jmeter源码导入eclipse步骤

    1.新建标准java项目2.右击项目选import filesystem 将apache-jmeter-4.0整个目录勾选allow output folders for source folders ...

  6. 解决ODI 12C Studio 运行缓慢问题

    一.配置 ODI 12C Studio 1.1 修改ODI Studio process的-Xms和-Xmx ide.conf: modifying the initial Heap size (-X ...

  7. 简易HashMap实现

    为了更好的理解HashMap线程不安全的根源,这里提供了HashMap的简易实现: package map.test; import org.apache.commons.lang3.StringUt ...

  8. C&plus;&plus; Primer学习笔记(二)

    题外话:一工作起来就没有大段的时间学习了,如何充分利用碎片时间是个好问题. 接  C++ Primer学习笔记(一)   27.与 vector 类型相比,数组的显著缺陷在于:数组的长度是固定的,无法 ...

  9. MVC Ajax Helpers

    在MVC中要实现Ajax有很多的方式,有微软自己的MicrosoftAjax,也可以用JQuery的AJax来实现,如果对其他的JavaScript框架熟悉,还可以采用其他的实现方案,比如说Proto ...

  10. Java反射机制的浅显理解(这篇文章还没写好,留个草稿给自己看的)

    目前只是有一个大概的理解,先把自己感觉容易立即的概念放这里,等以后结合实际工作理解深刻了再来补充. 一.什么是Java反射机制?(多种定义) 1. JAVA反射机制是在运行状态中,对于任意一个类,都能 ...