楼主: 熊猫儿

[转载] 【Android的一些重要知识7。。。。】

[复制链接]
论坛徽章:
1682
九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-27 15:37:10九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55玉石琵琶
日期:2014-06-26 16:52:29玉石琵琶
日期:2014-06-26 16:52:29
131#
 楼主| 发表于 2018-3-19 09:05 | 只看该作者
c、MyListView

[java] view plain copy


  • package com.example.zhy_wangandroid_hownoon;  
  •   
  • import android.content.Context;  
  • import android.content.res.TypedArray;  
  • import android.util.AttributeSet;  
  • import android.util.DisplayMetrics;  
  • import android.util.Log;  
  • import android.view.WindowManager;  
  • import android.widget.AbsListView;  
  • import android.widget.AbsListView.OnScrollListener;  
  • import android.widget.ListView;  
  •   
  • public class MyListView extends ListView implements OnScrollListener  
  • {  
  •     private static final String TAG = MyListView.class.getSimpleName();  
  •   
  •     /**
  •      * 每个屏幕显示多少个Item
  •      */  
  •     private int mItemCountInOneScreen ;  
  •     /**
  •      * 每个Item的高度
  •      */  
  •     private int mItemHeight;  
  •     /**
  •      * 记录第一个显示的Item
  •      */  
  •     private int mFirstVisibleItem;  
  •   
  •     public MyListView(Context context, AttributeSet attrs)  
  •     {  
  •         this(context, attrs, 0);  
  •   
  •     }  
  •     /**
  •      * 构造方法中拿到自定义属性ItemCount,计算每个Item高度
  •      * @param context
  •      * @param attrs
  •      * @param defStyle
  •      */  


使用道具 举报

回复
论坛徽章:
1682
九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-27 15:37:10九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55玉石琵琶
日期:2014-06-26 16:52:29玉石琵琶
日期:2014-06-26 16:52:29
132#
 楼主| 发表于 2018-3-19 09:05 | 只看该作者
  • public MyListView(Context context, AttributeSet attrs, int defStyle)  
  •     {  
  •         super(context, attrs, defStyle);  
  •   
  •         WindowManager wm = (WindowManager) context  
  •                 .getSystemService(Context.WINDOW_SERVICE);  
  •         DisplayMetrics outMetrics = new DisplayMetrics();  
  •         wm.getDefaultDisplay().getMetrics(outMetrics);  
  •       
  •          
  •         //获取MyListView_itemCount  
  •         TypedArray a = context.getTheme().obtainStyledAttributes(attrs,  
  •                 R.styleable.MyListView, defStyle, 0);  
  •   
  •         int n = a.getIndexCount();  
  •         for (int i = 0; i < n; i++)  
  •         {  
  •             int attr = a.getIndex(i);  
  •             switch (attr)  
  •             {  
  •             case R.styleable.MyListView_itemCount:  
  •                 mItemCountInOneScreen = a.getInt(attr, 6);  
  •                 break;  
  •             }  
  •         }  
  •         a.recycle();  
  •          
  •         //计算每个Item高度  
  •         mItemHeight = (outMetrics.heightPixels - getStatusHeight(context))  
  •                 / mItemCountInOneScreen;  
  •          
  •         //设置一个滚动监听  
  •         setOnScrollListener(this);  
  •   
  •         Log.e(TAG, mItemCountInOneScreen + "");  
  •     }  
  •       
  •       
  •   
  •     @Override  
  •     public void onScrollStateChanged(AbsListView view, int scrollState)  
  •     {  
  •         //滚动结束  
  •         if (scrollState == OnScrollListener.SCROLL_STATE_IDLE)  
  •         {  
  •             // Log.e(TAG, getChildAt(0).getTop() + " getTop()");  
  •   
  •             Log.e(TAG, mFirstVisibleItem + " SCROLL_STATE_IDLE");  
  •             //获取第一个Item的top  

使用道具 举报

回复
论坛徽章:
1682
九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-27 15:37:10九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55玉石琵琶
日期:2014-06-26 16:52:29玉石琵琶
日期:2014-06-26 16:52:29
133#
 楼主| 发表于 2018-3-19 09:07 | 只看该作者
  • int top = getChildAt(0).getTop();  
  •             if (top == 0)  
  •                 return;  
  •             //绝对值不为0时,如果绝对值大于mItemHeight的一半,则收缩,即显示下一个Item  
  •             if (Math.abs(top) > mItemHeight / 2)  
  •             {  
  •                 this.setSelection(mFirstVisibleItem + 1);  
  •   
  •                 // this.scrollTo(x, y)  
  •                 // smoothScrollToPosition(mFirstVisibleItem - 1);  
  •                 // scrollBy(0, mItemHeight- Math.abs(top));  
  •                 // smoothScrollBy(mItemHeight- Math.abs(top), 200);  
  •   
  •             } else//绝对值不为0时,如果绝对值小于于mItemHeight的一半,则展开,显示当前完整的Item  
  •             {  
  •                 this.setSelection(mFirstVisibleItem);  
  •   
  •                 // this.scrollTo(x, y)  
  •                 // smoothScrollBy( -Math.abs(top), 200);  
  •                 // smoothScrollByOffset(offset);  
  •                 // scrollBy(0, -Math.abs(top));  
  •                 // smoothScrollToPosition(mFirstVisibleItem);  
  •             }  
  •             // smoothScrollToPosition(mFirstVisibleItem);  
  •   
  •         }  
  •   
  •     }  
  •   
  •     /**
  •      * 滚动过程中不断记录当前显示的第一个Item
  •      */  
  •     @Override  
  •     public void onScroll(AbsListView view, int firstVisibleItem,  
  •             int visibleItemCount, int totalItemCount)  
  •     {  
  •         mFirstVisibleItem = firstVisibleItem;  
  •         // Log.e(TAG, mFirstVisibleItem + "");  
  •     }  
  •       
  •     /**
  •      * 对外公布每个Item的高度
  •      * @return
  •      */  http://blog.csdn.net/lmj623565791/article/details/38950509

使用道具 举报

回复
论坛徽章:
1682
九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-27 15:37:10九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55玉石琵琶
日期:2014-06-26 16:52:29玉石琵琶
日期:2014-06-26 16:52:29
134#
 楼主| 发表于 2018-3-20 08:58 | 只看该作者
  • public int getItemHeight()  
  •     {  
  •         return mItemHeight;  
  •     }  
  •   
  •     /**
  •      * 获得状态栏的高度
  •      *  
  •      * @param context
  •      * @return
  •      */  
  •     public int getStatusHeight(Context context)  
  •     {  
  •   
  •         int statusHeight = -1;  
  •         try  
  •         {  
  •             Class<?> clazz = Class.forName("com.android.internal.R$dimen");  
  •             Object object = clazz.newInstance();  
  •             int height = Integer.parseInt(clazz.getField("status_bar_height")  
  •                     .get(object).toString());  
  •             statusHeight = context.getResources().getDimensionPixelSize(height);  
  •         } catch (Exception e)  
  •         {  
  •             e.printStackTrace();  
  •         }  
  •         return statusHeight;  
  •     }  
  •   
  • }  


代码比较少,也比较简单,大家可以关注下,我在onScrollStateChanged注释掉的那些方法,原则上说每一个应该都能实现;但是我最终选择了setSelection(mFirstVisibleItem);有兴趣的可以拿别的方法试试;

d、MainActivity中


[java] view plain copy


  • package com.example.zhy_wangandroid_hownoon;  
  •   
  • import java.util.ArrayList;  
  • import java.util.List;  
  • import java.util.Random;  
  •   
  • import com.zhy.utils.CommonAdapter;  
  • import com.zhy.utils.ViewHolder;  
  •   
  • import android.app.Activity;  
  • import android.graphics.Color;  
  • import android.os.Bundle;  
  • import android.view.View;  
  • import android.view.ViewGroup;  
  • import android.view.Window;  


使用道具 举报

回复
论坛徽章:
1682
九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-27 15:37:10九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55玉石琵琶
日期:2014-06-26 16:52:29玉石琵琶
日期:2014-06-26 16:52:29
135#
 楼主| 发表于 2018-3-20 08:58 | 只看该作者
  • public class MainActivity extends Activity  
  • {  
  •   
  •     private MyListView mListView;  
  •     private CommonAdapter<String> mAdapter;  
  •     private List<String> mDatas;  
  •   
  •     @Override  
  •     protected void onCreate(Bundle savedInstanceState)  
  •     {  
  •         super.onCreate(savedInstanceState);  
  •         requestWindowFeature(Window.FEATURE_NO_TITLE);  
  •         setContentView(R.layout.activity_main);  
  •   
  •         mListView = (MyListView) findViewById(R.id.id_lv);  
  •         initDatas();  
  •         initViews();  
  •   
  •     }  
  •   
  •     private void initViews()  
  •     {  
  •         mListView = (MyListView) findViewById(R.id.id_lv);  
  •         mAdapter = new CommonAdapter<String>(this, mDatas, R.layout.item)  
  •         {  
  •             @Override  
  •             public void convert(ViewHolder helper, String item)  
  •             {  
  •                 View convertView = helper.getConvertView();  
  •                 convertView.setBackgroundColor(Color.rgb(  
  •                         new Random().nextInt(255), new Random().nextInt(255),  
  •                         new Random().nextInt(255)));  
  •                 ViewGroup.LayoutParams lp = convertView.getLayoutParams();  
  •                 lp.height = mListView.getItemHeight();  
  •                 convertView.setLayoutParams(lp);  
  •                 helper.setText(R.id.id_title, item);  
  •             }  
  •         };  
  •   
  •         mListView.setAdapter(mAdapter);  
  •     }  
  •   
  •     private void initDatas()  
  •     {  
  •         mDatas = new ArrayList<String>();  
  •   
  •         for (int i = 'A'; i <= 'Z'; i++)  
  •         {  
  •             mDatas.add(String.valueOf((char) +i));  
  •         }  
  •     }  
  • }  



使用道具 举报

回复
论坛徽章:
1682
九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-27 15:37:10九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55玉石琵琶
日期:2014-06-26 16:52:29玉石琵琶
日期:2014-06-26 16:52:29
136#
 楼主| 发表于 2018-3-20 08:59 | 只看该作者
使用就没撒说的了,我用了我们之前封装的CommonAdapter,如果不了解可以参考:Android 快速开发系列 打造万能的ListView GridView 适配器;如果看不惯自行改成传统的Adapter,相信大家应该没问题~

还有些需求是这样的,既要满足每次停止显示完整的Item,还希望即使用户给了个加速度,在用户抬起手指时,不会自动的滚动;

4、ListView显示完整Item,屏蔽自动滚动

这个比较容易了,只需要复写onTouchEvent方法,然后在ACTION_UP后,进行检查是显示/影藏当前Item,然后return true;


[java] view plain copy


  • @Override  
  •     public boolean onTouchEvent(MotionEvent ev)  
  •     {  
  •         int action = ev.getAction();  
  •         if (action == MotionEvent.ACTION_UP)  
  •         {  
  •             checkForReset();  
  •             return true;  
  •         }  
  •         return super.onTouchEvent(ev);  
  •     }  
  •   
  •     @Override  
  •     public void onScrollStateChanged(AbsListView view, int scrollState)  
  •     {  
  •         // 滚动结束  
  •         if (scrollState == OnScrollListener.SCROLL_STATE_IDLE)  
  •         {  
  •             checkForReset();  
  •         }  
  •   
  •     }  


使用道具 举报

回复
论坛徽章:
1682
九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-27 15:37:10九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55玉石琵琶
日期:2014-06-26 16:52:29玉石琵琶
日期:2014-06-26 16:52:29
137#
 楼主| 发表于 2018-3-20 08:59 | 只看该作者
关键代码如上,其他所有代码和上例一致;
效果图:




好了,就介绍到这了;


使用道具 举报

回复
论坛徽章:
1682
九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-27 15:37:10九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55玉石琵琶
日期:2014-06-26 16:52:29玉石琵琶
日期:2014-06-26 16:52:29
138#
 楼主| 发表于 2018-3-20 09:00 | 只看该作者
Android View 事件分发机制 源码解析 (上)

一直想写事件分发机制的文章,不管咋样,也得自己研究下事件分发的源码,写出心得~


首先我们先写个简单的例子来测试View的事件转发的流程~

1、案例

为了更好的研究View的事件转发,我们自定以一个MyButton继承Button,然后把跟事件传播有关的方法进行复写,然后添加上日志~

MyButton


[java] view plain copy


  • package com.example.zhy_event03;  
  •   
  • import android.content.Context;  
  • import android.util.AttributeSet;  
  • import android.util.Log;  
  • import android.view.MotionEvent;  
  • import android.widget.Button;  
  •   
  • public class MyButton extends Button  
  • {  
  •     private static final String TAG = MyButton.class.getSimpleName();  
  •   
  •     public MyButton(Context context, AttributeSet attrs)  
  •     {  
  •         super(context, attrs);  
  •     }  
  •   
  •     @Override  
  •     public boolean onTouchEvent(MotionEvent event)  
  •     {  
  •         int action = event.getAction();  
  •   
  •         switch (action)  
  •         {  
  •         case MotionEvent.ACTION_DOWN:  
  •             Log.e(TAG, "onTouchEvent ACTION_DOWN");  
  •             break;  
  •         case MotionEvent.ACTION_MOVE:  
  •             Log.e(TAG, "onTouchEvent ACTION_MOVE");  
  •             break;  
  •         case MotionEvent.ACTION_UP:  
  •             Log.e(TAG, "onTouchEvent ACTION_UP");  
  •             break;  
  •         default:  
  •             break;  
  •         }  
  •         return super.onTouchEvent(event);  
  •     }  
  •       
  •     @Override  
  •     public boolean dispatchTouchEvent(MotionEvent event)  
  •     {  
  •         int action = event.getAction();  
  •   
  •         switch (action)  
  •         {  
  •         case MotionEvent.ACTION_DOWN:  
  •             Log.e(TAG, "dispatchTouchEvent ACTION_DOWN");  
  •             break;  
  •         case MotionEvent.ACTION_MOVE:  
  •             Log.e(TAG, "dispatchTouchEvent ACTION_MOVE");  
  •             break;  
  •         case MotionEvent.ACTION_UP:  
  •             Log.e(TAG, "dispatchTouchEvent ACTION_UP");  
  •             break;  
  •   
  •         default:  
  •             break;  
  •         }  
  •         return super.dispatchTouchEvent(event);  
  •     }  
  •   
  •       
  • }  




使用道具 举报

回复
论坛徽章:
1682
九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-27 15:37:10九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55玉石琵琶
日期:2014-06-26 16:52:29玉石琵琶
日期:2014-06-26 16:52:29
139#
 楼主| 发表于 2018-3-21 15:03 | 只看该作者
在MainActivity中,我们还给MyButton设置了OnTouchListener这个监听~

好了,跟View事件相关一般就这三个地方了,一个onTouchEvent,一个dispatchTouchEvent,一个setOnTouchListener;

下面我们运行,然后点击按钮,查看日志输出:


[html] view plain copy


  • 08-31 06:09:39.030: E/MyButton(879): dispatchTouchEvent ACTION_DOWN  
  • 08-31 06:09:39.030: E/MyButton(879): onTouch ACTION_DOWN  
  • 08-31 06:09:39.049: E/MyButton(879): onTouchEvent ACTION_DOWN  
  • 08-31 06:09:39.138: E/MyButton(879): dispatchTouchEvent ACTION_MOVE  
  • 08-31 06:09:39.138: E/MyButton(879): onTouch ACTION_MOVE  
  • 08-31 06:09:39.147: E/MyButton(879): onTouchEvent ACTION_MOVE  
  • 08-31 06:09:39.232: E/MyButton(879): dispatchTouchEvent ACTION_UP  
  • 08-31 06:09:39.248: E/MyButton(879): onTouch ACTION_UP  
  • 08-31 06:09:39.248: E/MyButton(879): onTouchEvent ACTION_UP  


我有意点击的时候蹭了一下,不然不会触发MOVE,手抖可能会打印一堆MOVE的日志~~~

好了,可以看到,不管是DOWN,MOVE,UP都会按照下面的顺序执行:

1、dispatchTouchEvent

2、 setOnTouchListener的onTouch

3、onTouchEvent

下面就跟随日志的脚步开始源码的探索~

2、dispatchTouchEvent

首先进入View的dispatchTouchEvent


[java] view plain copy


  • /**
  •      * Pass the touch screen motion event down to the target view, or this
  •      * view if it is the target.
  •      *
  •      * @param event The motion event to be dispatched.
  •      * @return True if the event was handled by the view, false otherwise.
  •      */  
  •     public boolean dispatchTouchEvent(MotionEvent event) {  
  •         if (!onFilterTouchEventForSecurity(event)) {  
  •             return false;  
  •         }  
  •   
  •         if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&  
  •                 mOnTouchListener.onTouch(this, event)) {  
  •             return true;  
  •         }  
  •         return onTouchEvent(event);  
  •     }  


使用道具 举报

回复
论坛徽章:
1682
九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-27 15:37:10九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55九尾狐狸
日期:2012-09-19 11:12:55玉石琵琶
日期:2014-06-26 16:52:29玉石琵琶
日期:2014-06-26 16:52:29
140#
 楼主| 发表于 2018-3-21 15:03 | 只看该作者
直接看13行:首先判断mOnTouchListener不为null,并且view是enable的状态,然后 mOnTouchListener.onTouch(this, event)返回true,这三个条件如果都满足,直接return true ; 也就是下面的onTouchEvent(event)不会被执行了;

那么mOnTouchListener是和方神圣,我们来看看:


[java] view plain copy


  • /**
  •   * Register a callback to be invoked when a touch event is sent to this view.
  •   * @param l the touch listener to attach to this view
  •   */  
  • public void setOnTouchListener(OnTouchListener l) {  
  •      mOnTouchListener = l;  
  • }  

其实就是我们在Activity中设置的setOnTouchListener。

也就是说:如果我们设置了setOnTouchListener,并且return true,那么View自己的onTouchEvent就不会被执行了,当然了,本例我们return false,我们还得往下探索 ;

已经解决一个常见的问题:View的onTouchListener和onTouchEvent的调用关系,相信大家应该已经明白了~let's go;继续往下。

3、View的onTouchEvent:

接下来是View的onTouchEvent:


[java] view plain copy


  • /**
  •      * Implement this method to handle touch screen motion events.
  •      *
  •      * @param event The motion event.
  •      * @return True if the event was handled, false otherwise.
  •      */  
  •     public boolean onTouchEvent(MotionEvent event) {  
  •         final int viewFlags = mViewFlags;  
  •   
  •         if ((viewFlags & ENABLED_MASK) == DISABLED) {  
  •             // A disabled view that is clickable still consumes the touch  
  •             // events, it just doesn't respond to them.  
  •             return (((viewFlags & CLICKABLE) == CLICKABLE ||  
  •                     (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE));  
  •         }  
  •   
  •         if (mTouchDelegate != null) {  
  •             if (mTouchDelegate.onTouchEvent(event)) {  
  •                 return true;  
  •             }  
  •         }  
  •   
  •         if (((viewFlags & CLICKABLE) == CLICKABLE ||  
  •                 (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {  
  •             switch (event.getAction()) {  
  •                 case MotionEvent.ACTION_UP:  
  •                     boolean prepressed = (mPrivateFlags & PREPRESSED) != 0;  
  •                     if ((mPrivateFlags & PRESSED) != 0 || prepressed) {  
  •                         // take focus if we don't have it already and we should in  
  •                         // touch mode.  
  •                         boolean focusTaken = false;  
  •                         if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {  
  •                             focusTaken = requestFocus();  
  •                         }  
  •   


使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表