侧滑菜单 ——仿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 为内容布局 也可以自行定义
自定义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的入口。
上面的自定义属性需要声明
自定义属性(styleable)的名字为sidemenu 属性名为 MenuPadding
在自定义view中使用 需要自定义命名空间
xmlns:lyl="http://schemas.android.com/apk/res/com.example.horizontalscrollview_qq"
在res/下为项目的包名 可以在manifest.xml中复制
在自定义视图中使用:lyl:MenuPadding="50dp"
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里面实现了菜单的开关按钮
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); } }
相关文章推荐
- 死锁实例
- Spring rmi
- Struts2 全局结果类型<global-results>
- jvm内存模型
- java 中break、continue、return之间的区别与联系
- 解决firefox经常出现Adobe Flash 插件已崩溃
- C++逐行读取文本文件的正确做法
- sysfs创建目录:
- TCP堵塞控制
- adb shell 控制启动Activity、Service等
- 单链表 之c代码
- C++逐行读取文本文件的正确做法
- PySpark关于HDFS文件(目录)输入、数据格式的探讨
- Python学习 windows下面安装Python和pip(一)
- 在输入的字符串中判断是否有a,多种方法(比较前两种不同的表示方法)
- android studio的使用
- cocos-2dx 渲染(2)
- nginx对ip的访问频率进行限制(limit_req)和对ip连接数(并发量)进行限制(limit_conn)
- 我的openwrt学习笔记(六):MTK的OpenWrt系统编译以及下载
- hdu5400Arithmetic Sequence