Android——SideMenu侧滑菜单的实现

来源:互联网 发布:渐飞数据库 编辑:程序博客网 时间:2024/06/03 13:46

  最近有些忙,有一段时间没有写博客了,今天跟大家分享下SideMenu侧滑菜单的实现,自定义的Animation效果,给别人看起来就感觉好屌的样子,哈哈!不多说,先看看实现的效果。
  
  这里写图片描述
  
总体来说也并不复杂,下面给大家看下整个项目的结构:
  结构图
  
以下是实现的源码及详细步骤:
  新建android studio项目我这边就不讲述了,说一下android studio关联library项目,很简单,我贴几张图片大家就知道了,File->
 这里写图片描述

然后
 这里写图片描述

  这样就可以了。
  
首先看下ViewAnimationUtils类
  

package com.lai.library.utils;import android.app.Activity;import android.os.Handler;import android.support.v4.widget.DrawerLayout;import android.view.View;import android.view.animation.AccelerateInterpolator;import android.view.animation.Animation;import android.widget.ImageView;import com.lai.library.animations.FlipAnimation;import com.lai.library.interfaces.Resourceble;import com.lai.library.interfaces.ScreenShortable;import java.util.ArrayList;import java.util.List;import static com.lai.sidemenu.R.layout;/** * Created by henry on 2016/5/11. * 自定义的动画效果 */public class ViewAnimationUtils<T extends Resourceble> {    /**     * 切换隐藏与显示的效果     */    private final int ANIMATION_DURATION = 10;    public static final int CIRCULAR_REVEAL_ANIMATION_DURATION = 20;    private Activity activity;    private List<T> list;    private List<View> viewList = new ArrayList<View>();  //View集合    private ScreenShortable screenShortable;//获取图片    private DrawerLayout drawerLayout;    private ViewAnimatorListener viewAnimatorListener;//实现定义接口    /**     * 构造器     */    public ViewAnimationUtils(Activity activity, List<T> list, ScreenShortable screenShortable, DrawerLayout drawerLayout, ViewAnimatorListener viewAnimatorListener) {        this.activity = activity;        this.list = list;        this.screenShortable = screenShortable;        this.drawerLayout = drawerLayout;        this.viewAnimatorListener = viewAnimatorListener;    }    /**     * 显示菜单的数量     */    public void showMenuCount() {        setViewsClickable(false);//刚显示个数时view是出于false的状态        viewList.clear();//清空组件        double size = list.size();        for (int i = 0; i < size; i++) {            View viewMenu = activity.getLayoutInflater().inflate(layout.menu_list_item, null);            final int finalI = i;            /**             * view的点击事件             */            viewMenu.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View v) {                    int[] localtion = {0, 0};//用数组坐标记录位置                    v.getLocationOnScreen(localtion);//垂直                    switchItem(list.get(finalI), localtion[1] + v.getHeight() / 2);     //点击后调用switchItem隐藏                }            });            //得到资源并设置            ((ImageView) viewMenu.findViewById(com.lai.sidemenu.R.id.menu_item_image)).setImageResource(list.get(i).getImageRes());            viewMenu.setVisibility(View.GONE);            viewMenu.setEnabled(false);            viewList.add(viewMenu);//添加list中            viewAnimatorListener.addViewToContainer(viewMenu);//添加到动画接口中            final double position = i;            final double delay = 3 * ANIMATION_DURATION * (position / size);            /**             * 耗时操作             */            new Handler().postDelayed(new Runnable() {                @Override                public void run() {                    if (position < viewList.size()) {                        animateView((int) position);                    }                    if (position == viewList.size() - 1) {                        screenShortable.takeScreenShort();                        setViewsClickable(true);                    }                }            }, (long) delay);        }    }    /**     * 设置View     */    private void animateView(int position) {        final View view = viewList.get(position);        view.setVisibility(View.VISIBLE);//可见        FlipAnimation rotation = new FlipAnimation(90, 0, 0.0f, view.getHeight() / 2.0f);//设置动画效果        rotation.setDuration(ANIMATION_DURATION);        rotation.setFillAfter(true);        rotation.setInterpolator(new AccelerateInterpolator());        //动画监听        rotation.setAnimationListener(new Animation.AnimationListener() {            @Override            public void onAnimationStart(Animation animation) {            }            @Override            public void onAnimationEnd(Animation animation) {                view.clearAnimation();//结束后清除动画效果            }            @Override            public void onAnimationRepeat(Animation animation) {            }        });    }    /**     * 点击的Item     */    private void switchItem(Resourceble slideMenuItem, int topPosition) {        this.screenShortable = viewAnimatorListener.onSwitch(slideMenuItem, screenShortable, topPosition);        //点击后隐藏viewList        hideMenuContent();    }    /**     * 隐藏menu     */    private void hideMenuContent() {        setViewsClickable(false);        double size = list.size();        //隐藏全部        for (int i = list.size(); i >= 0; i--) {            final double position = i;//记录在viewList中点击的position作为头部,添加动画效果            final double delay = 3 * ANIMATION_DURATION * (position / size);    //线程时间(其实这一步没必要,线程的时间可以直接写死)            //耗时操作应放在handler里面操作            new Handler().postDelayed(new Runnable() {                @Override                public void run() {                    if (position < viewList.size()) {                        //设置隐藏时的动画                        animateHideView((int) position);                    }                }            }, (long) delay);        }    }    /**     * 设置view隐藏时的动画     */    private void animateHideView(final int position) {        final View view = viewList.get(position);//得到点击的view        //0表示正在处于的状态为0°,90为操作后的度数,0.0f表示起始精确位置,centerY为view高度的二分之一        FlipAnimation rotation = new FlipAnimation(0, 90, 0.0f, view.getHeight() / 2.0f);//设置动画        rotation.setDuration(ANIMATION_DURATION);   //设置动画时间        rotation.setFillAfter(true);        rotation.setInterpolator(new AccelerateInterpolator());        rotation.setAnimationListener(new Animation.AnimationListener() {            @Override            public void onAnimationStart(Animation animation) {            }            /**             * 结束时             * @param animation             */            @Override            public void onAnimationEnd(Animation animation) {                view.clearAnimation();                view.setVisibility(View.INVISIBLE);//隐藏view                if (position == viewList.size() - 1) //防止越界                {                    viewAnimatorListener.enableHomeButton();                    drawerLayout.closeDrawers();//关闭drawers                }            }            @Override            public void onAnimationRepeat(Animation animation) {            }        });        view.startAnimation(rotation);//开始动画    }    /**     * 设置控件是否可用     */    private void setViewsClickable(boolean clickable) {        //点击以后view不可再重新点击        viewAnimatorListener.disableHomeButton();        /**         * 点击第几个view         */        for (View view : viewList) {            view.setEnabled(clickable);        }    }    /**     * 定义接口     */    public interface ViewAnimatorListener {        //点击MenuItem        public ScreenShortable onSwitch(Resourceble slideMenuItem, ScreenShortable screenShortable, int position);        public void disableHomeButton();        public void enableHomeButton();        public void addViewToContainer(View view);    }}

  上面的注释写的非常详细了,一目了然。

下面是FlipAnimation类,自定义的动画效果,代码量很少,更容易理解!

package com.lai.library.animations;/** * Created by henry on 2016/5/11. */import android.graphics.Camera;import android.graphics.Matrix;import android.view.animation.Animation;import android.view.animation.Transformation;/** * 自定义动画效果 */public class FlipAnimation extends Animation {    private final float mFromDegrees;//起始的度数    private final float mToDegrees;//要到达的度数    private final float mCenterX;// 水平方向X轴的位置    private final float mCenterY;//Y轴的位置    private Camera mCamera;    /**     * 构造器     *     * @param fromDegrees     * @param toDegrees     * @param centerX     * @param centerY     */    public FlipAnimation(float fromDegrees, float toDegrees, float centerX, float centerY) {        this.mFromDegrees = fromDegrees;        this.mToDegrees = toDegrees;        this.mCenterX = centerX;        this.mCenterY = centerY;    }    /**     * 初始化屏幕宽度创建Camera     *     * @param width     * @param height     * @param parentWidth     * @param parentHeight     */    public void initialize(int width, int height, int parentWidth, int parentHeight) {        super.initialize(width, height, parentWidth, parentHeight);        mCamera = new Camera();    }    /**     * 动画效果     */    public void applyTransformation(float interpolatedTime, Transformation transformation) {        final float fromDegrees = mFromDegrees;        float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);//总度数        /**         * 获取值         */        final float centerX = mCenterX;        final float centerY = mCenterY;        final Camera camera = mCamera;        /**         * 对图片进行处理         * Translate           平移变换         Rotate                旋转变换         Scale                  缩放变换         Skew                  错切变换         */        final Matrix matrix = transformation.getMatrix();        camera.save();  //保存当前状态 ,与restore是成对出现的        camera.rotateY(degrees);//Y轴旋转        camera.getMatrix(matrix);//得到设置后的matrix        camera.restore();//回复当前状态        /**         * 下面两句标识以动画中心点为中央部分         */        matrix.preTranslate(-centerX, -centerY);        matrix.postTranslate(centerX, centerY);    }}

还有几个要实现的接口就不贴出来了,到最后面可以自己去下载源码。

  写完关联的library以后,接下来就是我们实际操作的页面了。我们只需要在MainActivity里面嵌套一个Fragment就行了,然后再实现完ViewAnimationUtils的四个接口,马上开始。
  第一步写一个Fragment类

package com.lai.sidemenu.fragment;import android.app.Fragment;import android.graphics.Bitmap;import android.graphics.Canvas;import android.os.Bundle;import android.support.annotation.Nullable;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.ImageView;import com.lai.library.interfaces.ScreenShortable;import com.lai.sidemenu.R;/** * Created by henry on 2016/5/11. */public class ContentFragment extends Fragment implements ScreenShortable {    /**     * 点击图片需要切换的选项value     */    public static final String CLOSE = "关闭";    public static final String BUILDING = "创建";    public static final String BOOK = "书本";    public static final String PAINT = "交点";    public static final String CASE = "案例";    public static final String SHOP = "商品";    public static final String PARTY = "派对";    public static final String MOVIE = "电影";    private View rootView;    private ImageView mImageView;    private int res;    private Bitmap bitmap;    public static ContentFragment newInstance(int resId) {        ContentFragment contentFragment = new ContentFragment();        Bundle bundle = new Bundle();        bundle.putInt(Integer.class.getName(), resId);        contentFragment.setArguments(bundle);//设置Arguments        return contentFragment;    }    @Override    public void onViewCreated(View view, Bundle savedInstanceState) {        super.onViewCreated(view, savedInstanceState);        this.rootView = view.findViewById(R.id.container);    }    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        res = getArguments().getInt(Integer.class.getName());//获取Arguments的值    }    @Nullable    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {        View view = inflater.inflate(R.layout.fragment_main, null);        mImageView = (ImageView) view.findViewById(R.id.image_content);        mImageView.setClickable(true);        mImageView.setFocusable(true);        mImageView.setImageResource(res);        return view;    }    /**     * 设置bitmap     * 耗时操作     */    @Override    public void takeScreenShort() {        Thread thread=new Thread(){            @Override            public void run() {                Bitmap bitmap=Bitmap.createBitmap(rootView.getWidth(),rootView.getHeight(),Bitmap.Config.ARGB_8888);                Canvas canvas=new Canvas(bitmap);                rootView.draw(canvas);                ContentFragment.this.bitmap=bitmap;            }        };        thread.start();    }    @Override    public Bitmap getBitmap() {        return bitmap;    }}

在MainActivity中主要就是为Fragment页面添加菜单项,一些点击的操作,见下面代码:

package com.lai.sidemenu;import android.content.res.Configuration;import android.graphics.Color;import android.graphics.drawable.BitmapDrawable;import android.os.Bundle;import android.os.PersistableBundle;import android.support.v4.widget.DrawerLayout;import android.support.v7.app.ActionBarActivity;import android.support.v7.app.ActionBarDrawerToggle;import android.support.v7.widget.Toolbar;import android.view.MenuItem;import android.view.View;import android.view.animation.AccelerateDecelerateInterpolator;import android.widget.LinearLayout;import com.lai.library.interfaces.Resourceble;import com.lai.library.interfaces.ScreenShortable;import com.lai.library.model.SlideMenuitem;import com.lai.library.utils.ViewAnimationUtils;import com.lai.sidemenu.fragment.ContentFragment;import java.util.ArrayList;import java.util.List;public class MainActivity extends ActionBarActivity implements ViewAnimationUtils.ViewAnimatorListener {    private ContentFragment contentFragment;    private DrawerLayout drawerLayout;    private ActionBarDrawerToggle drawerToggle;    private List<SlideMenuitem> list = new ArrayList<SlideMenuitem>();    private ViewAnimationUtils viewAnimationUtils;    private int res = R.drawable.content_music;    private LinearLayout linearLayout;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        contentFragment = ContentFragment.newInstance(R.drawable.content_music);        getFragmentManager().beginTransaction().replace(R.id.container_frame, contentFragment).commit();        drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);        drawerLayout.setScrimColor(Color.TRANSPARENT);        linearLayout = (LinearLayout) findViewById(R.id.left_drawer);        linearLayout.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                drawerLayout.closeDrawers();            }        });        setActionBar();        createMenuList();        viewAnimationUtils = new ViewAnimationUtils<>(this, list, contentFragment, drawerLayout, this);    }    /**     * 设置ActionBar一些基础操作     */    private void setActionBar() {        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);        setSupportActionBar(toolbar);        getSupportActionBar().setHomeButtonEnabled(true);        getSupportActionBar().setDisplayHomeAsUpEnabled(true);        drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close) {            public void onDrawerClosed(View view) {                super.onDrawerClosed(view);                linearLayout.removeAllViews();                linearLayout.invalidate();            }            @Override            public void onDrawerSlide(View drawerView, float slideOffset) {                super.onDrawerSlide(drawerView, slideOffset);                if (slideOffset > 0.6 && linearLayout.getChildCount() == 0) {                    viewAnimationUtils.showMenuCount();                }            }            @Override            public void onDrawerOpened(View drawerView) {                super.onDrawerOpened(drawerView);            }        };        drawerLayout.setDrawerListener(drawerToggle);    }    /**     * 创建menu菜单     */    private void createMenuList() {        SlideMenuitem menuitemOne = new SlideMenuitem(ContentFragment.CLOSE, R.drawable.icn_close);        list.add(menuitemOne);        SlideMenuitem menuitemTwo = new SlideMenuitem(ContentFragment.BUILDING, R.drawable.icn_1);        list.add(menuitemTwo);        SlideMenuitem menuitemthree = new SlideMenuitem(ContentFragment.BOOK, R.drawable.icn_2);        list.add(menuitemthree);        SlideMenuitem menuitemFour = new SlideMenuitem(ContentFragment.CASE, R.drawable.icn_3);        list.add(menuitemFour);        SlideMenuitem menuitemFive = new SlideMenuitem(ContentFragment.MOVIE, R.drawable.icn_4);        list.add(menuitemFive);        SlideMenuitem menuitemSix = new SlideMenuitem(ContentFragment.PAINT, R.drawable.icn_5);        list.add(menuitemSix);        SlideMenuitem menuitemSeven = new SlideMenuitem(ContentFragment.SHOP, R.drawable.icn_6);        list.add(menuitemSeven);        SlideMenuitem menuitemEight = new SlideMenuitem(ContentFragment.PARTY, R.drawable.icn_7);        list.add(menuitemEight);    }    /**     * 开始状态     *     * @param savedInstanceState     * @param persistentState     */    @Override    public void onPostCreate(Bundle savedInstanceState, PersistableBundle persistentState) {        super.onPostCreate(savedInstanceState, persistentState);        drawerToggle.syncState();    }    /**     * 配置drawerToggle     *     * @param newConfig     */    @Override    public void onConfigurationChanged(Configuration newConfig) {        super.onConfigurationChanged(newConfig);        drawerToggle.onConfigurationChanged(newConfig);    }    @Override    public boolean onOptionsItemSelected(MenuItem item) {        if (drawerToggle.onOptionsItemSelected(item)) {            return true;        }        return super.onOptionsItemSelected(item);    }    @Override    public ScreenShortable onSwitch(Resourceble slideMenuItem, ScreenShortable screenShortable, int position) {        switch (slideMenuItem.getName()) {            case ContentFragment.CLOSE:                return screenShortable;            default:                return replaceFragment(screenShortable, position);        }    }    /**     * 切换图片操作     *     * @param screenShortable     * @param position     * @return     */    private ScreenShortable replaceFragment(ScreenShortable screenShortable, int position) {        this.res = this.res == R.drawable.content_music ? R.drawable.content_films : R.drawable.content_music;        View view = findViewById(R.id.container_frame);        int finalRadius = Math.max(view.getWidth(), view.getHeight());        io.codetail.animation.SupportAnimator animator = io.codetail.animation.ViewAnimationUtils.createCircularReveal(view, 0, position, 0, finalRadius);        animator.setInterpolator(new AccelerateDecelerateInterpolator());        animator.setDuration(ViewAnimationUtils.CIRCULAR_REVEAL_ANIMATION_DURATION);        findViewById(R.id.content_overlay).setBackgroundDrawable(new BitmapDrawable(getResources(), screenShortable.getBitmap()));        animator.start();//开始动画        ContentFragment contentFragment = ContentFragment.newInstance(this.res);        getFragmentManager().beginTransaction().replace(R.id.content_frame, contentFragment).commit();        return contentFragment;    }    /**     * 设置button不可用     */    @Override    public void disableHomeButton() {        getSupportActionBar().setHomeButtonEnabled(false);    }    @Override    public void enableHomeButton() {        getSupportActionBar().setHomeButtonEnabled(true);        drawerLayout.closeDrawers();    }    @Override    public void addViewToContainer(View view) {        linearLayout.addView(view);    }}

主要的代码已经贴出来了,如果感兴趣的话可以从下面下载项目。

项目源码

0 0