前几天在github上看到一个DrawableLayout的项目,地址:https://github.com/Yalantis/Side-Menu.Android,感觉效果很不错,以后可以用到自己的项目中,于是对项目进行了仿写,并没有使用DrawableLayout,而是自己定义了一个LinearLayout,向其中添加按钮,点击按钮后进行页面的切换,具体效果如下所示:
看结果还是挺不错的,以下是源码分析,在编写过程中,借鉴了github上面的代码。
1、动画效果
在侧边栏弹出的时候,我们看到了一个翻转的动画效果,以y轴为翻转轴,菜单依次翻转弹出,我们需要定义一个FlipAnimation,继承Animation,实现翻转效果,代码如下:
/**
* 3d变化动画,实现了View绕Y轴旋转的效果,来源于开源控件Yalantis/Side-Menu.Android
* 地址 https://github.com/Yalantis/Side-Menu.Android
* Created by Konstantin on 22.12.2014.
*/
public class FlipAnimation extends Animation {
private final float mFromDegrees;
private final float mToDegrees;
private final float mCenterX;
private final float mCenterY;
private Camera mCamera;
public FlipAnimation(float fromDegrees, float toDegrees, float centerX, float centerY) {
mFromDegrees = fromDegrees;
mToDegrees = toDegrees;
mCenterX = centerX;
mCenterY = centerY;
}
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
mCamera = new Camera();
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
final float fromDegrees = mFromDegrees;
float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
final float centerX = mCenterX;
final float centerY = mCenterY;
final Camera camera = mCamera;
final Matrix matrix = t.getMatrix();
camera.save();
camera.rotateY(degrees);
camera.getMatrix(matrix);
camera.restore();
matrix.preTranslate(-centerX, -centerY);
matrix.postTranslate(centerX, centerY);
}
}
主要就是通过矩阵变换,实现动画效果,改变这个类,我们可以实现自定义动画效果。
2、侧边菜单动画效果
有了动画效果后,需要将动画效果运用在侧边菜单上,定义ViewAnimator,代码如下:
/**
* View动画
* Created by dingxiaolei on 16/4/1.
*/
public class ViewAnimator {
private final int ANIMATION_DURATION = 175;
private Activity activity;
private List list = new ArrayList<>();
private List viewList = new ArrayList<>();
private ViewAnimatorListener animatorListener;
public ViewAnimator(Activity activity, List list, ViewAnimatorListener animatorListener) {
this.activity = activity;
this.list = list;
this.animatorListener = animatorListener;
}
public void showMenuContent() {
setViewsClickable(true);
viewList.clear();
animatorListener.showMenu();
final int size = list.size();
for (int i = 0; i < size; i++) {
String menuItemName = list.get(i).getItemName();
int menuItemImgRes = list.get(i).getImageRes();
View viewMenu = activity.getLayoutInflater().inflate(R.layout.menu_list_item, null);
viewMenu.setVisibility(View.GONE);
TextView textView = (TextView) viewMenu.findViewById(R.id.menu_item_text);
ImageView imageView = (ImageView) viewMenu.findViewById(R.id.menu_item_image);
textView.setText(menuItemName);
imageView.setBackgroundResource(menuItemImgRes);
final int finalI = i;
viewMenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (finalI == size - 1) {
hideMenuContent();
} else {
animatorListener.onSwitch(finalI);
}
}
});
viewList.add(viewMenu);
animatorListener.addViewToContainer(viewMenu);
final double position = i;
final double delay = 3 * ANIMATION_DURATION * (position / size);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
animateView(finalI);
}
}, (long) delay);
}
}
private void animateView(int position) {
View view = viewList.get(position);
view.setVisibility(View.VISIBLE);
FlipAnimation flipAnimation = new FlipAnimation(90, 0, 0.0f, view.getHeight() / 2.0f);
flipAnimation.setDuration(ANIMATION_DURATION);
flipAnimation.setFillAfter(true);
view.startAnimation(flipAnimation);
}
private void hideMenuContent() {
setViewsClickable(false);
int size = list.size();
for (int i = 0; i < size; i++) {
final double position = i;
final double delay = 3 * ANIMATION_DURATION * (position / size);
new Handler().postDelayed(new Runnable() {
public void run() {
animateHideView((int) position);
}
}, (long) delay);
}
}
private void animateHideView(int position) {
View view = viewList.get(position);
view.setVisibility(View.VISIBLE);
FlipAnimation flipAnimation = new FlipAnimation(0, 90, 0.0f, view.getHeight() / 2.0f);
flipAnimation.setDuration(ANIMATION_DURATION);
flipAnimation.setFillAfter(true);
if (position == viewList.size() - 1) {
animatorListener.hideMenu();
}
view.startAnimation(flipAnimation);
}
private void setViewsClickable(boolean clickable) {
for (View view : viewList) {
view.setEnabled(clickable);
}
}
public interface ViewAnimatorListener {
public void onSwitch(int position);
public void addViewToContainer(View view);
public void showMenu();
public void hideMenu();
}
}
其中showMenuContent是显示菜单函数,hideMenuContent是隐藏菜单函数,通过Handler().postDelayed,来进行动画的延时显示。在这个类中,我们定义了一个内部接口ViewAnimatorListener,当这个函数被调用时,可以通过接口实现一些效果,这点可以在MainActivity中看出。
3、定义菜单每一项的数据结构
就是一张图片一个文字,没啥说的,代码如下
/**
* 侧滑菜单Item
* Created by dingxiaolei on 16/4/1.
*/
public class MenuItemBean {
private String itemName;
private int imageRes;
public MenuItemBean() {
}
public MenuItemBean(String itemName, int imageRes) {
this.itemName = itemName;
this.imageRes = imageRes;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public int getImageRes() {
return imageRes;
}
public void setImageRes(int imageRes) {
this.imageRes = imageRes;
}
}
4、定义Fragment
在点击侧边菜单每一项的时候,会进行页面切换,只要替换其中的fragment即可,这里我就定义了一个fragment,中间一个textview,fragment代码如下
public class ContentFragment extends android.support.v4.app.Fragment{
private RelativeLayout relativeLayout;
private TextView textView;
private int res;
private List list = new ArrayList<>();
public static ContentFragment newInstance(int resId) {
ContentFragment contentFragment = new ContentFragment();
Bundle bundle = new Bundle();
bundle.putInt(Integer.class.getName(), resId);
contentFragment.setArguments(bundle);
return contentFragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_content, container, false);
relativeLayout = (RelativeLayout) view.findViewById(R.id.content);
textView = (TextView) view.findViewById(R.id.text);
relativeLayout.setBackgroundResource(list.get(res).getImageRes());
textView.setText(list.get(res).getItemName());
return view;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
res = getArguments().getInt(Integer.class.getName(), 0);
initData();
}
private void initData() {
String[] menuItemNameList = {"姓名", "性别", "年龄", "籍贯", "配偶", "学历"};
MenuItemBean menuItem0 = new MenuItemBean(menuItemNameList[0], R.color.red);
list.add(menuItem0);
MenuItemBean menuItem1 = new MenuItemBean(menuItemNameList[1], R.color.green);
list.add(menuItem1);
MenuItemBean menuItem2 = new MenuItemBean(menuItemNameList[2], R.color.blue);
list.add(menuItem2);
MenuItemBean menuItem3 = new MenuItemBean(menuItemNameList[3], R.color.yellow);
list.add(menuItem3);
MenuItemBean menuItem4 = new MenuItemBean(menuItemNameList[4], R.color.lightBlue);
list.add(menuItem4);
MenuItemBean menuItem5 = new MenuItemBean(menuItemNameList[5], R.color.pink);
list.add(menuItem5);
}
}
5、MainActivity
最后是在主页面中,添加侧边菜单,这样达到了可以复用的效果,同时实现ViewAnimator中所有的接口方法,达到我们自己所想要的效果。代码如下:
public class MainActivity extends AppCompatActivity implements ViewAnimator.ViewAnimatorListener {
private ViewAnimator viewAnimator;
private LinearLayout linearLayout;
private ScrollView scrollView;
private ImageView showMenuImageView;
private ContentFragment contentFragment;
private List list = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
contentFragment = ContentFragment.newInstance(0);
getSupportFragmentManager().beginTransaction()
.replace(R.id.fram_content, contentFragment)
.commit();
createMenuList();
linearLayout = (LinearLayout) findViewById(R.id.left_drawer);
showMenuImageView = (ImageView) findViewById(R.id.show_slide_menu);
scrollView = (ScrollView) findViewById(R.id.scrollView);
viewAnimator = new ViewAnimator(this, list, this);
showMenuImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// showMenuImageView.setVisibility(View.GONE);
viewAnimator.showMenuContent();
}
});
}
private void createMenuList() {
String[] menuItemNameList = {"姓名", "性别", "年龄", "籍贯", "配偶", "学历", "隐藏"};
MenuItemBean menuItem0 = new MenuItemBean(menuItemNameList[0], R.drawable.ic_apps_grey600_24dp);
list.add(menuItem0);
MenuItemBean menuItem1 = new MenuItemBean(menuItemNameList[1], R.drawable.ic_arrow_drop_down_circle_grey600_24dp);
list.add(menuItem1);
MenuItemBean menuItem2 = new MenuItemBean(menuItemNameList[2], R.drawable.ic_airplanemode_on_grey600_24dp);
list.add(menuItem2);
MenuItemBean menuItem3 = new MenuItemBean(menuItemNameList[3], R.drawable.ic_dvr_grey600_24dp);
list.add(menuItem3);
MenuItemBean menuItem4 = new MenuItemBean(menuItemNameList[4], R.drawable.ic_check_grey600_24dp);
list.add(menuItem4);
MenuItemBean menuItem5 = new MenuItemBean(menuItemNameList[5], R.drawable.ic_access_alarm_grey600_24dp);
list.add(menuItem5);
MenuItemBean menuItem6 = new MenuItemBean(menuItemNameList[6], R.drawable.ic_close_grey600_24dp);
list.add(menuItem6);
}
@Override
public void onSwitch(int position) {
replaceFragment(position);
}
private void replaceFragment(int position) {
ContentFragment contentFragment = ContentFragment.newInstance(position);
getSupportFragmentManager().beginTransaction().replace(R.id.fram_content, contentFragment).commit();
}
@Override
public void addViewToContainer(View view) {
linearLayout.addView(view);
}
@Override
public void showMenu() {
scrollView.setVisibility(View.VISIBLE);
showMenuImageView.setVisibility(View.GONE);
}
@Override
public void hideMenu() {
scrollView.setVisibility(View.GONE);
linearLayout.removeAllViews();
showMenuImageView.setVisibility(View.VISIBLE);
}
}
项目源码下载:http://download.csdn.net/detail/ddxxll2008/9487997