关于fragment内的监听事件
2015-09-16 11:13
435 查看
使用fragment+radiobutton实现导航标签页,遇到一个问题,fragment没有提供监听touch事件的方法,所以无法实现左右滑动的功能。在网上查询了好久,终于找到了解决方法。
方法一:
是在FragmentActivity中提供一个ontouch接口,然后在fragment中实现接口。具体代码参考:Android
Fragment中监听事件http://blog.csdn.net/jdsjlzx/article/details/20695279。
修改注册方法registerMyOnTouchListener写在fragment的生命周期onResume中,注销方法 unregisterMyOnTouchListener写在onPause中。
但是这种方法也存在一些问题。
当代码结构如上图所示时,在第二层的fragment实现左右滑动切换第三层的fragment页面,当点击home键离开程序执行onPause方法,再回到程序时,第二层的三个fragment都会执行onResume方法。导致三个fragment都启动了监听事件,滑动第二层的fragment1时,fragment2和fragment3会一起滑动。
点击home键离开程序的生命周期:
返回程序的生命周期:
同时注册了三个监听事件,导致滑动一个fragment时,另外两个fragment也执行了滑动操作。
解决方法:
使用数组存储监听事件。
fragment内注册和注销代码:
方法二:
这种方法虽然实现了左右滑动,并且区别了fragment的监听事件。
但还是存在一些问题:
比如在包含listview时,滑动距离过小会导致左右滑动事件和点击事件一起触发,距离过大又会影响用户体验。
原因是左右滑动没有消费掉当前点击事件,而是继续传递给子控件,具体原因可能是onTouchEvent()用于处理事件,返回值决定当前控件是否消费(consume)了这个事件,也就是说在当前控件在处理完Touch事件后,是否还允许Touch事件继续向上(父控件)传递,一但返回True,则父控件不用操心自己来处理Touch事件。而左右滑动应该是先判断父控件是否滑动,不滑动则向下(子控件)传递touch事件。这时应该使用onInterceptTouchEvent()来处理。参考文章:Android-onInterceptTouchEvent()和onTouchEvent()总结/article/8007182.html。
但是onInterceptTouchEvent()是ViewGroup的一个方法,只有包含子view的控件有这个方法,如Linearlayout,没有子view的控件没有这个方法,如TextView。
那么在fragment中没有onInterceptTouchEvent(),于是我自定义了一个FlingLinearLayout继承自Linearlayout。重写其中的onInterceptTouchEvent()方法,并自定义左右滑动方法Fling。具体FlingLinearLayout类的代码如下:
应用中实现的代码:
xml布局:
最后问题完美解决了。而且不需要使用最上面说的使用接口获取activity的touch监听。只需要在xml文件中把RadioGroup放在FlingLinearLayout布局里面就可以了。具体要实现什么功能可以在FlingLinearLayout中自己写。
文章中也许有疏漏的地方,欢迎大家指出我的问题,或者大家有什么建议都可以和我交流,希望能在交流中共同进步。O(∩_∩)O~
方法一:
是在FragmentActivity中提供一个ontouch接口,然后在fragment中实现接口。具体代码参考:Android
Fragment中监听事件http://blog.csdn.net/jdsjlzx/article/details/20695279。
修改注册方法registerMyOnTouchListener写在fragment的生命周期onResume中,注销方法 unregisterMyOnTouchListener写在onPause中。
但是这种方法也存在一些问题。
当代码结构如上图所示时,在第二层的fragment实现左右滑动切换第三层的fragment页面,当点击home键离开程序执行onPause方法,再回到程序时,第二层的三个fragment都会执行onResume方法。导致三个fragment都启动了监听事件,滑动第二层的fragment1时,fragment2和fragment3会一起滑动。
点击home键离开程序的生命周期:
返回程序的生命周期:
同时注册了三个监听事件,导致滑动一个fragment时,另外两个fragment也执行了滑动操作。
解决方法:
使用数组存储监听事件。
<span style="font-size:14px;">/** * 以下的几个方法用来,让fragment能够监听touch事件 */ <span style="white-space: pre;"> </span>private MyOntouchListener[] mol = new MyOntouchListener[3]; <span style="white-space: pre;"> </span>@Override <span style="white-space: pre;"> </span>public boolean onTouchEvent(MotionEvent event) { <span style="white-space: pre;"> </span>// TODO Auto-generated method stub <span style="white-space: pre;"> </span>//获取RadioGroup当前Tab的值-1得到对应数组里的touch监听事件。</span>
<span style="font-size:14px;"><span style="white-space: pre;"> </span>//getCurrentTab()方法为radiobutton+fragment时使用的适配器里自定义的方法,用于获取当前Tab <span style="white-space: pre;"> </span>if (mol[tabAdapter.getCurrentTab() - 1] != null) { <span style="white-space: pre;"> </span>MyOntouchListener listener = mol[tabAdapter.getCurrentTab() - 1]; <span style="white-space: pre;"> </span>listener.onTouchEvent(event); <span style="white-space: pre;"> </span>} <span style="white-space: pre;"> </span>return super.onTouchEvent(event); <span style="white-space: pre;"> </span>} <span style="white-space: pre;"> </span>public void registerListener(MyOntouchListener listener, int i) { <span style="white-space: pre;"> </span>mol[i] = listener; <span style="white-space: pre;"> </span>} <span style="white-space: pre;"> </span>public void unRegisterListener(MyOntouchListener listener, int i) { <span style="white-space: pre;"> </span>mol[i] = null; <span style="white-space: pre;"> </span>} <span style="white-space: pre;"> </span>public interface MyOntouchListener { <span style="white-space: pre;"> </span>public void onTouchEvent(MotionEvent event); <span style="white-space: pre;"> </span>}</span>
fragment内注册和注销代码:
<span style="font-size:14px;">// 获取activity的onTouchEvent方法 mGestureDetector = new GestureDetector(activity, this); listener = new FragmentTab.MyOntouchListener() { @Override public void onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub mGestureDetector.onTouchEvent(event); } };</span>
<span style="font-size:14px;"><span style="font-size:18px;"> // 利用生命周期设置只有显示的fragment能注册滑动监听事件 @Override public void onResume() { // TODO Auto-generated method stub ((FragmentTab) activity).registerDispatch(dis, 0); ((FragmentTab) activity).registerListener(listener, 0); super.onResume(); } @Override public void onPause() { // TODO Auto-generated method stub ((FragmentTab) activity).unRegisterDispatch(dis, 0); ((FragmentTab) activity).unRegisterListener(listener, 0); super.onPause(); }</span></span>
方法二:
这种方法虽然实现了左右滑动,并且区别了fragment的监听事件。
但还是存在一些问题:
比如在包含listview时,滑动距离过小会导致左右滑动事件和点击事件一起触发,距离过大又会影响用户体验。
原因是左右滑动没有消费掉当前点击事件,而是继续传递给子控件,具体原因可能是onTouchEvent()用于处理事件,返回值决定当前控件是否消费(consume)了这个事件,也就是说在当前控件在处理完Touch事件后,是否还允许Touch事件继续向上(父控件)传递,一但返回True,则父控件不用操心自己来处理Touch事件。而左右滑动应该是先判断父控件是否滑动,不滑动则向下(子控件)传递touch事件。这时应该使用onInterceptTouchEvent()来处理。参考文章:Android-onInterceptTouchEvent()和onTouchEvent()总结/article/8007182.html。
但是onInterceptTouchEvent()是ViewGroup的一个方法,只有包含子view的控件有这个方法,如Linearlayout,没有子view的控件没有这个方法,如TextView。
那么在fragment中没有onInterceptTouchEvent(),于是我自定义了一个FlingLinearLayout继承自Linearlayout。重写其中的onInterceptTouchEvent()方法,并自定义左右滑动方法Fling。具体FlingLinearLayout类的代码如下:
<span style="font-size:14px;">public class FlingLinearLayout extends LinearLayout { private int mLastMotionX; private int mLastMotionY; private RadioGroup rgs; private RadioButton rb; <span style="white-space:pre"> </span>//获取对应的RadioGroup public void setRgs(RadioGroup rgs) { this.rgs = rgs; } public FlingLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); } public FlingLinearLayout(Context context) { super(context); } public FlingLinearLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // TODO Auto-generated method stub int x = (int) ev.getRawX(); int y = (int) ev.getRawY(); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: // 首先拦截down事件,记录x坐标 mLastMotionX = x; mLastMotionY = y; break; case MotionEvent.ACTION_MOVE: // deltaX > 0 是向右运动,< 0是向左运动 int deltaX = x - mLastMotionX; int deltaY = y - mLastMotionY; if (Fling(deltaX, deltaY)) { return true; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: break; default: break; } return false; } </span>
<span style="font-size:14px;"><span style="white-space:pre"> </span>//左右滑动方法 private boolean Fling(int deltaX, int deltaY) { for (int i = 0; i < rgs.getChildCount(); i++) { int radioButtonId = rgs.getChildAt(i).getId(); if (rgs.getCheckedRadioButtonId() == radioButtonId) { int next = (i + 1) % rgs.getChildCount(); if (next == 0) { next = i; } int pre; if (i == 0) { pre = 0; } else { pre = i - 1; } if (deltaX < -30 && Math.abs(deltaY) < 30) { rb = (RadioButton) findViewById(rgs.getChildAt(next) .getId()); rb.setChecked(true); return true; } else if (deltaX > 30 && Math.abs(deltaY) < 30) { rb = (RadioButton) findViewById(rgs.getChildAt(pre).getId()); rb.setChecked(true); return true; } } } return false; } }</span>
应用中实现的代码:
<span style="font-size:14px;">fll = (FlingLinearLayout) view.findViewById(R.id.<span style="font-family: verdana, Arial, Helvetica, sans-serif;">FlingLinearLayout</span>); pp_rgs = (RadioGroup) view.findViewById(R.id.pp_tabs_rg); fll.setRgs(pp_rgs);</span>
xml布局:
<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?> <com.example.utils.FlingLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/FlingLinearLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFFFFF" android:orientation="vertical" > <!-- 使用fragment实现tabhost功能 --> <HorizontalScrollView android:id="@+id/pp_radio_scroll" android:layout_width="fill_parent" android:layout_height="wrap_content" android:scrollbars="none" > <RadioGroup android:id="@+id/pp_tabs_rg" android:layout_width="fill_parent" android:layout_height="48dp" android:orientation="horizontal" > <RadioButton android:id="@+id/pp_tab_rb_all" android:layout_width="35dp" android:layout_height="36dp" android:layout_marginBottom="12dp" android:layout_marginLeft="10dp" android:layout_marginRight="22dp" android:background="@drawable/pp_title_redline" android:button="@null" android:checked="true" android:gravity="center" android:singleLine="true" android:text="全部" android:textColor="@drawable/pp_fragment_text" android:textSize="14sp" /> </RadioGroup> </HorizontalScrollView> <FrameLayout android:id="@+id/pp_tab_content" android:layout_width="fill_parent" android:layout_height="0dp" android:layout_weight="1.0" android:background="#f2f2f2" /> </com.example.utils.FlingLinearLayout></span>
最后问题完美解决了。而且不需要使用最上面说的使用接口获取activity的touch监听。只需要在xml文件中把RadioGroup放在FlingLinearLayout布局里面就可以了。具体要实现什么功能可以在FlingLinearLayout中自己写。
文章中也许有疏漏的地方,欢迎大家指出我的问题,或者大家有什么建议都可以和我交流,希望能在交流中共同进步。O(∩_∩)O~
相关文章推荐
- 工作方向转变—— React Native For Android
- MVC4相关Razor语法浅谈
- 通过GeoIP获取ip所属地 (国家,城市,时区,邮编,经纬度等)
- Lifyray笑傲江湖之API总结TextUtil
- Zabbix告警集成 实时接收Zabbix告警,提供微信、移动APP、短信邮件提醒。
- qt 数据库表不存在则创建
- 一款APP,从设计稿到切图
- keil MDK的信号函数
- 设计模式那点事—模板模式
- c++关于文件夹(文件)的相关操作_findfirst,_findnext和_findclose方法
- 找出数列单独的数字
- adb logcat 基本用法
- ANT build.xml文件详解(一)
- tomcat 7 用mod_jk做 负载均衡
- 有关数据分析领域的了解
- 异常框架图
- Javascript学习笔记【第一章】
- Hibernate中saveOrUpdate、update和merge的区别
- android listview adater
- http状态码