早上看到一篇文章介绍了ResideMenu得使用,这是一个类似SlidingMenu的控件,感觉有点高尚大,反正我之前没见过,本着凑热闹的好奇心,立马clone把玩下,项目地址奉上:
https://github.com/SpecialCyCi/AndroidResideMenu.git
原理概述
在分析源代码之前,简单谈谈,这个效果在这里是如何实现的。
点击按钮画面缩小为50%同时向右侧滑动至中间位置,也可以向右滑动,然后那几个个菜单项就会带着动画出现,动画这里用的是nineoldandroids的兼容包,在整个过程中有三个东西要理解,一是菜单view,二是内容view,还有就是承载他们的父view,在点击后调用AnimatorSet组合动画把内容view向右改变,然后在把菜单view加进来。
实现分析
看过代码后其实这个的实现方式与其他的开源控件确实不太通,之前很少看到有用承载activity的节点view来做的。
怎么使用我就不说了,直接看作者的介绍;https://github.com/SpecialCyCi/AndroidResideMenu/blob/master/README_CN.md
// attach to current activity; resideMenu = new ResideMenu(this); resideMenu.setBackground(R.drawable.menu_background); resideMenu.attachToActivity(this);
// create menu items;
String titles[] = { "Home", "Profile", "Calendar", "Settings" };
int icon[] = { R.drawable.icon_home, R.drawable.icon_profile, R.drawable.icon_calendar, R.drawable.icon_settings };
for (int i = 0; i < titles.length; i++){
ResideMenuItem item = new ResideMenuItem(this, icon[i], titles[i]);
item.setOnClickListener(this);
resideMenu.addMenuItem(item);
}
下面我们来看这个ResideMenu是怎么写的
scaleDown_activity是一个AnimationSet的实例,直接开始动画,view_decor当然就是承载activity的父view,最后把菜单加进来,你会发现这里加了两次,感觉非常奇怪,因为这个sv_menu本身是处在this里面的,
按道理来说一个view是不能同时处在来个节点当中,当时我就斯巴达了,原来这里作者其实写一个比较古怪的方法,先把sv_menu从this当中移除,在加到外面的view_dector中,也就是 if (sv_menu.getParent() != null) removeMenuLayout();这句话的用意,在菜单第一次加载时,我先出于this中,此时和sv_menu.getParent()是同一个指向,这样的写法在我看来味的作用就是可以减少view结构的层数,别无它用,所以完全可以这样来写:
话说回来作者的写法也许有其他考量,我暂时没注意到,修改后的代码可以正常运行。至于前一个 if (getParent() != null) view_decor.removeView(this);比较好理解就是把菜单view先移除,不过也没什么意义,这样每次都重新移除加入是出于什么考虑有待商榷,所以把这两个地方都改一下,就是:
只在第一次的时候才把菜单加入到view_dector里面再看看关闭菜单是怎么写的:
这几个AnimationSet的创建写的还是比较合理,放大还原这个里面只写了缩放的操作,缩小的里面还有缩放坐标点的设置,默认的话是view的中心,这不是我们希望的。
为了跟好的理解这个缩放的坐标点我花了一张示意图,箭头指向的点为屏幕宽度X1.5,高度为屏幕高度X0.5,view的高宽都缩放为50%,得到的就是红色的位置。
其他的参考源代码,这里只做核心的代码分析。
出处:http://www.cnblogs.com/avenwu/
Android开源界面库--ResideMenu用法
网上关于ResideMenu用法的教程很多,但基本上全是从Github上copy下来的,Gitbub上给出的了对应的demo,但是由于我的IDE原因吧,demo一直导入不成功。为此自己又捣鼓了一翻,终于运行成功ResideMenu的真容。







package com.example.residemenutest;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;
import com.special.ResideMenu.ResideMenu;
import com.special.ResideMenu.ResideMenuItem;
public class MenuActivity extends FragmentActivity implements View.OnClickListener{
private ResideMenu resideMenu;
private MenuActivity mContext;
private ResideMenuItem itemHome;
private ResideMenuItem itemProfile;
private ResideMenuItem itemCalendar;
private ResideMenuItem itemSettings;
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mContext = this;
setUpMenu();
changeFragment(new HomeFragment());
}
private void setUpMenu() {
// attach to current activity;
resideMenu = new ResideMenu(this);
resideMenu.setBackground(R.drawable.menu_background);
resideMenu.attachToActivity(this);
resideMenu.setMenuListener(menuListener);
// create menu items;
itemHome = new ResideMenuItem(this, R.drawable.icon_home, "Home");
itemProfile = new ResideMenuItem(this, R.drawable.icon_profile, "Profile");
itemCalendar = new ResideMenuItem(this, R.drawable.icon_calendar, "Calendar");
itemSettings = new ResideMenuItem(this, R.drawable.icon_settings, "Settings");
itemHome.setOnClickListener(this);
itemProfile.setOnClickListener(this);
itemCalendar.setOnClickListener(this);
itemSettings.setOnClickListener(this);
resideMenu.addMenuItem(itemHome);
resideMenu.addMenuItem(itemProfile);
resideMenu.addMenuItem(itemCalendar);
resideMenu.addMenuItem(itemSettings);
findViewById(R.id.title_bar_menu).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
resideMenu.openMenu();
}
});
}
@Override
public void onClick(View view) {
if (view == itemHome){
changeFragment(new HomeFragment());
}else if (view == itemProfile){
changeFragment(new ProfileFragment());
}else if (view == itemCalendar){
changeFragment(new CalendarFragment());
}else if (view == itemSettings){
changeFragment(new SettingsFragment());
}
resideMenu.closeMenu();
}
private ResideMenu.OnMenuListener menuListener = new ResideMenu.OnMenuListener() {
@Override
public void openMenu() {
Toast.makeText(mContext, "Menu is opened!", Toast.LENGTH_SHORT).show();
}
@Override
public void closeMenu() {
Toast.makeText(mContext, "Menu is closed!", Toast.LENGTH_SHORT).show();
}
};
private void changeFragment(Fragment targetFragment){
resideMenu.clearIgnoredViewList();
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.main_fragment, targetFragment, "fragment")
.setTransitionStyle(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.commit();
}
// What good method is to access resideMenu?
public ResideMenu getResideMenu(){
return resideMenu;
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@android:color/white"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/layout_top">
<ImageView
android:layout_width="match_parent"
android:layout_height="3dp"
android:background="#2ea3fe"/>
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button
android:layout_width="28dp"
android:layout_height="28dp"
android:background="@drawable/titlebar_menu_selector"
android:id="@+id/title_bar_menu"
android:layout_gravity="left|center_vertical"
android:layout_marginLeft="10dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="7dp"
android:text="RESideMenu DEMO"
android:textSize="24sp"
android:textColor="#999999"
android:layout_gravity="center"/>
</FrameLayout>
<ImageView
android:layout_width="match_parent"
android:layout_height="5dp"
android:background="#ebebeb"/>
</LinearLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="@+id/main_fragment">
</FrameLayout>
</LinearLayout>
接下来是四个Fragment,它们只是一些简单的展示所以很简单,如比较漂亮的HomeFragment,代码如下:
package com.example.residemenutest;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.special.ResideMenu.ResideMenu;
/**
* User: special
* Date: 14-13-20
* Time: 下午1:33
* Mail: cym@saymagic.cn
*/
public class HomeFragment extends Fragment {
private View parentView;
private ResideMenu resideMenu;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
parentView = inflater.inflate(R.layout.home, container, false);
setUpViews();
return parentView;
}
private void setUpViews() {
MenuActivity parentActivity = (MenuActivity) getActivity();
resideMenu = parentActivity.getResideMenu();
parentView.findViewById(R.id.btn_open_menu).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
resideMenu.openMenu();
}
});
// add gesture operation's ignored views
FrameLayout ignored_view = (FrameLayout) parentView.findViewById(R.id.ignored_view);
resideMenu.addIgnoredView(ignored_view);
}
}
剩下的代码不一一展示了,都很简单,ResideMenu其实封装的已经很好了,你可以用调用residemenu的openMenu()打开这个菜单,closeMenu()关闭这个菜单等等。最后,把本文所需的ResideMenu文件和自己写的demo 源码分享出来。
转载请注明---曹艳明个人博客:www.saymagic.cn.