編輯:關於Android編程
上一篇《Android自定義組件系列【6】——進階實踐(3)》中補充了關於Android中事件分發的過程知識,這一篇我們接著來分析任老師的《可下拉的PinnedHeaderExpandableListView的實現》。
一、StickyLayout中的OnGiveUpTouchEventListener接口的作用是什麼?
public interface OnGiveUpTouchEventListener { public boolean giveUpTouchEvent(MotionEvent event); }在StickyLayout中還提供了設置監聽的方法如下:
public void setOnGiveUpTouchEventListener(OnGiveUpTouchEventListener l) { mGiveUpTouchEventListener = l; }這種方式其實是一種鉤子方法,在OnGiveUpTouchEventListener中定義了一個抽象方法(未具體實現)giveUpTouchEvent.,然後通過MainActivity繼承OnGiveUpTouchEventListener接口來實現具體邏輯。
@Override public boolean giveUpTouchEvent(MotionEvent event) { if (expandableListView.getFirstVisiblePosition() == 0) { View view = expandableListView.getChildAt(0); if (view != null && view.getTop() >= 0) { return true; } } return false; }這個方法中的邏輯:取到ExpandableListView中的第一個可見項,如果是它的子View中的第一個則說明現在首先應該滑動上面的Header部分(讓其展開)。
這裡返回的true和false有什麼不同呢?向下看
@Override public boolean onInterceptTouchEvent(MotionEvent event) { int intercepted = 0; int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { mLastXIntercept = x; mLastYIntercept = y; mLastX = x; mLastY = y; intercepted = 0; break; } case MotionEvent.ACTION_MOVE: { int deltaX = x - mLastXIntercept; int deltaY = y - mLastYIntercept; if (mStatus == STATUS_EXPANDED && deltaY <= -mTouchSlop) { intercepted = 1; } else if (mGiveUpTouchEventListener != null) { if (mGiveUpTouchEventListener.giveUpTouchEvent(event) && deltaY >= mTouchSlop) { intercepted = 1; } } break; } case MotionEvent.ACTION_UP: { intercepted = 0; mLastXIntercept = mLastYIntercept = 0; break; } default: break; } Log.d(TAG, intercepted= + intercepted); return intercepted != 0; }在StickyLayout類中的事件攔截方法的ACTION_MOVE中有這麼幾句代碼:
if (mStatus == STATUS_EXPANDED && deltaY <= -mTouchSlop) { intercepted = 1; } else if (mGiveUpTouchEventListener != null) { if (mGiveUpTouchEventListener.giveUpTouchEvent(event) && deltaY >= mTouchSlop) { intercepted = 1; } }現在應該明白了吧,呵呵。STATUS_EXPANDED是一個狀態值,意思是現在Header部分是展開的,如果Header部分是收起的則會判斷giveUpTouchEvent的返回值,如果giveUpTouchEvent返回true說明列表全部被拉下來了,此時應該將Header部分展開。如果返回false則應該下滑列表而不是展開Header部分。
二、PinnedHeaderExpandableListView對OnScrollLister的實現
@Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (mHeaderView != null && scrollState == SCROLL_STATE_IDLE) { int firstVisiblePos = getFirstVisiblePosition(); if (firstVisiblePos == 0) { mHeaderView.layout(0, 0, mHeaderWidth, mHeaderHeight); } } if (mScrollListener != null) { mScrollListener.onScrollStateChanged(view, scrollState); } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (totalItemCount > 0) { refreshHeader(); } if (mScrollListener != null) { mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); } }OnScrollListener是ListView的滾動事件。
在onScrollStateChanged(AbsListView view, int scrollState)中,scrollState有三種狀態,分別是:
1、SCROLL_STATE_FLING:開始滾動
2、SCROLL_STATE_TOUCH_SCROLL:正在滾動
3、SCROLL_STATE_IDLE:已經停止
onScroll()方法在列表滾動時一直回調,知道滾動停止才停止回調,另外單擊時也回調一次。而OnScrollStateChanged的意思是上面三種狀態改變時回調,回調順序如下:
protected void refreshHeader() { if (mHeaderView == null) { return; } int firstVisiblePos = getFirstVisiblePosition(); int pos = firstVisiblePos + 1; int firstVisibleGroupPos = getPackedPositionGroup(getExpandableListPosition(firstVisiblePos)); int group = getPackedPositionGroup(getExpandableListPosition(pos)); if (group == firstVisibleGroupPos + 1) { View view = getChildAt(1); if (view.getTop() <= mHeaderHeight) { int delta = mHeaderHeight - view.getTop(); mHeaderView.layout(0, -delta, mHeaderWidth, mHeaderHeight - delta); } } else { mHeaderView.layout(0, 0, mHeaderWidth, mHeaderHeight); } if (mHeaderUpdateListener != null) { mHeaderUpdateListener.updatePinnedHeader(firstVisibleGroupPos); } }refreshHeader()方法中可以看到,先判斷上面的是不是多個列表頭如果是則重新設置下面列表頭的位置到“標准位置”,這樣就感覺有一種頂上去的感覺了。
@Override public boolean dispatchTouchEvent(MotionEvent ev) { int x = (int) ev.getX(); int y = (int) ev.getY(); Log.d(TAG, dispatchTouchEvent); int pos = pointToPosition(x, y); if (y >= mHeaderView.getTop() && y <= mHeaderView.getBottom()) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { mActionDownHappened = true; } else if (ev.getAction() == MotionEvent.ACTION_UP) { int groupPosition = getPackedPositionGroup(getExpandableListPosition(pos)); if (groupPosition != INVALID_POSITION && mActionDownHappened) { if (isGroupExpanded(groupPosition)) { collapseGroup(groupPosition); } else { expandGroup(groupPosition); } mActionDownHappened = false; } } return true; } return super.dispatchTouchEvent(ev); }可以看到PinnedHeaderExpandableListView中的事件分發函數中有如下代碼:
if (y >= mHeaderView.getTop() && y <= mHeaderView.getBottom())限制高度(在列表頭位置)
if (isGroupExpanded(groupPosition)) { collapseGroup(groupPosition); } else { expandGroup(groupPosition); }
JSON定義:JSON(JavaScript Object Notation) 是一種輕量級的數據交換格式。它基於JavaScript(Standard ECMA-262
Service概念及用途:Android中的服務,它與Activity不同,它是不能與用戶交互的,不能自己啟動的,運行在後台的程序,如果我們退出應用時,Service進程
ViewPage使用之一就是輪播廣告,就以此為出發點,來詳細解析一下ViewPage的使用和加載機制。首先直接上一個damo,在代碼中我也直接給出了詳細的解釋。然後,再在
因為Android的編譯系統不同於Linux Kernel的遞歸式的編譯系統,它的編譯系統是一種稱之為independent的模式,每個模塊基本獨立(它有可能依賴其他模塊