您的位置:首页 > 其它

侧滑菜单 ——仿QQ实现动画效果

2015-08-18 18:32 507 查看
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:android="http://schemas.android.com/apk/res/android"
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);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: