Android 使用ViewDragHelper实现向slidingMenu侧滑菜单的效果

第一步:实现类

import com.android.view.tool.Logger;

import android.content.Context;
import android.support.v4.widget.ViewDragHelper;
import android.support.v4.widget.ViewDragHelper.Callback;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

/**
 * DrawerLayout侧滑布局
 * 
 * @Project App_View
 * @Package com.android.view.dragview
 * @author chenlin
 * @version 1.0
 * @Note TODO
 */
public class SlideLayout extends ViewGroup {
    private static final String TAG = "SlideLayout";
    /** 最小距离 */
    private static final int MIN_DRAWER_MARGIN = 64;
    /** 最小移动速度 */
    private static final int MIN_FLING_VELOCITY = 400;

    private ViewDragHelper mHelper;
    /** 左侧菜单 */
    private View mLeftMenuView;
    /** 内容视图 */
    private View mContentView;
    /** 最小移动速度 */
    private float minVel;
    /** 菜单的偏移量 */
    private float mLeftMenuOffset;
    private int mMinDrawerMargin;

    public SlideLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SlideLayout(Context context) {
        this(context, null);
    }

    public SlideLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // 得到密度
        float density = getResources().getDisplayMetrics().density;
        minVel = MIN_FLING_VELOCITY * density;
        mMinDrawerMargin = (int) (MIN_DRAWER_MARGIN * density + 0.5f);

        // 初始化
        mHelper = ViewDragHelper.create(this, 1.0f, cb);
        // 从左侧滑入
        mHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
        // 设置最新速度
        mHelper.setMinVelocity(minVel);
    }

    private Callback cb = new Callback() {

        /**
         * 说明只有mLeftMenuView可以移动
         */
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            Logger.e(TAG, "tryCaptureView");
            return child == mLeftMenuView;
        }

        /**
         * 触摸到左边时,capture mLeftMenuView
         */
        @Override
        public void onEdgeDragStarted(int edgeFlags, int pointerId) {
            Logger.e(TAG, "onEdgeDragStarted");
            mHelper.captureChildView(mLeftMenuView, pointerId);
        }

        /**
         * 水平方向移动的距离
         */
        @Override
        public int getViewHorizontalDragRange(View child) {
            return child == mLeftMenuView ? child.getWidth() : 0;
        }

        /**
         * 菜单移动时,用来设置菜单是否显示
         */
        @Override
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
            // 1.先得到菜单的宽度
            int childWidth = changedView.getWidth();
            // 2.得到偏移量
            float offset = (childWidth + left) * 1.0f / childWidth;
            // 3.设置是否可见
            changedView.setVisibility(offset == 0 ? VISIBLE : GONE);

            // 4.
            mLeftMenuOffset = offset;

            // 5.视图改变了,重绘制
            invalidate();
        }

        /**
         * 手指放开时 主要用于设定左侧菜单的位置
         */
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            // 1.得到宽度
            int childWidth = releasedChild.getWidth();
            // 2.得到偏移量
            float offset = (childWidth + releasedChild.getLeft()) * 1.0f / childWidth;

            // 3.设置位置,如果在右边,则菜单移动到0,否则移动到最左侧
            int finalLeft = xvel > 0 || xvel == 0 && offset > 0 ? 0 : -childWidth;
            mHelper.settleCapturedViewAt(finalLeft, releasedChild.getTop());
        }

        /**
         * 计算left 我们的目标范围是-mLeft.getWidth 到 0 的宽度
         */
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            return Math.max(-child.getWidth(), Math.min(left, 0));
        }

        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
            return super.clampViewPositionVertical(child, top, dy);
        }

    };

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        View leftMenuView = getChildAt(1);

        // 1.得到测量的size
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        // 2.测量父控件
        setMeasuredDimension(widthSize, heightSize);
        // 3.先设左菜单
        MarginLayoutParams lp = (MarginLayoutParams) leftMenuView.getLayoutParams();

        int leftMenuWidthSpec = getChildMeasureSpec(widthMeasureSpec, lp.leftMargin + lp.rightMargin + mMinDrawerMargin, lp.width);
        int leftMenuHeighSpec = getChildMeasureSpec(heightMeasureSpec, lp.topMargin + lp.bottomMargin, lp.height);
        // 4.测量菜单
        leftMenuView.measure(leftMenuWidthSpec, leftMenuHeighSpec);

        // 5.右边的内容view
        View contentView = getChildAt(0);
        lp = (MarginLayoutParams) contentView.getLayoutParams();

        int contentWidthSpec = MeasureSpec.makeMeasureSpec(widthSize - lp.leftMargin - lp.rightMargin, lp.width);
        int contentHeightSpec = MeasureSpec.makeMeasureSpec(heightSize - lp.topMargin - lp.bottomMargin, lp.height);
        contentView.measure(contentWidthSpec, contentHeightSpec);

        // 6.把测量后的view赋值给定义的
        mLeftMenuView = leftMenuView;
        mContentView = contentView;

    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        // 1.先获得子view
        View menuView = mLeftMenuView;
        View contentView = mContentView;

        // 2.进行内容定位
        MarginLayoutParams lp = (MarginLayoutParams) contentView.getLayoutParams();
        contentView.layout(lp.leftMargin, lp.topMargin, lp.leftMargin + mLeftMenuView.getMeasuredWidth(),
                lp.topMargin + mLeftMenuView.getMeasuredHeight());

        // 3.菜单定位
        lp = (MarginLayoutParams) menuView.getLayoutParams();
        final int menuWidth = menuView.getMeasuredWidth();
        int left = -menuWidth + (int) (menuWidth * mLeftMenuOffset);
        menuView.layout(left, lp.topMargin, left + menuView.getMeasuredWidth(), lp.topMargin + menuView.getMeasuredHeight());
    }

    /**
     * 把事件交由mHelper处理
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        mHelper.processTouchEvent(ev);
        return true;
    }

    /**
     * 如果在移动,则不断的绘制
     */
    @Override
    public void computeScroll() {
        if (mHelper.continueSettling(true)) {
            invalidate();
        }
    }

    /**
     * 关闭slide
     */
    public void closeSlide() {
        View menuView = mLeftMenuView;
        mLeftMenuOffset = 0.0f;
        mHelper.smoothSlideViewTo(menuView, -menuView.getWidth(), menuView.getTop());
    }

    /**
     * 打开slide
     */
    public void openSlide() {
        View menuView = mLeftMenuView;
        mLeftMenuOffset = 1.0f;
        mHelper.smoothSlideViewTo(menuView, 0, menuView.getTop());
    }

    /**
     * 设置全屏
     */
    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    }

    /**
     * 把布局的参数交由MarginLayoutParam来处理
     */
    @Override
    protected LayoutParams generateLayoutParams(LayoutParams p) {
        return new MarginLayoutParams(p);
    }

}

第二步:实现类

/**
 * 实现侧滑效果
 * 
 * @Project App_View
 * @Package com.android.view.dragview
 * @author chenlin
 * @version 1.0
 * @Date 2016年4月22日
 * @Note TODO
 */
public class SlideActivity extends ActionBarActivity {

    private SlideMenuFragment mMenuFragment;
    private SlideLayout mSlideLayout;
    private TextView mContentTv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_slide);
        initViews();
        initFragment();
    }

    private void initViews() {
        mSlideLayout = (SlideLayout) findViewById(R.id.id_drawerlayout);
        mContentTv = (TextView) findViewById(R.id.id_content_tv);
    }

    private void initFragment() {
        FragmentManager fm = getSupportFragmentManager();
        mMenuFragment = (SlideMenuFragment) fm.findFragmentById(R.id.id_container_menu);
        if (mMenuFragment == null) {
            mMenuFragment = new SlideMenuFragment();
            fm.beginTransaction().add(R.id.id_container_menu, mMenuFragment).commit();
        }
        mMenuFragment.setOnMenuItemSelectedListener(new SlideMenuFragment.OnMenuItemSelectedListener() {
            @Override
            public void menuItemSelected(String title) {
                mSlideLayout.closeSlide();
                mContentTv.setText(title);
            }
        });
    }


}

布局文件

<?xml version="1.0" encoding="utf-8"?>
<com.android.view.dragview.SlideLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/id_drawerlayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <!-- content -->

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#44ff0000"
        android:clickable="true" >

        <TextView
            android:id="@+id/id_content_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="hello world"
            android:textSize="40sp" />
    </RelativeLayout>

    <!-- menu -->

    <FrameLayout
        android:id="@+id/id_container_menu"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    </FrameLayout>

</com.android.view.dragview.SlideLayout>

第四步:创建fragment

import com.android.view.R;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.ListFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;

/**
 * 左侧菜单
 * @Project    App_View
 * @Package    com.android.view.dragview
 * @author     chenlin
 * @version    1.0
 * @Date       2016年4月22日
 * @Note       TODO
 */
public class SlideMenuFragment extends ListFragment {
    /**菜单个数*/
    private static final int SIZE_MENU_ITEM = 3;
    /**菜单集合*/
    private SlideMenuItem[] mItems = new SlideMenuItem[SIZE_MENU_ITEM];


    private SlideMenuAdapter mAdapter;

    //---回调函数----------------------------------------------
    public OnMenuItemSelectedListener mlistener;
    public interface OnMenuItemSelectedListener {
        void menuItemSelected(String title);
    }
    public void setOnMenuItemSelectedListener(OnMenuItemSelectedListener listener) {
        mlistener = listener;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //初始化菜单项
        SlideMenuItem menuItem = null;
        for (int i = 0; i < mItems.length; i++) {
            menuItem = new SlideMenuItem(getResources().getStringArray(R.array.array_left_menu)[i], false, R.drawable.music_36px, R.drawable.music_36px_light);
            mItems[i] = menuItem;
        }
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        view.setBackgroundColor(0xffffffff);
        //加载数据
        mAdapter = new SlideMenuAdapter(getActivity(), mItems);
        setListAdapter(mAdapter);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return super.onCreateView(inflater, container, savedInstanceState);
    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);
        if (mlistener != null) {
            SlideMenuItem item = (SlideMenuItem) getListAdapter().getItem(position);
            mlistener.menuItemSelected(item.text);
        }
        mAdapter.setSelected(position);
    }
}

第四步:创建适配器

import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.android.view.R;

/**
 * 菜单适配器
 * @Project    App_View
 * @Package    com.android.view.dragview
 * @author     chenlin
 * @version    1.0
 * @Note       TODO
 */
public class SlideMenuAdapter extends ArrayAdapter<SlideMenuItem> {
    private LayoutInflater mInflater;
    private int mSelected;

    public SlideMenuAdapter(Context context, SlideMenuItem[] objects) {
        super(context, -1, objects);
        mInflater = LayoutInflater.from(context);
    }

    public void setSelected(int position) {
        this.mSelected = position;
        notifyDataSetChanged();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        SlideMenuItem item = getItem(position);
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.item_left_menu, parent, false);
        }
        ImageView iv = (ImageView) convertView.findViewById(R.id.id_item_icon);
        TextView title = (TextView) convertView.findViewById(R.id.id_item_title);
        title.setText(item.text);
        iv.setImageResource(item.icon);
        convertView.setBackgroundColor(Color.TRANSPARENT);

        //如果是选中的
        if (position == mSelected) {
            iv.setImageResource(item.iconSelected);
            convertView.setBackgroundColor(getContext().getResources().getColor(R.color.state_menu_item_selected));
        }

        return convertView;
    }

}

实体类:

/**
 * 菜单项属性值
 * 
 * @Project App_View
 * @Package com.android.view.dragview
 * @author chenlin
 * @version 1.0
 * @Note TODO
 */
public class SlideMenuItem {
    public boolean isSelected; //是否选中
    public String text;//文本
    public int icon;//图标
    public int iconSelected;//被选中的图片

    public SlideMenuItem(String text, boolean isSelected, int icon, int iconSelected) {
        this.text = text;
        this.isSelected = isSelected;
        this.icon = icon;
        this.iconSelected = iconSelected;
    }

}

颜色选择器state_menu_item_selected.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true"
          android:drawable="@android:color/white"/> <!-- pressed -->
    <item android:drawable="@android:color/black"/> <!-- default -->
</selector>

数组文件arrays.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="array_left_menu">
        <item>首页</item>
        <item>新闻</item>
        <item>游戏</item>
    </string-array>
</resources>

———————————————————————
有需求者请加qq:136137465,非诚勿扰
(java 架构师全套教程,共760G, 让你从零到架构师,每月轻松拿3万)
01.高级架构师四十二个阶段高
02.Java高级系统培训架构课程148课时
03.Java高级互联网架构师课程
04.Java互联网架构Netty、Nio、Mina等-视频教程
05.Java高级架构设计2016整理-视频教程
06.架构师基础、高级片
07.Java架构师必修linux运维系列课程
08.Java高级系统培训架构课程116课时
(送:hadoop系列教程,java设计模式与数据结构, Spring Cloud微服务, SpringBoot入门)
——————————————————————–

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lovoo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值