本文主要是介绍ViewDragHelper实战 自己打造Drawerlayout,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow
也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!
转载请标明出处:
http://blog.csdn.net/lmj623565791/article/details/47396187;
本文出自:【张鸿洋的博客】
一、概述
中间拖了蛮长时间了,在上一篇我们介绍了ViewDragHelper
,详情:ViewDragHelper完全解析,当然了,上一篇都是小示例的形式去演示代码功能,并不能给人一种实用的感觉。那么,本篇博客就准备实用ViewDragHelper
来实现一个DrawerLayout的效果,当然了,大家也可以选择直接去看Drawerlayout
的源码。相信侧滑大家肯定不陌生,网络上流传无数个版本,其实利用ViewDragHelper
就能方便的写出比较不错的侧滑代码~
那么首先上个效果图:
ok,其实和DrawerLayout效果类似,当然不是完全的一致~~本篇的主要目的也是演示VDH的实战用法,大家在选择侧滑的时候还是建议使用DrawerLayout
.
二、实战
(一)布局文件
首先看一下布局文件:
<com.zhy.learn.view.LeftDrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"android:id="@+id/id_drawerlayout" android:layout_height="match_parent" > <!--content--> <RelativeLayout android:clickable="true" android:layout_width="match_parent" android:background="#44ff0000" android:layout_height="match_parent"> <TextView android:id="@+id/id_content_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="hello world" android:textSize="40sp" android:layout_centerInParent="true"/> </RelativeLayout> <!--menu--> <FrameLayout android:id="@+id/id_container_menu" android:layout_width="match_parent" android:layout_height="match_parent" > </FrameLayout></com.zhy.learn.view.LeftDrawerLayout>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
ok,可以看到我们的LeftDrawerLayout里面一个是content,一个是menu~为了方便,我们就默认child0为content,child1为menu。
(二)LeftDrawerLayout
package com.zhy.learn.view;import android.content.Context;import android.support.v4.widget.ViewDragHelper;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import com.zhy.util.common.L;/** * Created by zhy on 15/5/29. */public class LeftDrawerLayout extends ViewGroup{ private static final int MIN_DRAWER_MARGIN = 64; // dp /** * Minimum velocity that will be detected as a fling */ private static final int MIN_FLING_VELOCITY = 400; // dips per second /** * drawer离父容器右边的最小外边距 */ private int mMinDrawerMargin; private View mLeftMenuView; private View mContentView; private ViewDragHelper mHelper; /** * drawer显示出来的占自身的百分比 */ private float mLeftMenuOnScrren; public LeftDrawerLayout(Context context, AttributeSet attrs) { super(context, attrs); //setup drawer's minMargin final float density = getResources().getDisplayMetrics().density; final float minVel = MIN_FLING_VELOCITY * density; mMinDrawerMargin = (int) (MIN_DRAWER_MARGIN * density + 0.5f); mHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() { @Override public int clampViewPositionHorizontal(View child, int left, int dx) { int newLeft = Math.max(-child.getWidth(), Math.min(left, 0)); return newLeft; } @Override public boolean tryCaptureView(View child, int pointerId) { L.e("tryCaptureView"); return child == mLeftMenuView; } @Override public void onEdgeDragStarted(int edgeFlags, int pointerId) { L.e("onEdgeDragStarted"); mHelper.captureChildView(mLeftMenuView, pointerId); } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { L.e("onViewReleased"); final int childWidth = releasedChild.getWidth(); float offset = (childWidth + releasedChild.getLeft()) * 1.0f / childWidth; mHelper.settleCapturedViewAt(xvel > 0 || xvel == 0 && offset > 0.5f ? 0 : -childWidth, releasedChild.getTop()); invalidate(); } @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { final int childWidth = changedView.getWidth(); float offset = (float) (childWidth + left) / childWidth; mLeftMenuOnScrren = offset; //offset can callback here changedView.setVisibility(offset == 0 ? View.INVISIBLE : View.VISIBLE); invalidate(); } @Override public int getViewHorizontalDragRange(View child) { return mLeftMenuView == child ? child.getWidth() : 0; } }); //设置edge_left track mHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT); //设置minVelocity mHelper.setMinVelocity(minVel); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(widthSize, heightSize); View leftMenuView = getChildAt(1); MarginLayoutParams lp = (MarginLayoutParams) leftMenuView.getLayoutParams(); final int drawerWidthSpec = getChildMeasureSpec(widthMeasureSpec, mMinDrawerMargin + lp.leftMargin + lp.rightMargin, lp.width); final int drawerHeightSpec = getChildMeasureSpec(heightMeasureSpec, lp.topMargin + lp.bottomMargin, lp.height); leftMenuView.measure(drawerWidthSpec, drawerHeightSpec); View contentView = getChildAt(0); lp = (MarginLayoutParams) contentView.getLayoutParams(); final int contentWidthSpec = MeasureSpec.makeMeasureSpec( widthSize - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY); final int contentHeightSpec = MeasureSpec.makeMeasureSpec( heightSize - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY); contentView.measure(contentWidthSpec, contentHeightSpec); mLeftMenuView = leftMenuView; mContentView = contentView; } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { View menuView = mLeftMenuView; View contentView = mContentView; MarginLayoutParams lp = (MarginLayoutParams) contentView.getLayoutParams(); contentView.layout(lp.leftMargin, lp.topMargin, lp.leftMargin + contentView.getMeasuredWidth(), lp.topMargin + contentView.getMeasuredHeight()); lp = (MarginLayoutParams) menuView.getLayoutParams(); final int menuWidth = menuView.getMeasuredWidth(); int childLeft = -menuWidth + (int) (menuWidth * mLeftMenuOnScrren); menuView.layout(childLeft, lp.topMargin, childLeft + menuWidth, lp.topMargin + menuView.getMeasuredHeight()); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { boolean shouldInterceptTouchEvent = mHelper.shouldInterceptTouchEvent(ev); return shouldInterceptTouchEvent; } @Override public boolean onTouchEvent(MotionEvent event) { mHelper.processTouchEvent(event); return true; } @Override public void computeScroll() { if (mHelper.continueSettling(true)) { invalidate(); } } public void closeDrawer() { View menuView = mLeftMenuView; mLeftMenuOnScrren = 0.f; mHelper.smoothSlideViewTo(menuView, -menuView.getWidth(), menuView.getTop()); } public void openDrawer() { View menuView = mLeftMenuView; mLeftMenuOnScrren = 1.0f; mHelper.smoothSlideViewTo(menuView, 0, menuView.getTop()); } @Override protected LayoutParams generateDefaultLayoutParams() { return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); } protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { return new MarginLayoutParams(p); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
哈,很少的代码就完成了我们的侧滑的编写,目测如果使用横向的LinearLayout代码更短。构造方法中,主要就是初始化我们的mDragHelper了,接下来onMeasure和onLayout都比较简单,onLayout也只是去将我们的menu设置到屏幕的左侧以至于不可见。onInterceptTouchEvent
和onTouchEvent
中都只需要简单的调用mDragHelper的方法。那么核心代码都在我们的ViewDragHelper.Callback的实例中了。注意一点:我们LeftDrawerLayout默认的LayoutParams为MarginLayoutParams,注意复写相关方法。
接下来就把注意力放到我们的Callback中,我尽可能的按照调用的逻辑来解释各个方法:
onEdgeDragStarted 如果你仔细的看过上篇,那么一定知道这个方法的回调位置;因为我们的View不可见,所以我们没有办法直接通过触摸到它来把menu设置为captureView,所以我们只能设置边界检测,当MOVE时回调onEdgeDragStarted时,我们直接通过captureChildView手动捕获。
tryCaptureView 那么既然我们手动捕获了,为什么还需要这个方法呢?主要是因为当Drawer拉出的时候,我们通过拖拽Drawer也能进行移动菜单。
clampViewPositionHorizontal 主要是移动的时候去控制控制范围,可以看到我们的
int newLeft = Math.max(-child.getWidth(), Math.min(left, 0));
一定>=-child.getWidth() && <=0 。getViewHorizontalDragRange 为什么要复写,我们上篇已经描述过,返回captureView的移动范围。
onViewReleased 则是释放的时候触发的,我们计算当前显示的百分比,以及加速度来决定是否显示drawer,从代码可以看出,当
xvel > 0
||xvel == 0 && offset > 0.5f
显示我们的菜单,其他情况隐藏。这里注意一点xvel的值只有大于我们设置的minVelocity才会出现大于0,如果小于我们设置的值则一直是0。onViewPositionChanged 整个pos变化的过程中,我们计算offset保存,这里可以使用接口将offset回调出去,方便做动画。
ok,我们重写的所有方法描述完成了~那么博文主要内容也就结束了~哈~是不是 so easy ~!
呃,忘了MainActivity和Fragment的代码了~~按顺序贴
(三)LeftDrawerLayoutActivity
package com.imooc.testandroid;import android.os.Bundle;import android.support.v4.app.FragmentManager;import android.support.v7.app.ActionBarActivity;import android.view.Menu;import android.view.MenuItem;import android.widget.TextView;import com.zhy.learn.view.LeftDrawerLayout;public class LeftDrawerLayoutActivity extends ActionBarActivity{ private LeftMenuFragment mMenuFragment; private LeftDrawerLayout mLeftDrawerLayout ; private TextView mContentTv ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_left_drawer_layout); mLeftDrawerLayout = (LeftDrawerLayout) findViewById(R.id.id_drawerlayout); mContentTv = (TextView) findViewById(R.id.id_content_tv); FragmentManager fm = getSupportFragmentManager(); mMenuFragment = (LeftMenuFragment) fm.findFragmentById(R.id.id_container_menu); if (mMenuFragment == null) { fm.beginTransaction().add(R.id.id_container_menu, mMenuFragment = new LeftMenuFragment()).commit(); } mMenuFragment.setOnMenuItemSelectedListener(new LeftMenuFragment.OnMenuItemSelectedListener() { @Override public void menuItemSelected(String title) { mLeftDrawerLayout.closeDrawer(); mContentTv.setText(title); } }); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
可以看到drawer使用了一个Fragment ~~
(四) LeftMenuFragment
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;/** * Created by zhy on 15/4/26. */public class LeftMenuFragment extends ListFragment { private static final int SIZE_MENU_ITEM = 3; private MenuItem[] mItems = new MenuItem[SIZE_MENU_ITEM]; private LeftMenuAdapter mAdapter; private LayoutInflater mInflater; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mInflater = LayoutInflater.from(getActivity()); MenuItem menuItem = null; for (int i = 0; i < SIZE_MENU_ITEM; i++) { menuItem = new MenuItem(getResources().getStringArray(R.array.array_left_menu)[i], false, R.drawable.music_36px, R.drawable.music_36px_light); mItems[i] = menuItem; } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return super.onCreateView(inflater, container, savedInstanceState); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); view.setBackgroundColor(0xffffffff); setListAdapter(mAdapter = new LeftMenuAdapter(getActivity(), mItems)); } @Override public void onListItemClick(ListView l, View v, int position, long id) { super.onListItemClick(l, v, position, id); if (mMenuItemSelectedListener != null) { mMenuItemSelectedListener.menuItemSelected(((MenuItem) getListAdapter().getItem(position)).text); } mAdapter.setSelected(position); } //选择回调的接口 public interface OnMenuItemSelectedListener { void menuItemSelected(String title); } private OnMenuItemSelectedListener mMenuItemSelectedListener; public void setOnMenuItemSelectedListener(OnMenuItemSelectedListener menuItemSelectedListener) { this.mMenuItemSelectedListener = menuItemSelectedListener; }}public class MenuItem{ public MenuItem(String text, boolean isSelected, int icon, int iconSelected) { this.text = text; this.isSelected = isSelected; this.icon = icon; this.iconSelected = iconSelected; } boolean isSelected; String text; int icon; int iconSelected;}/** * Created by zhy on 15/4/26. */public class LeftMenuAdapter extends ArrayAdapter<MenuItem> { private LayoutInflater mInflater; private int mSelected; public LeftMenuAdapter(Context context, MenuItem[] objects) { super(context, -1, objects); mInflater = LayoutInflater.from(context); } @Override public View getView(int position, View convertView, ViewGroup parent) { 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(getItem(position).text); iv.setImageResource(getItem(position).icon); convertView.setBackgroundColor(Color.TRANSPARENT); if (position == mSelected) { iv.setImageResource(getItem(position).iconSelected); convertView.setBackgroundColor(getContext().getResources().getColor(R.color.state_menu_item_selected)); } return convertView; } public void setSelected(int position) { this.mSelected = position; notifyDataSetChanged(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
贴了一大串,主要就是Fragment的代码,内部有个ListView,所以还有个Adapter,这个Fragment在之前的博文中出现过,搬过来而已。item的布局文件就是一个TextView和ImageView~~不贴了~~大家自己下载源码~
源码点击下载(导入方式注意看下ReadMe)
ok,到此结束~~hava a nice day ~~
欢迎关注我的微博:
http://weibo.com/u/3165018720
群号:463081660,欢迎入群
微信公众号:hongyangAndroid
(欢迎关注,第一时间推送博文信息)
给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow
这篇关于ViewDragHelper实战 自己打造Drawerlayout的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!