ListView使用技巧
- 优化技巧
拓展
滚动到顶部,底部时有个弹性距离可以继续滑动,松开后回弹
1
2
3
4
5
6
7
8
9private void init(){
mMaxOverDistance= (int) (getResources().getDisplayMetrics().density*mMaxOverDistance);
}
@Override
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
Log.e("overscroll","by "+mMaxOverDistance);
return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, mMaxOverDistance, isTouchEvent);
}
聊天ListView
- getItemViewType(position)-> mData.get(position).getType()
- getViewTypeCount()->2
- getView()区分type,实例化不同布局添加内容
listview选中未选中状态: 在getView()中判断,点击选中的item的position和当前position是否相同,添加不同的布局
Android Scroll
滑动效果是触摸事件不断改变View的坐标,移动位置,来达到滑动效果
- 触摸事件类型
1 | //单点触摸按下 |
实项滑动的七种方法
layout()
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相对于视图坐标系的获取坐标getX,getY,而lastX,lastY不需要重新设置坐标,因为相对于视图坐标,点击屏幕获取到的坐标会重新设置
对于Android屏幕坐标系,getRawX,getRawY,lastRawX,lastRawY需要重新设置,获取准确的偏移量,第一次坐标位置getRawX,getRawY在(10,10),在移动到(20,20),偏移量为10,此时不重新设置,下个点是(50,50),偏移量是50-10=40,而实际正确的偏移量为50-20=30
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
int rx = (int) event.getRawX();
int ry = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
lastrX = rx;
lastrY = ry;
break;
case MotionEvent.ACTION_MOVE:
int dx = x - lastX;
int dy = y - lastY;
int rdx = rx - lastrX;
int rdy = ry - lastrY;
Log.e("drag", "x=" + x + " y=" + y
+ " lastX=" + lastX + " lastY=" + lastY);
Log.e("drag", "rx=" + rx + " ry=" + ry
+ " lastrX=" + lastrX + " lastrY=" + lastrY);
Log.e("drag", "dx=" + dx + " dy=" + dy
+ " rdx=" + rdx + " rdy=" + rdy);
layout(getLeft() + dx, getTop() + dy,
getRight() + dx, getBottom() + dy);
// lastrX = x;
// lastrY = y;
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}offsetLeftAndrRight(),offsetTopAndBottom()
1
2offsetLeftAndRight(dx);
offsetTopAndBottom(dy);LayoutParams(),ViewGroup.MarginLayoutParams
1
2
3
4
5
6
7
8
9FrameLayout.LayoutParams layoutParams= (FrameLayout.LayoutParams) getLayoutParams();
layoutParams.leftMargin=getLeft()+dx;
layoutParams.topMargin=getTop()+dy;
setLayoutParams(layoutParams);
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
layoutParams.leftMargin = getLeft() + dx;
layoutParams.topMargin = getTop() + dy;
setLayoutParams(layoutParams);ScrollTo(x,y)/ScrollBy(dx,dy)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23ViewGroup 移动的是子View
View移动的是内容
//移动的是屏幕下方画布,会造成内容向相反方向移动
//scrollBy(dx,dy);
//所以移动父视图,并且值为负,相反方向scrollby才有正确的效果
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
if (!isScroll) {
lastrX = rx;
lastrY = ry;
}
break;
case MotionEvent.ACTION_MOVE:
int dx = x - lastX;
int dy = y - lastY;
//移动的是屏幕下方画布,会造成内容向相反方向移动
// scrollBy(dx,dy);
//((View) getParent()).scrollBy(-dx, -dy);
((View) getParent()).scrollTo(-(int) event.getRawX() + lastrX, -(int) event.getRawY() + lastrY);
isScroll = true;
break;
Scroller 实现平移滑动
初始化Scroller
1
mScroller=new Scroller(context);
重写computeScroll()模拟滑动
1
2
3
4
5
6
7
8
9
10
11@Override
public void computeScroll() {
super.computeScroll();
//判断Scroll是否执行完毕,true 没有执行完
if(mScroller.computeScrollOffset()){
((View)getParent()).scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
//只能通过invalidate()—>draw()->computeScroll()间接调用computeScroll(),
//结束后computeScrollOffset()返回false,中断循环
postInvalidate();
}
}startScroll 开始模拟滑动
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@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
int rx = (int) event.getRawX();
int ry = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
lastRx = rx;
lastRy = ry;
break;
case MotionEvent.ACTION_MOVE:
((View) getParent()).scrollTo(-rx + lastRx, -ry + lastRy);
break;
case MotionEvent.ACTION_UP:
View parent = (View) getParent();
//模拟滑动,起始坐标和偏移量,滑动偏移为滑动距离的负数,相反方向滑动
mScroller.startScroll(parent.getScrollX(), parent.getScrollY(),
-parent.getScrollX(), -parent.getScrollY());
//通知重绘
invalidate();
break;
}
return true;
}
ViewDragHelper实项Drawlayout菜单侧滑 youtubelayout
回调
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
56private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
/**重写tryCaptureView,何时开始检测触摸事件,
* 当前触摸的是MainView时开始检测*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return mMainView == child;
}
/**水平垂直方向上的滑动,默认返回0,不滑动*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
// return super.clampViewPositionHorizontal(child, left, dx);
return left;
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
// return super.clampViewPositionVertical(child, top, dy);
return top;
}
/**拖动结束后调用,自动滑动打开或关闭菜单*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
if (mMainView.getTop() > mHeight / 2) {
mViewDragHelper.smoothSlideViewTo(mMainView, 0, (int) (mHeight * 1.2f));
} else {
if (mMainView.getLeft() < mWidth / 2) {
//关闭菜单
mViewDragHelper.smoothSlideViewTo(mMainView, 0, 0);
} else {
mViewDragHelper.smoothSlideViewTo(mMainView, (int) (mWidth * 1.2f), 0);
}
}
ViewCompat.postInvalidateOnAnimation(ViewDragHelperView.this);
}
/**更改scale进行缩放*/
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
}
/**状态改变*/
@Override
public void onViewDragStateChanged(int state) {
super.onViewDragStateChanged(state);
}
/**触摸后回调*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
}
};获取宽度
1
2
3
4
5
6@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = mMenuView.getMeasuredWidth();
mHeight = mMenuView.getMeasuredHeight();
}获取MenuView,MainView
1
2
3
4
5
6@Override
protected void onFinishInflate() {
super.onFinishInflate();
mMenuView = getChildAt(0);
mMainView = getChildAt(1);
}
触摸事件拦截,并传递给VieDragHelper
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16/**
* 触摸事件传递给ViewDragHelper,必须写
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
mViewDragHelper.processTouchEvent(event);
return true;
}
/**
* 重写事件拦截方法,把事件传递给ViewDragHelper
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mViewDragHelper.shouldInterceptTouchEvent(ev);
}重写computeScroll()
1
2
3
4
5
6
7
8
9
10/**
* 平滑移动
*/
@Override
public void computeScroll() {
super.computeScroll();
if (mViewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
}
}