一、常见的滑动冲突

场景1:外部滑动和内部滑动不一致

场景2:外部滑动和内部滑动一致

场景3:上面两种情况的嵌套

二、滑动冲突的处理方法

场景一:根据水平滑动还是竖直滑动判断到底由谁来拦截事件。

场景二:从业务上找突破点,比如内部为ListView,点在ListView内部的时候让ListView滑动,如果在ListView外则让父View滑动。

场景三:同样还是从业务上寻找突破点。

三、各种拦截的方法(暂时只介绍外部拦截法,内部拦截发P158)

原理:点击事件都经过父控件的拦截处理,如果父控件需要则拦截事件,不需要则不拦截。

四、示例

场景一:仿ViewPager,有三个页面,每个页面有一个ListView

使用:①、创建ScrollerLinearLayout继承LinearLayout 并在activity_main.xml中使用②、在MainActivity中动态加载三个ListView ③、重写ScrollerLinearLayout的onIntereptTouchEvent()方法

重写的逻辑:当DOWN的时候,滑动动画还在进行的时候,拦截、当MOVE的时候,判断坐标是横移的距离还是竖移距离大,如果横移大拦截,竖移大不拦截。

④、重写onTouchEvent():如果DOWN,则不处理。MOVE,根据滑动的方向和距离,根据scrollTo/scrollBy进行滑动。UP,则获取滑动的速度,根据速度判断如果速度快的话,则滑动到下一页或前一页。如果慢的话,判断如果当前位移滑动过半页了则滑动到下一页或前一页。

⑤、自动滑动的方法 详见View的滑动

步骤一:初始化相关信息

<!--已创建ScrollerLinearLayout-->
<com.maikefengchao.scrollercomplict.ScrollerLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:id="@+id/main_linear_scroller"
tools:context="com.maikefengchao.scrollercomplict.MainActivity"> </com.maikefengchao.scrollercomplict.ScrollerLinearLayout>

activity_main

<!--需要动态载入的页面的layout-->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/content_tv_title"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="@android:color/holo_blue_dark"/>
<ListView
android:id="@+id/content_lv_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"></ListView>
</LinearLayout>

content_layout

步骤二:动态加载content_layout布局,内含ListView

public class MainActivity extends AppCompatActivity {

    private ScrollerLinearLayout mScrollearLinear;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
} private void initView(){
//获取Horizon对象
mScrollearLinear = (ScrollerLinearLayout)findViewById(R.id.main_linear_scroller);
//获取当前屏幕的宽高,为将content_layout的宽高与屏幕一直,如果是match_parent,三个布局的间距无限长。
DisplayMetrics metric = new DisplayMetrics();
getWindow().getWindowManager().getDefaultDisplay().getMetrics(metric);
int screenWidth = metric.widthPixels;
int screenHeight = metric.heightPixels; //将content_layout装入horizon中 :动态加载layout
for(int i=0; i<3; ++i){
//加载布局获取ViewGroup
ViewGroup layout = (ViewGroup) getLayoutInflater().inflate(R.layout.content_layout,mScrollearLinear,false);
//设置layout的宽高
layout.getLayoutParams().width = screenWidth;
layout.getLayoutParams().height = screenHeight;
//动态配置View的子View
TextView textView = (TextView)layout.findViewById(R.id.content_tv_title);
textView.setText("Page:"+i);
//设置View的背景颜色
layout.setBackgroundColor(Color.rgb(255/(i+1),255/(i+1),0));
//创建ListView
createList(layout);
//真正添加进View中
mScrollearLinear.addView(layout);
}
}
//普通ListView的创建不解释
private void createList(ViewGroup viewGroup){
ListView listView = (ListView) viewGroup.findViewById(R.id.content_lv_list);
ArrayList<String> arrayList = new ArrayList<>();
for(int i=0; i<30; ++i){
arrayList.add("name#"+i);
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,R.layout.listview_content_item,R.id.item_tv_content,arrayList);
listView.setAdapter(adapter);
}
}

MainActivity

步骤三:重写ScrollerLinearLayout的onIntereptTouchEvent()拦截事件

private static final String TAG = "ScrollerLinearLayout";
//滑动类,用来滑动切换界面的
private Scroller mScroller;
private Context mContext;
//速度类,用来判断手指滑动的速度
private VelocityTracker mVelocityTracker;
//onInterceptTouchEvent中,判断手指滑动的距离,选择是否拦截
private int mOldInterceptX = 0;
private int mOldInterceptY = 0; //onTouchEvent中,新旧点判断移动距离,进行滑动
private int mOldX = 0;
private int mOldY = 0;
//当前子类的序号
private int mChildIndex = 0;
//有多少个子类
private int mChildSize;
//当前子类的宽度
private int mChildWidth; public ScrollerLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
} public ScrollerLinearLayout(Context context) {
super(context);
initView(context);
} public ScrollerLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
} //初始化对象
private void initView(Context context){
mContext = context;
mScroller = new Scroller(context);
mVelocityTracker = VelocityTracker.obtain();
}
//获取子View的宽/高/数量信息,有四种方法获取View的宽、高、数量①
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
mChildWidth = getChildAt(0).getWidth();
mChildSize = getChildCount();
} @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean intercepted = false;
int currentX = (int)ev.getX();
int currentY = (int)ev.getY();
switch (ev.getAction()){
/*当子View正在滑动的时候拦截*/
case MotionEvent.ACTION_DOWN:
if (!mScroller.isFinished()){
//滑动优化,可以不添加
mScroller.abortAnimation();
intercepted = true;
}
break;
/*获取当前移动举例信息,判断用户是竖划还是横划*/
case MotionEvent.ACTION_MOVE:
int deltaX = mOldInterceptX - currentX;
int deltaY = mOldInterceptY - currentY;
if (Math.abs(deltaX) > Math.abs(deltaY)){
intercepted = true;
}
else {
intercepted = false;
}
break;
/*不拦截*/
case MotionEvent.ACTION_UP:
intercepted = false;
break;
}
mOldInterceptX = currentX;
mOldInterceptY = currentY;
return intercepted;
}

ScrollerLinearLayout

步骤四:重写onTouchEvent()方法,并配置自动滑动的类

 //....接上    

@Override
public boolean onTouchEvent(MotionEvent event) {
/*速度类需要获取事件对象,才能使用*/
mVelocityTracker.addMovement(event);
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
break;
/*获取滑动的距离,并用方法滑动*/
case MotionEvent.ACTION_MOVE:
int destX = (int)(mOldX - event.getX());
int destY = 0;
/*注:为正向左边移动,负向右边移动*/
scrollBy(destX, destY);
break;
/*自动滑动,当速度大于50时候或当滑动距离大于一半的时候自动滑动到下一View或者前一View*/
case MotionEvent.ACTION_UP:
int scrollX = getScrollX();
//VelocityTracker的使用见其他文章
mVelocityTracker.computeCurrentVelocity(1000);
float xVelocity = mVelocityTracker.getXVelocity();
if (Math.abs(xVelocity) >= 50 ){
/*从左向右滑动为正,从右向左为负*/
mChildIndex = xVelocity>0?mChildIndex-1:mChildIndex+1;
}
else {
//滑动超过屏幕的1/2的时候
mChildIndex = (scrollX + (mChildWidth*1)/2)/mChildWidth;
}
//限制只能滑动有的页面
mChildIndex = Math.max(0,Math.min(mChildIndex,mChildSize-1));
int dx = mChildWidth*mChildIndex - scrollX;
//初始化滑动类的滑动信息,详见View的滑动这一章
smoothScrollBy(dx);
mVelocityTracker.clear();
break;
}
mOldX = (int)event.getX();
mOldY = (int)event.getY();
return true;
} private void smoothScrollBy(int dx){
mScroller.startScroll(getScrollX(),0,dx,0,1000);
invalidate();
} @Override
public void computeScroll() {
super.computeScroll();
if (mScroller.computeScrollOffset()){
scrollTo(mScroller.getCurrX(), 0);
postInvalidate();
}
}

ScrollerLinearLayout

解释①:因为这是第四章的内容,到第四章会详细解释

为什么在构造方法中,无法调用getChildAt()和getChildCount()方法。因为在构造的过程中并没有调用measure()方法,无法获取子View的任何信息。

所以同样在Activity中也一样,如果View没有完全创建完成,则Activity在任何位置都获取不到view的宽/高。

(暂时使用两种P190页详解)所以最适合调用的四种方法(第一种方法可以在View中,其他方法适用于在Activity中获取需要的View的宽高):

①、onWindowFocusChanged:该方法在View初始化完成之后才会被调用,当Activity的窗口得到焦点和失去焦点的时候都会调用一次。

   @Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if (hasFocus()){
int width = getMeasuredWidth();
int height = getMeasuredHeight();
}
}

SimpleView

②、view.post(runnable):将runnable投递到消息队列的队尾。

View的滑动冲突的更多相关文章

  1. 一个Demo带你彻底掌握View的滑动冲突

    本文已授权微信公众号:鸿洋(hongyangAndroid)在微信公众号平台原创首发. 近期在又一次学习Android自己定义View这一块的内容.遇到了平时开发中常常碰到的一个棘手问题:View的滑 ...

  2. view的滑动冲突解决方案

    一.常见的滑动冲突场景 1.外部滑动方向和内部滑动方向不一致 2.外部滑动方向和内部滑动方向一致 3.上面两种情况的嵌套 二.滑动冲突处理的原则 场景1的处理原则是:当用户左右滑动时,需要让外部的vi ...

  3. 自定义控件(视图)2期笔记13:View的滑动冲突之 内部拦截法

    1. 内部拦截法: 父容器不拦截事件,所有的事件全部都传递给子元素,如果子元素需要此事件就直接消耗掉,否则就交给父容器进行处理. 这种方法和Android中的事件分发机制不一样,需要配合request ...

  4. 自定义控件(视图)2期笔记12:View的滑动冲突之 外部拦截法

    1. 外部拦截法: 点击事件通过父容器拦截处理,如果父容器需要就拦截,不需要就不拦截. 这种方法比较符合事件分发机制.外部拦截法需要重写父容器的onInterceptTouchEvent方法,在内部做 ...

  5. View的滑动冲突和解决方案

    1.滑动冲突原因: 当有内外两层View同时可以滑动的时候,这个时候就会产生滑动冲突. 2.常见的冲突场景: 场景1: 场景2: 场景3: 4.解决方法种类: (1)外部拦截法: 针对场景1,我们可以 ...

  6. 自定义控件(视图)2期笔记11:View的滑动冲突之 概述

    1. 引入: 滑动冲突可以说是日常开发中比较常见的一类问题,也是比较让人头疼的一类问题,尤其是在使用第三方框架的时候,两个原本完美的控件,组合在一起之后,忽然发现整个世界都不好了. 那到底是为什么会产 ...

  7. 滑动冲突的补充——Event的流程走向

    一.之前分析的滑动冲突,并没有讲述event事件是如何分发到不同的控件 View的滑动冲突 现在分析一下滑动冲突event事件的流向 假设:  我们的一个事件为  点下——>左滑动一次——> ...

  8. Android View的滑动

    Android View的滑动 文章目录 Android View的滑动 一.实现移动 1.1 layout() 1.2 设置位置偏移量 1.3 改变布局参数 1.4 动画 1.5 ScrollTo以 ...

  9. (转载)Android滑动冲突的完美解决

    Android滑动冲突的完美解决 作者:softwindy_brother 字体:[增加 减小] 类型:转载 时间:2017-01-24我要评论 这篇文章主要为大家详细介绍了Android滑动冲突的完 ...

随机推荐

  1. C语言undefined behaviour未定义行为

    C语言中的未定义行为(Undefined Behavior)是指C语言标准未做规定的行为.同时,标准也从没要求编译器判断未定义行为,所以这些行为有编译器自行处理,在不同的编译器可能会产生不同的结果,又 ...

  2. 一种获取spring环境上下文方法:SpringContextUtil

    获得spring里注册Bean的有好几种方法,这里介绍一种比较简单的方法: import org.springframework.beans.BeansException; import org.sp ...

  3. IE8下的项目在IE11下某些功能无法实现的问题

    在IE8和IE11 下获取数据的时间进行判断有些不同,也要根据浏览器的版本判断分别实现 $(".btndelete").children().children().click(fu ...

  4. php非递归无限级分类.

    项目需要.递归无限级分类效率实在太低.理了半天思路写的. 分类越多效率越高. /** * 单次循环返回无限极分类嵌套 * @param array $data 操作的数组 * @param strin ...

  5. 【Lucene4.8教程之一】使用Lucene4.8进行索引及搜索的基本操作

    在Lucene对文本进行处理的过程中,可以大致分为三大部分: 1.索引文件:提取文档内容并分析,生成索引 2.搜索内容:搜索索引内容,根据搜索关键字得出搜索结果 3.分析内容:对搜索词汇进行分析,生成 ...

  6. oracle表空间使用率统计查询

    今天发现有一张采样表从1月5号开始不记录数据了,所以想查看一下表空间使用率,在网上零零散散找了很多资料,现在记录如下,也不知道哪一个最准确.还有一个就是网上拷贝的sql代码格式太乱了,不好看,找到一个 ...

  7. Android 样式

    先在Value文件夹下建一个Common.xml的文件. <style name="CodeFont" parent="@android:style/TextApp ...

  8. PHP中的错误处理

    程序只要在运行,就免不了会出现错误!或早或晚,只是时间问题罢了. 错误很常见,比如Notice,Warning等等.此时一般使用set_error_handler来处理: <?php set_e ...

  9. UVA11988 Broken KeyBoard

    链表的思想很简单,要做到活用也不难.一般我是这样做得,从实际问题出发,先高度的概括符不符合链表的特点.能不能用链表简单解决.接着,就是编码.链表编码要理清细节性思路,最好是简单的画下图,正如改题的链表 ...

  10. 使用Flask 生成中文图片验证码

    因最近要用到验证码,上网搜了下,发现什么验证码感觉都能被攻破,连最近疯传的变态的12306的验证码居然有人一天就攻破了,所以,综合考虑,还是使用汉字: web框架是Flask,然后使用python的I ...