转载

通信录分组并且分组标签悬停划入划出(包含错误信息及修改)--第三方开源--PinnedSectionListView

通信录分组并且分组标签悬停划入划出(包含错误信息及修改)--第三方开源--PinnedSectionListView

PinnedSectionListView在github上的链接地址是: https://github.com/beworker/pinned-section-listview 。

下载下来后直接将PinnedSectionListView.java(在一些SDK版本拉动的时候会异常崩溃,异常信息和修改后的文档在后面)复制粘贴在要用的包中:

通信录分组并且分组标签悬停划入划出(包含错误信息及修改)--第三方开源--PinnedSectionListView

activity_main.xml:

1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  2     xmlns:tools="http://schemas.android.com/tools"  3     android:layout_width="match_parent"  4     android:layout_height="match_parent"  5     tools:context="com.zzw.testpinnedsectionlistview.MainActivity" >  6   7     <com.zzw.testpinnedsectionlistview.PinnedSectionListView  8         android:id="@+id/listView"  9         android:layout_width="match_parent" 10         android:layout_height="match_parent" /> 11  12 </RelativeLayout>

item.xml:

1 <?xml version="1.0" encoding="utf-8"?>  2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  3     android:layout_width="match_parent"  4     android:layout_height="match_parent"  5     android:orientation="vertical" >  6   7     <ImageView  8         android:id="@+id/imageView"  9         android:layout_width="wrap_content" 10         android:layout_height="wrap_content" 11         android:layout_alignParentLeft="true" 12         android:layout_centerVertical="true" 13         android:src="@drawable/ic_launcher" /> 14  15     <TextView 16         android:id="@+id/textView" 17         android:layout_width="wrap_content" 18         android:layout_height="wrap_content" 19         android:layout_alignBottom="@+id/imageView1" 20         android:layout_alignParentRight="true" 21         android:gravity="center" 22         android:textSize="20sp" 23         android:layout_alignTop="@+id/imageView1" 24         android:layout_toRightOf="@+id/imageView1" 25         android:text="TextView" /> 26  27 </RelativeLayout>  item.xml

MainActivity.java:

1 package com.zzw.testpinnedsectionlistview;   2    3 import java.util.ArrayList;   4    5 import com.zzw.testpinnedsectionlistview.PinnedSectionListView.PinnedSectionListAdapter;   6    7 import android.app.Activity;   8 import android.content.Context;   9 import android.graphics.Color;  10 import android.os.Bundle;  11 import android.view.LayoutInflater;  12 import android.view.View;  13 import android.view.ViewGroup;  14 import android.widget.ArrayAdapter;  15 import android.widget.TextView;  16   17 public class MainActivity extends Activity {  18   19     private ArrayList<Item> items = null;  20   21     private final int VIEW_TYPE_COUNT = 2;  22   23     @Override  24     protected void onCreate(Bundle savedInstanceState) {  25         super.onCreate(savedInstanceState);  26         setContentView(R.layout.activity_main);  27   28         items =new ArrayList<MainActivity.Item>();  29         // 假设我们演示以A,B,C,,,F这样的字符串作为分组的标签。  30         // 每一组装载5个子数据。  31         String[] groups = { "A", "B", "C", "D", "E" };  32         for (int i = 0; i < groups.length; i++) {  33             String s = groups[i];  34   35             Item group = new Item();  36             group.type = Item.GROUP;  37             group.text = s;  38             items.add(group);  39   40             for (int j = 0; j < 10; j++) {  41                 Item child = new Item();  42                 child.type = Item.CHILD;  43                 child.text = s + "组数据:" + j;  44                 items.add(child);  45             }  46         }  47   48         PinnedSectionListView listView = (PinnedSectionListView) findViewById(R.id.listView);  49         listView.setAdapter(new MyAdapter(this, -1));  50   51     }  52   53     private class Item {  54         public static final int GROUP = 0;  55         public static final int CHILD = 1;  56   57         public int type;  58         public String text;  59     }  60   61     private class MyAdapter extends ArrayAdapter<Item> implements PinnedSectionListAdapter {  62   63         private LayoutInflater inflater;  64   65         public MyAdapter(Context context, int resource) {  66             super(context, resource);  67   68             inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);  69         }  70   71         @Override  72         public int getItemViewType(int position) {  73   74             return items.get(position).type;  75         }  76   77         @Override  78         public int getCount() {  79   80             return items.size();  81         }  82   83         @Override  84         public int getViewTypeCount() {  85   86             return VIEW_TYPE_COUNT;  87         }  88   89         @Override  90         public Item getItem(int position) {  91   92             return items.get(position);  93         }  94   95         @Override  96         public View getView(int position, View convertView, ViewGroup parent) {  97             switch (getItemViewType(position)) {  98             case Item.GROUP:  99  100                 if (convertView == null) { 101                     convertView = inflater.inflate(android.R.layout.simple_list_item_1, null); 102                 } 103  104                 TextView textView_group = (TextView) convertView.findViewById(android.R.id.text1); 105                 textView_group.setText(getItem(position).text); 106                 textView_group.setTextColor(Color.BLUE); 107                 textView_group.setTextSize(30); 108                 textView_group.setBackgroundColor(Color.GRAY); 109  110                 break; 111  112             case Item.CHILD: 113                 if (convertView == null) { 114                     convertView = inflater.inflate(R.layout.item, null); 115                 } 116  117                 TextView textView_child = (TextView) convertView.findViewById(R.id.textView); 118                 textView_child.setText(getItem(position).text); 119                 textView_child.setBackgroundColor(Color.YELLOW); 120  121                 break; 122             } 123             return convertView; 124         } 125  126         /* 127          * 假设此方法返回皆为false。那么PinnedSectionListView将退化成为一个基础的ListView. 128          * 只不过退化后的ListView只是一个拥有两个View Type的ListView。 129          *  130          * 从某种角度上讲,此方法对于PinnedSectionListView至关重要 131          * 返回值true或false,将直接导致PinnedSectionListView是一个PinnedSectionListView, 132          * 还是一个普通的ListView 133          *  134          */ 135         @Override 136         public boolean isItemViewTypePinned(int viewType) { 137             boolean type = false; 138             switch (viewType) { 139             case Item.GROUP: 140                 type = true; 141                 break; 142  143             case Item.CHILD: 144                 type = false; 145                 break; 146  147             default: 148                 type = false; 149                 break; 150             } 151             return type; 152         } 153     } 154 }

程序运行拉动的时候有的sdk版本会出现程序崩溃,LogCat是这样情况:

通信录分组并且分组标签悬停划入划出(包含错误信息及修改)--第三方开源--PinnedSectionListView

报错的是原代码PinnedSectionListView.java中的(200行左右):

// read layout parameters         LayoutParams layoutParams = (LayoutParams) pinnedView.getLayoutParams();         if (layoutParams == null) {             layoutParams = (LayoutParams) generateDefaultLayoutParams();             pinnedView.setLayoutParams(layoutParams);         }

主要是这句话:

layoutParams = (LayoutParams) generateDefaultLayoutParams();

经由研究发现,此原因是在调用Android系统的generateDefaultLayoutParams()方法时候,发生异常,致使代码运行获得的结果layoutParams不正常,进而导致PinnedSectionListView崩溃。

解决方案:

自己动手重写Android系统的generateDefaultLayoutParams()方法,返回自己定制的LayoutParams值。

具体实现:

在PinnedSectionListView.java中增加自己重写的generateDefaultLayoutParams()方法:

1 @Override   2    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {   3        4     LayoutParams mLayoutParams=new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);   5        6     return mLayoutParams;   7    }

最终修复bug,改进后的PinnedSectionListView.java全部源代码为如下(可直接复制粘贴使用):

1 /*   2  * Copyright (C) 2013 Sergej Shafarenka, halfbit.de   3  *   4  * Licensed under the Apache License, Version 2.0 (the "License");   5  * you may not use this file kt in compliance with the License.   6  * You may obtain a copy of the License at   7  *   8  * http://www.apache.org/licenses/LICENSE-2.0   9  *  10  * Unless required by applicable law or agreed to in writing, software  11  * distributed under the License is distributed on an "AS IS" BASIS,  12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  13  * See the License for the specific language governing permissions and  14  * limitations under the License.  15  */  16   17 package com.zzw.testpinnedsectionlistview;  18   19   20 import android.content.Context;  21 import android.database.DataSetObserver;  22 import android.graphics.Canvas;  23 import android.graphics.Color;  24 import android.graphics.PointF;  25 import android.graphics.Rect;  26 import android.graphics.drawable.GradientDrawable;  27 import android.graphics.drawable.GradientDrawable.Orientation;  28 import android.os.Parcelable;  29 import android.util.AttributeSet;  30 import android.view.MotionEvent;  31 import android.view.SoundEffectConstants;  32 import android.view.View;  33 import android.view.ViewConfiguration;  34 import android.view.ViewGroup;  35 import android.view.accessibility.AccessibilityEvent;  36 import android.widget.AbsListView;  37 import android.widget.HeaderViewListAdapter;  38 import android.widget.ListAdapter;  39 import android.widget.ListView;  40 import android.widget.SectionIndexer;  41   42   43 /**  44  * ListView, which is capable to pin section views at its top while the rest is still scrolled.  45  */  46 public class PinnedSectionListView extends ListView {  47   48     //-- inner classes  49   50     /** List adapter to be implemented for being used with PinnedSectionListView adapter. */  51     public static interface PinnedSectionListAdapter extends ListAdapter {  52         /** This method shall return 'true' if views of given type has to be pinned. */  53         boolean isItemViewTypePinned(int viewType);  54     }  55   56     /** Wrapper class for pinned section view and its position in the list. */  57     static class PinnedSection {  58         public View view;  59         public int position;  60         public long id;  61     }  62   63     //-- class fields  64   65     // fields used for handling touch events  66     private final Rect mTouchRect = new Rect();  67     private final PointF mTouchPoint = new PointF();  68     private int mTouchSlop;  69     private View mTouchTarget;  70     private MotionEvent mDownEvent;  71   72     // fields used for drawing shadow under a pinned section  73     private GradientDrawable mShadowDrawable;  74     private int mSectionsDistanceY;  75     private int mShadowHeight;  76   77     /** Delegating listener, can be null. */  78     OnScrollListener mDelegateOnScrollListener;  79   80     /** Shadow for being recycled, can be null. */  81     PinnedSection mRecycleSection;  82   83     /** shadow instance with a pinned view, can be null. */  84     PinnedSection mPinnedSection;  85   86     /** Pinned view Y-translation. We use it to stick pinned view to the next section. */  87     int mTranslateY;  88   89     /** Scroll listener which does the magic */  90     private final OnScrollListener mOnScrollListener = new OnScrollListener() {  91   92         @Override public void onScrollStateChanged(AbsListView view, int scrollState) {  93             if (mDelegateOnScrollListener != null) { // delegate  94                 mDelegateOnScrollListener.onScrollStateChanged(view, scrollState);  95             }  96         }  97   98         @Override  99         public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 100  101             if (mDelegateOnScrollListener != null) { // delegate 102                 mDelegateOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); 103             } 104  105             // get expected adapter or fail fast 106             ListAdapter adapter = getAdapter(); 107             if (adapter == null || visibleItemCount == 0) return; // nothing to do 108  109             final boolean isFirstVisibleItemSection = 110                     isItemViewTypePinned(adapter, adapter.getItemViewType(firstVisibleItem)); 111  112             if (isFirstVisibleItemSection) { 113                 View sectionView = getChildAt(0); 114                 if (sectionView.getTop() == getPaddingTop()) { // view sticks to the top, no need for pinned shadow 115                     destroyPinnedShadow(); 116                 } else { // section doesn't stick to the top, make sure we have a pinned shadow 117                     ensureShadowForPosition(firstVisibleItem, firstVisibleItem, visibleItemCount); 118                 } 119  120             } else { // section is not at the first visible position 121                 int sectionPosition = findCurrentSectionPosition(firstVisibleItem); 122                 if (sectionPosition > -1) { // we have section position 123                     ensureShadowForPosition(sectionPosition, firstVisibleItem, visibleItemCount); 124                 } else { // there is no section for the first visible item, destroy shadow 125                     destroyPinnedShadow(); 126                 } 127             } 128         }; 129  130     }; 131  132     /** Default change observer. */ 133     private final DataSetObserver mDataSetObserver = new DataSetObserver() { 134         @Override public void onChanged() { 135             recreatePinnedShadow(); 136         }; 137         @Override public void onInvalidated() { 138             recreatePinnedShadow(); 139         } 140     }; 141  142     //-- constructors 143  144     public PinnedSectionListView(Context context, AttributeSet attrs) { 145         super(context, attrs); 146         initView(); 147     } 148  149     public PinnedSectionListView(Context context, AttributeSet attrs, int defStyle) { 150         super(context, attrs, defStyle); 151         initView(); 152     } 153  154     private void initView() { 155         setOnScrollListener(mOnScrollListener); 156         mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); 157         initShadow(true); 158     } 159  160     //-- public API methods 161  162     public void setShadowVisible(boolean visible) { 163         initShadow(visible); 164         if (mPinnedSection != null) { 165             View v = mPinnedSection.view; 166             invalidate(v.getLeft(), v.getTop(), v.getRight(), v.getBottom() + mShadowHeight); 167         } 168     } 169  170     //-- pinned section drawing methods 171  172     public void initShadow(boolean visible) { 173         if (visible) { 174             if (mShadowDrawable == null) { 175                 mShadowDrawable = new GradientDrawable(Orientation.TOP_BOTTOM, 176                         new int[] { Color.parseColor("#ffa0a0a0"), Color.parseColor("#50a0a0a0"), Color.parseColor("#00a0a0a0")}); 177                 mShadowHeight = (int) (8 * getResources().getDisplayMetrics().density); 178             } 179         } else { 180             if (mShadowDrawable != null) { 181                 mShadowDrawable = null; 182                 mShadowHeight = 0; 183             } 184         } 185     } 186  187      188     @Override 189     protected ViewGroup.LayoutParams generateDefaultLayoutParams() { 190         LayoutParams mLayoutParams=new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT);     191         return mLayoutParams; 192     } 193      194     /** Create shadow wrapper with a pinned view for a view at given position */ 195     void createPinnedShadow(int position) { 196  197         // try to recycle shadow 198         PinnedSection pinnedShadow = mRecycleSection; 199         mRecycleSection = null; 200  201         // create new shadow, if needed 202         if (pinnedShadow == null) pinnedShadow = new PinnedSection(); 203         // request new view using recycled view, if such 204         View pinnedView = getAdapter().getView(position, pinnedShadow.view, PinnedSectionListView.this); 205  206         // read layout parameters 207         LayoutParams layoutParams = (LayoutParams) pinnedView.getLayoutParams(); 208         if (layoutParams == null) { 209             layoutParams = (LayoutParams) generateDefaultLayoutParams(); 210             pinnedView.setLayoutParams(layoutParams); 211         } 212  213         int heightMode = MeasureSpec.getMode(layoutParams.height); 214         int heightSize = MeasureSpec.getSize(layoutParams.height); 215  216         if (heightMode == MeasureSpec.UNSPECIFIED) heightMode = MeasureSpec.EXACTLY; 217  218         int maxHeight = getHeight() - getListPaddingTop() - getListPaddingBottom(); 219         if (heightSize > maxHeight) heightSize = maxHeight; 220  221         // measure & layout 222         int ws = MeasureSpec.makeMeasureSpec(getWidth() - getListPaddingLeft() - getListPaddingRight(), MeasureSpec.EXACTLY); 223         int hs = MeasureSpec.makeMeasureSpec(heightSize, heightMode); 224         pinnedView.measure(ws, hs); 225         pinnedView.layout(0, 0, pinnedView.getMeasuredWidth(), pinnedView.getMeasuredHeight()); 226         mTranslateY = 0; 227  228         // initialize pinned shadow 229         pinnedShadow.view = pinnedView; 230         pinnedShadow.position = position; 231         pinnedShadow.id = getAdapter().getItemId(position); 232  233         // store pinned shadow 234         mPinnedSection = pinnedShadow; 235     } 236  237     /** Destroy shadow wrapper for currently pinned view */ 238     void destroyPinnedShadow() { 239         if (mPinnedSection != null) { 240             // keep shadow for being recycled later 241             mRecycleSection = mPinnedSection; 242             mPinnedSection = null; 243         } 244     } 245  246     /** Makes sure we have an actual pinned shadow for given position. */ 247     void ensureShadowForPosition(int sectionPosition, int firstVisibleItem, int visibleItemCount) { 248         if (visibleItemCount < 2) { // no need for creating shadow at all, we have a single visible item 249             destroyPinnedShadow(); 250             return; 251         } 252  253         if (mPinnedSection != null 254                 && mPinnedSection.position != sectionPosition) { // invalidate shadow, if required 255             destroyPinnedShadow(); 256         } 257  258         if (mPinnedSection == null) { // create shadow, if empty 259             createPinnedShadow(sectionPosition); 260         } 261  262         // align shadow according to next section position, if needed 263         int nextPosition = sectionPosition + 1; 264         if (nextPosition < getCount()) { 265             int nextSectionPosition = findFirstVisibleSectionPosition(nextPosition, 266                     visibleItemCount - (nextPosition - firstVisibleItem)); 267             if (nextSectionPosition > -1) { 268                 View nextSectionView = getChildAt(nextSectionPosition - firstVisibleItem); 269                 final int bottom = mPinnedSection.view.getBottom() + getPaddingTop(); 270                 mSectionsDistanceY = nextSectionView.getTop() - bottom; 271                 if (mSectionsDistanceY < 0) { 272                     // next section overlaps pinned shadow, move it up 273                     mTranslateY = mSectionsDistanceY; 274                 } else { 275                     // next section does not overlap with pinned, stick to top 276                     mTranslateY = 0; 277                 } 278             } else { 279                 // no other sections are visible, stick to top 280                 mTranslateY = 0; 281                 mSectionsDistanceY = Integer.MAX_VALUE; 282             } 283         } 284  285     } 286  287     int findFirstVisibleSectionPosition(int firstVisibleItem, int visibleItemCount) { 288         ListAdapter adapter = getAdapter(); 289  290         int adapterDataCount = adapter.getCount(); 291         if (getLastVisiblePosition() >= adapterDataCount) return -1; // dataset has changed, no candidate 292  293         if (firstVisibleItem+visibleItemCount >= adapterDataCount){//added to prevent index Outofbound (in case) 294             visibleItemCount = adapterDataCount-firstVisibleItem; 295         } 296  297         for (int childIndex = 0; childIndex < visibleItemCount; childIndex++) { 298             int position = firstVisibleItem + childIndex; 299             int viewType = adapter.getItemViewType(position); 300             if (isItemViewTypePinned(adapter, viewType)) return position; 301         } 302         return -1; 303     } 304  305     int findCurrentSectionPosition(int fromPosition) { 306         ListAdapter adapter = getAdapter(); 307  308         if (fromPosition >= adapter.getCount()) return -1; // dataset has changed, no candidate 309          310         if (adapter instanceof SectionIndexer) { 311             // try fast way by asking section indexer 312             SectionIndexer indexer = (SectionIndexer) adapter; 313             int sectionPosition = indexer.getSectionForPosition(fromPosition); 314             int itemPosition = indexer.getPositionForSection(sectionPosition); 315             int typeView = adapter.getItemViewType(itemPosition); 316             if (isItemViewTypePinned(adapter, typeView)) { 317                 return itemPosition; 318             } // else, no luck 319         } 320  321         // try slow way by looking through to the next section item above 322         for (int position=fromPosition; position>=0; position--) { 323             int viewType = adapter.getItemViewType(position); 324             if (isItemViewTypePinned(adapter, viewType)) return position; 325         } 326         return -1; // no candidate found 327     } 328  329     void recreatePinnedShadow() { 330         destroyPinnedShadow(); 331         ListAdapter adapter = getAdapter(); 332         if (adapter != null && adapter.getCount() > 0) { 333             int firstVisiblePosition = getFirstVisiblePosition(); 334             int sectionPosition = findCurrentSectionPosition(firstVisiblePosition); 335             if (sectionPosition == -1) return; // no views to pin, exit 336             ensureShadowForPosition(sectionPosition, 337                     firstVisiblePosition, getLastVisiblePosition() - firstVisiblePosition); 338         } 339     } 340  341     @Override 342     public void setOnScrollListener(OnScrollListener listener) { 343         if (listener == mOnScrollListener) { 344             super.setOnScrollListener(listener); 345         } else { 346             mDelegateOnScrollListener = listener; 347         } 348     } 349  350     @Override 351     public void onRestoreInstanceState(Parcelable state) { 352         super.onRestoreInstanceState(state); 353         post(new Runnable() { 354             @Override public void run() { // restore pinned view after configuration change 355                 recreatePinnedShadow(); 356             } 357         }); 358     } 359  360     @Override 361     public void setAdapter(ListAdapter adapter) { 362  363         // assert adapter in debug mode 364         if (BuildConfig.DEBUG && adapter != null) { 365             if (!(adapter instanceof PinnedSectionListAdapter)) 366                 throw new IllegalArgumentException("Does your adapter implement PinnedSectionListAdapter?"); 367             if (adapter.getViewTypeCount() < 2) 368                 throw new IllegalArgumentException("Does your adapter handle at least two types" + 369                         " of views in getViewTypeCount() method: items and sections?"); 370         } 371  372         // unregister observer at old adapter and register on new one 373         ListAdapter oldAdapter = getAdapter(); 374         if (oldAdapter != null) oldAdapter.unregisterDataSetObserver(mDataSetObserver); 375         if (adapter != null) adapter.registerDataSetObserver(mDataSetObserver); 376  377         // destroy pinned shadow, if new adapter is not same as old one 378         if (oldAdapter != adapter) destroyPinnedShadow(); 379  380         super.setAdapter(adapter); 381     } 382  383     @Override 384     protected void onLayout(boolean changed, int l, int t, int r, int b) { 385         super.onLayout(changed, l, t, r, b); 386         if (mPinnedSection != null) { 387             int parentWidth = r - l - getPaddingLeft() - getPaddingRight(); 388             int shadowWidth = mPinnedSection.view.getWidth(); 389             if (parentWidth != shadowWidth) { 390                 recreatePinnedShadow(); 391             } 392         } 393     } 394  395     @Override 396     protected void dispatchDraw(Canvas canvas) { 397         super.dispatchDraw(canvas); 398  399         if (mPinnedSection != null) { 400  401             // prepare variables 402             int pLeft = getListPaddingLeft(); 403             int pTop = getListPaddingTop(); 404             View view = mPinnedSection.view; 405  406             // draw child 407             canvas.save(); 408  409             int clipHeight = view.getHeight() + 410                     (mShadowDrawable == null ? 0 : Math.min(mShadowHeight, mSectionsDistanceY)); 411             canvas.clipRect(pLeft, pTop, pLeft + view.getWidth(), pTop + clipHeight); 412  413             canvas.translate(pLeft, pTop + mTranslateY); 414             drawChild(canvas, mPinnedSection.view, getDrawingTime()); 415  416             if (mShadowDrawable != null && mSectionsDistanceY > 0) { 417                 mShadowDrawable.setBounds(mPinnedSection.view.getLeft(), 418                         mPinnedSection.view.getBottom(), 419                         mPinnedSection.view.getRight(), 420                         mPinnedSection.view.getBottom() + mShadowHeight); 421                 mShadowDrawable.draw(canvas); 422             } 423  424             canvas.restore(); 425         } 426     } 427  428     //-- touch handling methods 429  430     @Override 431     public boolean dispatchTouchEvent(MotionEvent ev) { 432  433         final float x = ev.getX(); 434         final float y = ev.getY(); 435         final int action = ev.getAction(); 436  437         if (action == MotionEvent.ACTION_DOWN 438                 && mTouchTarget == null 439                 && mPinnedSection != null 440                 && isPinnedViewTouched(mPinnedSection.view, x, y)) { // create touch target 441  442             // user touched pinned view 443             mTouchTarget = mPinnedSection.view; 444             mTouchPoint.x = x; 445             mTouchPoint.y = y; 446  447             // copy down event for eventually be used later 448             mDownEvent = MotionEvent.obtain(ev); 449         } 450  451         if (mTouchTarget != null) { 452             if (isPinnedViewTouched(mTouchTarget, x, y)) { // forward event to pinned view 453                 mTouchTarget.dispatchTouchEvent(ev); 454             } 455  456             if (action == MotionEvent.ACTION_UP) { // perform onClick on pinned view 457                 super.dispatchTouchEvent(ev); 458                 performPinnedItemClick(); 459                 clearTouchTarget(); 460  461             } else if (action == MotionEvent.ACTION_CANCEL) { // cancel 462                 clearTouchTarget(); 463  464             } else if (action == MotionEvent.ACTION_MOVE) { 465                 if (Math.abs(y - mTouchPoint.y) > mTouchSlop) { 466  467                     // cancel sequence on touch target 468                     MotionEvent event = MotionEvent.obtain(ev); 469                     event.setAction(MotionEvent.ACTION_CANCEL); 470                     mTouchTarget.dispatchTouchEvent(event); 471                     event.recycle(); 472  473                     // provide correct sequence to super class for further handling 474                     super.dispatchTouchEvent(mDownEvent); 475                     super.dispatchTouchEvent(ev); 476                     clearTouchTarget(); 477  478                 } 479             } 480  481             return true; 482         } 483  484         // call super if this was not our pinned view 485         return super.dispatchTouchEvent(ev); 486     } 487  488     private boolean isPinnedViewTouched(View view, float x, float y) { 489         view.getHitRect(mTouchRect); 490  491         // by taping top or bottom padding, the list performs on click on a border item. 492         // we don't add top padding here to keep behavior consistent. 493         mTouchRect.top += mTranslateY; 494  495         mTouchRect.bottom += mTranslateY + getPaddingTop(); 496         mTouchRect.left += getPaddingLeft(); 497         mTouchRect.right -= getPaddingRight(); 498         return mTouchRect.contains((int)x, (int)y); 499     } 500  501     private void clearTouchTarget() { 502         mTouchTarget = null; 503         if (mDownEvent != null) { 504             mDownEvent.recycle(); 505             mDownEvent = null; 506         } 507     } 508  509     private boolean performPinnedItemClick() { 510         if (mPinnedSection == null) return false; 511  512         OnItemClickListener listener = getOnItemClickListener(); 513         if (listener != null && getAdapter().isEnabled(mPinnedSection.position)) { 514             View view =  mPinnedSection.view; 515             playSoundEffect(SoundEffectConstants.CLICK); 516             if (view != null) { 517                 view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 518             } 519             listener.onItemClick(this, view, mPinnedSection.position, mPinnedSection.id); 520             return true; 521         } 522         return false; 523     } 524  525     public static boolean isItemViewTypePinned(ListAdapter adapter, int viewType) { 526         if (adapter instanceof HeaderViewListAdapter) { 527             adapter = ((HeaderViewListAdapter)adapter).getWrappedAdapter(); 528         } 529         return ((PinnedSectionListAdapter) adapter).isItemViewTypePinned(viewType); 530     } 531  532 }  PinnedSectionListView.java
正文到此结束
Loading...