1.事件分发传递
2.scroller 原理
3.TouchEvent 事件
4.scrollTo()
开始时候带着的问题
1.手指放上触发子view的 touch事件,当手指一动到下一个view的时候触发父veiw。手指不抬起时候。
* 2.内容如何滚动移动子 item veiw的位置
* 3.如何缓存进行复用问题。
* 4.有时候会同时出来两个删除?
* 5.为什么会造成卡顿。?
* 6.需要计算点击的item 和 缓存上一个item 进行状态复原
7.item ui怎么写?
* 对滑动内容的管理
* 1.代码都写在SLiderView是否可行?
* 2.如果只用move 事件 ,计算差值---如何进行解决呢!
* 3.子类进行事件消耗和不消耗 区别
* 4.过滤 水平滑动和垂直滑动的方法
*/
看到这个图第一想法就是在手滑动的时候让item中的内容向左滑动,具体滑动距离就是 超出屏幕的部分宽度。
那么如何实现?
1.通过view的onlayou()
2.通过objectAnimator动画
3.scroller 的scrollTo( ) scrollBy().实现。
最简单最直接的方式当然是scroller,也是平时开发中接触较多的一个系统api。
当然选择使用 scroller很重要的一个原因是因为scroller是滑动的内容。而不是包裹的view滑动
当然先来了解一下scrollTo()scrollBy(),也是调用的scrollTo(),上图
引用blog地址: http://www.xuebuyuan.com/2013505.html
直接扫描书本上。有可能会和自己理解的不同。scrollTo(100,0),就是内容想右。(图三)而不是图上的内容向左边。(图二)
其实这个应该和android的x轴 y轴正方向理解不要混了。ScrollTo()是内容从0点 向左移动到100 点位置。
懂了这点。那个getscrollX() 和getscrollY() 就好理解。就是指。内容的滚动距(0,0)点距离
有了scrollto() 和 getscrollX(),这个侧滑基本上可以得完成了。
Scroller 是如何让view进行移动?
StartScroll()这个方法并没有使view进行移动。这是初始化一些参数,
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
mMode = SCROLL_MODE;
mFinished = false;
mDuration = duration;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mStartX = startX;
mStartY = startY;
mFinalX = startX + dx;
mFinalY = startY + dy;
mDeltaX = dx;
mDeltaY = dy;
mDurationReciprocal = 1.0f / (float) mDuration;
}
invalidate(); //触发重绘
然后在ondraw()中会去调用
@Override
public void computeScroll() {
super.computeScroll();
}
去判断是否结束滚动。那么只要重写该方法。基本上。View的重复滚动问题就完事了
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate(); //绘制–
}
}
对就是得上面的这个函数,是系统scroller 从开始位置滚动到终止位置。
读scrollto( ) 源码会发现里面有一个简单时间位移算法。根据当前位置和起始时间终止时间计算当前滚动到的位置。 然后不断进行view重绘。直到滚动到终止位置!
简单介绍一下实现,也是给予上面的滑动原理,进行健壮性的扩展。能符合日常的开发需求
1.自定义
class SilderListViewDemo extends ListView
SliderViewDemo extends LinearLayout
分别重写 sliderView 和 SliderViewDemo 类的,onTouch() 进行监听action_down,action_move ,action_up
这里需要将listview TouchEvent事件传递给 item中自定义SliderView的onTouch 进行操作。
直接贴出来代码和分析的注释部分:
ListView 的onTouch( );
@Override
public boolean onTouchEvent(MotionEvent event) {
//这里为什么要写在这里,不写在acton_down中,因为这里每次都调用,而action_down只有down时候触发。(算我没说)
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mX = x;
mY = y;
//根据 x,y 确定点击的那个item
currentPositon = this.pointToPosition((int) event.getX(), (int) event.getY());
//未关闭状态进行复原
if (mPosition != currentPositon) {
mPosition = currentPositon;
if (itemViewContent != null) {
//恢复上个侧滑的状态
itemViewContent.reset();
}
isScrolling = false;
}
break;
case MotionEvent.ACTION_UP:
if (itemViewContent != null) {
//手指抬起,去判断自定滑动到起点还是终点
itemViewContent.adjustScroller();
}
break;
case MotionEvent.ACTION_MOVE:
if (mPosition != -1) {
float detex = Math.abs(x - mX);
float deteY = Math.abs(y - mY);
if (deteY < 30 && detex > 20) {
isScrolling = true;
//这里本可以通过position拿到 点击的view,因为listview的item的缓存复用问题的,这里我们只需要考虑屏幕内显示的item
int firstPositon = getFirstVisiblePosition();
int screenPosition = currentPositon - firstPositon;
itemViewContent = (SliderViewDemo) getChildAt(screenPosition);
//将事件传递给sliderView去处理
itemViewContent.onTouchEvent(event);
}
}
break;
default:
break;
}
//注意当我们不主动消耗事件,交给系统去分发接下来的事件
return super.onTouchEvent(event);
}
接下来看sliderView ( LinerLayout ) 中的onTouch代码
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
//这里没有写 down 和 up监听。不是必须可写或者不写。主要逻辑不再这里处理
case MotionEvent.ACTION_MOVE:
float x = event.getX();
float y = event.getY();
//移动的差值
float deltaX = x - mLastX;
float delatY = y - mLastY;
mLastX = x;
mLastY = y;
if (Math.abs(deltaX) < Math.abs(delatY) * 2) {
//过滤 y轴时间,否则会导致无法滑动效果
break;
}
float newScrollX = getScrollX() - deltaX;
if (newScrollX < 0) {
newScrollX = 0;
} else if (newScrollX > mHolderWidth) { //滑动距离为规定的del删除的距离
newScrollX = mHolderWidth;
}
this.scrollTo((int) newScrollX, 0);
break;
default:
break;
}
return super.onTouchEvent(event); //将事件交给父类。这点很重要。如果子类消耗。父类中onTouch事件就不触发
}
还有写异常判断。手指抬起时候。进行判断。是左滑动还是右滑动。下面是demo链接地址: