侧滑菜单 ——仿QQ实现动画效果
1、首先实现侧滑菜单,这里用HorizontalScrollView来进行实现
2、SideMenu为自定义view 继承horizontalScrollView
3、这个自定义命名空间 :xmlns:lyl="http://schemas.android.com/apk/res/com.example.horizontalscrollview_qq"
中的res/下面为项目的包名 可以复制manifest.xml中的包名
4、<include />中包含的是侧滑菜单的布局 可以自行定义
5、内部的linearlayout 为内容布局 也可以自行定义
<RelativeLayout xmlns:andro> xmlns:lyl="http://schemas.android.com/apk/res/com.example.horizontalscrollview_qq" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.horizontalscrollview_qq.MainActivity" > <com.example.sidemenu.SideMenu android:id="@+id/menu" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/img_frame_background" lyl:MenuPadding="50dp" > <LinearLayout android:layout_width="wrap_content" android:layout_height="match_parent" android:orientation="horizontal" > <include layout="@layout/side_menu" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="match_parent" android:background="@drawable/qq" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@android:color/transparent" android:onClick="toggleMenu" android:text="@string/back" android:textColor="@android:color/white" android:textSize="30sp" /> </LinearLayout> </LinearLayout> </com.example.sidemenu.SideMenu> </RelativeLayout>
自定义View
1、构造方法
一个参数 context
两个参数 context attr
三个参数 context attr defStyle
三个参数的构造方法中含有 自定义属性的值 所以 在一个参数的构造方法中使用this(context ,null)调用两个参数的,以此类推
2、复写 onMeasure()方法
定义子视图 设置子视图的大小
3、复写 onLayout()方法
设置子视图的位置
4、动画效果
这里为更好的兼容3.0以下的版本 导入nineoldAndroid.jar包
nineoldAndroid的API和Honeycomb API完全一样,只是改变了使用com.nineoldandroids.XXX的入口。
package com.example.sidemenu;
import com.example.horizontalscrollview_qq.R;
import com.nineoldandroids.view.ViewHelper;
import android.content.Context;
import android.content.res.TypedArray;
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.view.animation.AnimationSet;
import android.view.animation.TranslateAnimation;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
public class SideMenu extends HorizontalScrollView {
private LinearLayout mWapper;
private ViewGroup mMenu;
private ViewGroup mContent;
private int mScreenWidth;
private int mMenuRightpadding = 50;
private boolean once;
private int mMenuWidth;
private int mContentWidth;
private boolean isOpen;
public SideMenu(Context context) {
// super(context);
// 调用两个参数的构造方法
this(context, null);
}
public SideMenu(Context context, AttributeSet attrs) {
// super(context, attrs);
// 调用含有自定义属性参数的构造方法
this(context, attrs, 0);
}
public SideMenu(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 读取所有自定义参数
TypedArray array = context.getTheme().obtainStyledAttributes(attrs,
R.styleable.sidemenu, defStyleAttr, 0);
// 获得属性数组的数量
int n = array.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = array.getIndex(i);
switch (attr) {
case R.styleable.sidemenu_MenuPadding:
// 1 、设置自定义属性值
// 2、设置默认值
mMenuRightpadding = array.getDimensionPixelSize(attr,
(int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 50, context
.getResources().getDisplayMetrics()));
break;
default:
break;
}
}
// 回收
array.recycle();
WindowManager manager = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(outMetrics);
mScreenWidth = outMetrics.widthPixels;
}
// 自定义视图时,需要复写这几个方法 onMeasure onLayout
// onMeasure 计算子View的宽和高,以及设置自己的宽和高
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (!once) {
// 先初始化linearLayout
mWapper = (LinearLayout) getChildAt(0);
// linearLayout内装入子视图
mMenu = (ViewGroup) mWapper.getChildAt(0);
// 在装入第二个子视图
mContent = (ViewGroup) mWapper.getChildAt(1);
// 设置 第一个 视图的 宽度
mMenuWidth = mMenu.getLayoutParams().width = mScreenWidth
- mMenuRightpadding;
// 设置第二个视图的宽度
mContentWidth = mContent.getLayoutParams().width = mScreenWidth;
// 只计算一次
once = true;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
// onLayout 决定子View的布局的位置
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (changed) {
// 默认显示的位置
this.scrollTo(mMenuWidth, 0);
isOpen = false;
}
}
// 触摸事件处理
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_UP:
int scrollX = getScrollX();
if (scrollX >= mMenuWidth / 2) {
this.smoothScrollTo(mMenuWidth, 0);
isOpen = false;
} else {
this.smoothScrollTo(0, 0);
isOpen = true;
}
return true;
}
return super.onTouchEvent(ev);
}
// 打开菜单
public void open() {
this.smoothScrollTo(0, 0);
isOpen = true;
}
// 关闭菜单
public void close() {
this.smoothScrollTo(mMenuWidth, 0);
isOpen = false;
}
// 按钮开关
public void toggle() {
if (isOpen) {
close();
} else {
open();
}
}
// 实现侧滑的抽屉效果
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
// l: horizontalScroll起始的水平位置
// t: 起始的垂直位置
// 调用动画属性 设置translation
// mMenu.setTranslationX(l);
// 这里为更好的兼容3.0以下的版本 导入nineoldAndroid.jar包
// 该API和Honeycomb API完全一样,只是改变了使用com.nineoldandroids.XXX的入口。
ViewHelper.setTranslationX(mMenu, l*0.7f);
float scale = l * 1.0f / mMenuWidth;
// 实现内容区域的缩放
// 设置缩放的中心点
ViewHelper.setPivotX(mContent, 0);
ViewHelper.setPivotY(mContent, mContent.getHeight() / 2);
// 从1.0缩放到0.7
ViewHelper.setScaleX(mContent, 0.7f + 0.3f * scale);
ViewHelper.setScaleY(mContent, 0.7f + 0.3f * scale);
// mMenu 的缩放从0.7到1.0
ViewHelper.setScaleX(mMenu, 1.0f - 0.3f * scale);
ViewHelper.setScaleY(mMenu, 1.0f - 0.3f * scale);
// 设置mMenu 的透明度 0.6到1.0
ViewHelper.setAlpha(mMenu, 1.0f - 0.6f * scale);
}
}
上面的自定义属性需要声明
自定义属性(styleable)的名字为sidemenu 属性名为 MenuPadding
在自定义view中使用 需要自定义命名空间
xmlns:lyl="http://schemas.android.com/apk/res/com.example.horizontalscrollview_qq"
在res/下为项目的包名 可以在manifest.xml中复制
在自定义视图中使用:lyl:MenuPadding="50dp"
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="MenuPadding" format="dimension"></attr>
<declare-styleable name="sidemenu">
<attr name="MenuPadding" ></attr>
</declare-styleable>
</resources>
1、自定义view中 可以通过 TypedArray来获得自定义的所有属性
TypedArray array = context.getTheme().obtainStyledAttributes(attrs,
R.styleable.sidemenu, defStyleAttr, 0);
2、 获得自定义属性可以通过 getDimensionPixelSize(index, defValue)来获得 并设置默认值
当需要将参数值的单位进行转化时可以用
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context
.getResources().getDisplayMetrics());
单位为dip 即返回的的结果为:50dp乘以显示密度density(dpi/160)。即为像素px
mian里面实现了菜单的开关按钮
package com.example.horizontalscrollview_qq;
import com.example.horizontalscrollview_qq.R.id;
import com.example.sidemenu.SideMenu;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
public class MainActivity extends Activity {
private SideMenu menu;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main_activity);
menu=(SideMenu) findViewById(id.menu);
}
public void toggleMenu(View view){
menu.toggle();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}