Advertisement
Guest User

Horizontal ListView class

a guest
Jan 5th, 2014
325
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 26.77 KB | None | 0 0
  1. HORIZONTL LISTVIEW CLASS
  2.  
  3. /**
  4. * The MIT License (MIT)
  5. * Copyright (c) 2012 Tang Yu Software Corporation
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy
  8. * of this software and associated documentation files (the "Software"), to deal
  9. * in the Software without restriction, including without limitation the rights
  10. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. * copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in all
  15. * copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  23. * SOFTWARE.
  24. */
  25. package com.example.lc5plus;
  26.  
  27. import java.util.LinkedList;
  28. import java.util.Queue;
  29.  
  30. import android.content.Context;
  31. import android.database.DataSetObserver;
  32. import android.graphics.Rect;
  33. import android.util.AttributeSet;
  34. import android.view.GestureDetector;
  35. import android.view.GestureDetector.OnGestureListener;
  36. import android.view.Gravity;
  37. import android.view.MotionEvent;
  38. import android.view.View;
  39. import android.view.ViewGroup;
  40. import android.widget.AdapterView;
  41. import android.widget.LinearLayout;
  42. import android.widget.ListAdapter;
  43. import android.widget.Scroller;
  44.  
  45. /**
  46. * Base on dinocore1 source code.
  47. * https://github.com/dinocore1/DevsmartLib-Android/tree/master/demo/src/com/devsmart/demo <br>
  48. * In my practice, i get into trouble on dynamic loading, select to special item ,scrolling listener and so on. <br>
  49. * So i decide to solve the problems.
  50. * e.. i change the license. i don't known it's a right choice.
  51. * @author bin
  52. */
  53. public class HorizontalListView extends AdapterView<ListAdapter> {
  54.  
  55. /**
  56. * Regular layout - usually an unsolicited layout from the view system
  57. */
  58. static final int LAYOUT_NORMAL = 0x00;
  59.  
  60. /**
  61. * Make a mSelectedItem appear in a specific location and build the rest of
  62. * the views from there. The top is specified by mSpecificTop.
  63. */
  64. static final int LAYOUT_SPECIFIC = 0x04;
  65.  
  66. static final int LAYOUT_FREEZE = 0x08;
  67.  
  68. /**
  69. * Controls how the next layout will happen
  70. */
  71. int mLayoutMode = LAYOUT_NORMAL;
  72.  
  73.  
  74. public boolean mAlwaysOverrideTouch = true;
  75.  
  76. protected ListAdapter mAdapter;
  77. protected Scroller mScroller;
  78. private GestureDetector mGesture;
  79.  
  80. private int mLeftViewIndex = -1;
  81. private int mRightViewIndex = 0;
  82.  
  83. private int mMaxX = Integer.MAX_VALUE;
  84. private int mMinX = Integer.MIN_VALUE;
  85. protected int mCurrentX;
  86. protected int mNextX;
  87. private int mDisplayOffset = 0;
  88.  
  89. private Queue<View> mRemovedViewQueue = new LinkedList<View>();
  90.  
  91. private OnItemSelectedListener mOnItemSelected;
  92. private OnItemClickListener mOnItemClicked;
  93. private OnItemLongClickListener mOnItemLongClicked;
  94. private OnScrollListener mOnScrolled;
  95.  
  96. private boolean mDataChanged = false;
  97.  
  98. private int mFirstPosition = 0;
  99.  
  100. public HorizontalListView(Context context, AttributeSet attrs) {
  101. super(context, attrs);
  102. initView();
  103. }
  104.  
  105. private synchronized void initView() {
  106. mLeftViewIndex = -1;
  107. mRightViewIndex = 0;
  108. mDisplayOffset = 0;
  109. mCurrentX = 0;
  110. mNextX = 0;
  111. mFirstPosition = 0;
  112. mSpecificPosition = 0;
  113. mSpecificLeft = 0;
  114. mMaxX = Integer.MAX_VALUE;
  115. mMinX = Integer.MIN_VALUE;
  116. mScroller = new Scroller(getContext());
  117. if (!isInEditMode()) {
  118. mGesture = new GestureDetector(getContext(), mOnGesture);
  119. }
  120. }
  121.  
  122. private synchronized void initViewForSpecific() {
  123. mLeftViewIndex = mSpecificPosition - 1;
  124. mRightViewIndex = mSpecificPosition + 1;
  125. mFirstPosition = mSpecificPosition;
  126. mDisplayOffset = 0;
  127. mCurrentX = 0;
  128. mNextX = 0;
  129. mMaxX = Integer.MAX_VALUE;
  130. mMinX = Integer.MIN_VALUE;
  131. if (!isInEditMode()) {
  132. mGesture = new GestureDetector(getContext(), mOnGesture);
  133. }
  134. }
  135.  
  136. @Override
  137. public void setOnItemSelectedListener(
  138. OnItemSelectedListener listener) {
  139. mOnItemSelected = listener;
  140. }
  141.  
  142. @Override
  143. public void setOnItemClickListener(OnItemClickListener listener) {
  144. mOnItemClicked = listener;
  145. }
  146.  
  147. @Override
  148. public void setOnItemLongClickListener(
  149. OnItemLongClickListener listener) {
  150. mOnItemLongClicked = listener;
  151. }
  152.  
  153. public void setOnScrollListener(OnScrollListener listener) {
  154. mOnScrolled = listener;
  155. }
  156.  
  157. private DataSetObserver mDataObserver = new DataSetObserver() {
  158.  
  159. @Override
  160. public void onChanged() {
  161. synchronized (HorizontalListView.this) {
  162. mDataChanged = true;
  163. }
  164. invalidate();
  165. requestLayout();
  166. }
  167.  
  168. @Override
  169. public void onInvalidated() {
  170. reset();
  171. invalidate();
  172. requestLayout();
  173. }
  174.  
  175. };
  176.  
  177. private int mSpecificLeft;
  178.  
  179. private int mSpecificPosition;
  180.  
  181. private int mScrollStatus;
  182.  
  183. private boolean mIsCancelOrUp;
  184.  
  185. private boolean mIsLayoutDirty;
  186.  
  187. private int mFreezePosInAdapter = -1;
  188.  
  189. private View mFreezeChild;
  190.  
  191. private int mSpecificOldPosition;
  192.  
  193. private int mSpecificOldLeft;
  194.  
  195. @Override
  196. public ListAdapter getAdapter() {
  197. return mAdapter;
  198. }
  199.  
  200. @Override
  201. public View getSelectedView() {
  202. return getChildAt(mSpecificPosition - getFirstVisiblePosition());
  203. }
  204.  
  205. @Override
  206. public void setAdapter(ListAdapter adapter) {
  207. if (mAdapter != null) {
  208. mAdapter.unregisterDataSetObserver(mDataObserver);
  209. }
  210. mAdapter = adapter;
  211. mAdapter.registerDataSetObserver(mDataObserver);
  212. mDataChanged = true;
  213. requestLayout();
  214. // reset();
  215. }
  216.  
  217. private synchronized void reset() {
  218. initView();
  219. removeAllViewsInLayout();
  220. requestLayout();
  221. }
  222.  
  223. @Override
  224. public int getFirstVisiblePosition() {
  225. return mFirstPosition;
  226. }
  227.  
  228. @Override
  229. public int getLastVisiblePosition() {
  230. return mFirstPosition + getChildCount() - 1;
  231. }
  232.  
  233. @Override
  234. public void setSelection(int position) {
  235. setSelectionFromLeft(position, 0);
  236. }
  237.  
  238. /**
  239. * Sets the selected item and positions the selection y pixels from the left edge
  240. * of the ListView. (If in touch mode, the item will not be selected but it will
  241. * still be positioned appropriately.)
  242. *
  243. * @param position Index (starting at 0) of the data item to be selected.
  244. * @param x The distance from the left edge of the ListView (plus padding) that the
  245. * item will be positioned.
  246. */
  247. public void setSelectionFromLeft(int position, int x) {
  248. if (setSelectionFrom(position, x) >= 0) {
  249. requestLayout();
  250. }
  251. }
  252.  
  253. private int setSelectionFrom(int position, int x) {
  254. if (mAdapter == null) return -1;
  255. if (position < 0 || position >= mAdapter.getCount()) return -1;
  256.  
  257. if (!isInTouchMode()) {
  258. position = lookForSelectablePosition(position, true);
  259. }
  260.  
  261. if (position >= 0) {
  262. mLayoutMode |= LAYOUT_SPECIFIC;
  263. mSpecificPosition = position;
  264. mSpecificLeft = getPaddingLeft() + x;
  265. }
  266. return position;
  267. }
  268.  
  269. private boolean isAllowSelectionOnShown(int position, int delta) {
  270. final int deltaPos = position - getFirstVisiblePosition();
  271.  
  272. if (getChildCount() == 0) return false;
  273. if (deltaPos < 0 || deltaPos >= getChildCount()) {
  274. //out of show child.
  275. return false;
  276. }
  277.  
  278. View posView = getChildAt(position - getFirstVisiblePosition());
  279.  
  280. if (posView.getRight() + delta < 0 ||
  281. posView.getLeft() + delta > getMeasuredWidth()) {
  282. return false;
  283. }
  284. return true;
  285. }
  286.  
  287. /**
  288. * has setSelection request.
  289. * @return true is to select. otherwise is not.
  290. * @see #setSelection(int)
  291. * @see #setSelectionFromLeft(int, int)
  292. */
  293. public boolean isLayoutRequestedBySelection() {
  294. return Util.isFlagContain(mLayoutMode, LAYOUT_SPECIFIC);
  295. }
  296.  
  297. @Override
  298. public void requestLayout() {
  299. mIsLayoutDirty = true;
  300. super.requestLayout();
  301. }
  302.  
  303. /**
  304. * request freeze a child. usually to keep current child position on refresh data action which will be change data position.
  305. * @param child
  306. * @param posInAdapter
  307. */
  308. public void requestChildFreeze(View child, int posInAdapter) {
  309. mLayoutMode |= LAYOUT_FREEZE;
  310. if (!mIsLayoutDirty) {
  311. setSelectionFromLeft(posInAdapter, child.getLeft());
  312. } else {
  313. mFreezeChild = child;
  314. mFreezePosInAdapter = posInAdapter;
  315. }
  316. }
  317.  
  318. /**
  319. * has freeze request.
  320. * @return true is to freeze. otherwise is not.
  321. * @see #requestChildFreeze(android.view.View, int)
  322. */
  323. public boolean isLayoutRequestByFreeze() {
  324. return Util.isFlagContain(mLayoutMode, LAYOUT_FREEZE);
  325. }
  326.  
  327. /**
  328. * Find a position that can be selected (i.e., is not a separator).
  329. *
  330. * @param position The starting position to look at.
  331. * @param lookDown Whether to look down for other positions.
  332. * @return The next selectable position starting at position and then searching either up or
  333. * down. Returns {@link #INVALID_POSITION} if nothing can be found.
  334. */
  335. private int lookForSelectablePosition(int position, boolean lookDown) {
  336. final ListAdapter adapter = mAdapter;
  337. if (adapter == null || isInTouchMode()) {
  338. return INVALID_POSITION;
  339. }
  340.  
  341. final int count = adapter.getCount();
  342. if (!adapter.areAllItemsEnabled()) {
  343. if (lookDown) {
  344. position = Math.max(0, position);
  345. while (position < count && !adapter.isEnabled(position)) {
  346. position++;
  347. }
  348. } else {
  349. position = Math.min(position, count - 1);
  350. while (position >= 0 && !adapter.isEnabled(position)) {
  351. position--;
  352. }
  353. }
  354.  
  355. if (position < 0 || position >= count) {
  356. return INVALID_POSITION;
  357. }
  358. return position;
  359. } else {
  360. if (position < 0 || position >= count) {
  361. return INVALID_POSITION;
  362. }
  363. return position;
  364. }
  365. }
  366.  
  367. private void addAndMeasureChild(final View child, int viewPos) {
  368. LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) child.getLayoutParams();
  369. if (params == null) {
  370. params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
  371. //params.weight = 1.0f;
  372. params.gravity = Gravity.RIGHT;
  373.  
  374. }
  375.  
  376. addViewInLayout(child, viewPos, params, true);
  377.  
  378. int heightMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(),
  379. MeasureSpec.EXACTLY);
  380. int childHeightSpec = ViewGroup.getChildMeasureSpec(heightMeasureSpec,
  381. getPaddingTop() + getPaddingBottom(), params.height);
  382. int childWidthSpec = 0;
  383. if (params.width == LayoutParams.MATCH_PARENT) {
  384. childWidthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(),
  385. MeasureSpec.EXACTLY);
  386. } else if (params.width == LayoutParams.WRAP_CONTENT) {
  387. childWidthSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
  388. } else {
  389. childWidthSpec = MeasureSpec.makeMeasureSpec(params.width, MeasureSpec.EXACTLY);
  390. }
  391. child.measure(childWidthSpec, childHeightSpec);
  392.  
  393. }
  394.  
  395. @Override
  396. protected void onLayout(boolean changed, int left, int top,
  397. int right, int bottom) {
  398. super.onLayout(changed, left, top, right, bottom);
  399.  
  400. if (mAdapter == null) {
  401. return;
  402. }
  403.  
  404. if (isLayoutRequestByFreeze()) {
  405. mLayoutMode &= ~LAYOUT_FREEZE;
  406. if (mIsLayoutDirty) {
  407. mFirstPosition = mFreezePosInAdapter;
  408. Util.v("Freeze pos = " + mFreezePosInAdapter);
  409. Util.v("Freeze left = " + (mFreezeChild == null ? 0 : mFreezeChild.getLeft()));
  410. setSelectionFrom(mFreezePosInAdapter, (mFreezeChild == null ? 0 : mFreezeChild.getLeft()));
  411. }
  412. }
  413.  
  414. if (mIsLayoutDirty) mIsLayoutDirty = false;
  415.  
  416. if (mDataChanged) {
  417. if (isLayoutRequestedBySelection()) {
  418. initViewForSpecific();
  419. } else {
  420. int oldCurrentX = mCurrentX;
  421. initView();
  422. removeAllViewsInLayout();
  423. mNextX = oldCurrentX;
  424. }
  425. mDataChanged = false;
  426. }
  427.  
  428. if (mScroller.computeScrollOffset()) {
  429. int scrollx = mScroller.getCurrX();
  430. mNextX = scrollx;
  431. }
  432.  
  433. if (mNextX <= mMinX) {
  434. mNextX = mMinX;
  435. mScroller.forceFinished(true);
  436. }
  437. if (mNextX >= mMaxX) {
  438. mNextX = mMaxX;
  439. mScroller.forceFinished(true);
  440. }
  441.  
  442. int dx = 0;
  443. if (Util.isFlagContain(mLayoutMode, LAYOUT_SPECIFIC)) {
  444. removeAllViewsInLayout();
  445. initViewForSpecific();
  446.  
  447. fillSpecificV2(mSpecificPosition, mSpecificLeft);
  448. positionItems(mSpecificLeft);
  449.  
  450. if (mScroller.computeScrollOffset()) {
  451. int finalX = mScroller.getFinalX();
  452. finalX = Math.min(finalX, mMaxX);
  453. finalX = Math.max(finalX, mMinX);
  454. mScroller.setFinalX(finalX);
  455. }
  456.  
  457. mLayoutMode &= ~LAYOUT_SPECIFIC;
  458. } else {
  459. dx = mCurrentX - mNextX;
  460. removeNonVisibleItems(dx);
  461. fillList(dx);
  462. positionItems(dx);
  463.  
  464. if (mMinX == 0 || mMaxX == 0) {
  465. mNextX = mCurrentX;
  466. if (!mScroller.isFinished()) {
  467. mScroller.forceFinished(true);
  468. }
  469. }
  470. }
  471.  
  472. mCurrentX = mNextX;
  473.  
  474. if (!mScroller.isFinished()) {
  475. post(new Runnable() {
  476.  
  477. @Override
  478. public void run() {
  479. requestLayout();
  480. }
  481. });
  482. } else {
  483. reportScroll(OnScrollListener.SCROLL_IDLE);
  484. reportScrollState(OnScrollListener.SCROLL_IDLE);
  485. }
  486. }
  487.  
  488. private void fillList(final int dx) {
  489. int edge = 0;
  490. View child = getChildAt(getChildCount() - 1);
  491. if (child != null) {
  492. edge = child.getRight();
  493. }
  494. fillListRight(edge, dx);
  495.  
  496. edge = 0;
  497. child = getChildAt(0);
  498. if (child != null) {
  499. edge = child.getLeft();
  500. }
  501. fillListLeft(edge, dx);
  502. }
  503.  
  504. private void fillSpecificV2(int position, int delta) {
  505. View child = mAdapter.getView(position, mRemovedViewQueue.poll(), this);
  506. if (child == null) return;
  507. addAndMeasureChild(child, -1);
  508.  
  509. if (child != null) {
  510.  
  511. int leftEdge = delta, rightEdge = delta + child.getMeasuredWidth();
  512. if (leftEdge + child.getMeasuredWidth() < 0 || rightEdge > getMeasuredWidth()) {
  513. mSpecificLeft = 0;
  514. leftEdge = 0;
  515. rightEdge = child.getMeasuredWidth();
  516. }
  517.  
  518. fillListRight(rightEdge, 0);
  519. int widthDelta = getMeasuredWidth() - getChildrenWidth(0, getChildCount()) - leftEdge;
  520. int childCountAfterFillRight = getChildCount();
  521. if (widthDelta > 0) {
  522. // move to right edge if not fill right screen.
  523. leftEdge += widthDelta;
  524. mSpecificLeft += widthDelta;
  525. }
  526. fillListLeft(leftEdge, 0);
  527. widthDelta = leftEdge - getChildrenWidth(0, getChildCount() - childCountAfterFillRight);
  528. if (widthDelta > 0) {
  529. // move to left edge if not fill left screen.
  530. mSpecificLeft -= widthDelta;
  531. }
  532. }
  533. }
  534.  
  535. int getChildrenWidth(int start, int end) {
  536. int allWidth = 0;
  537. for (int i = start; i < end; i++) {
  538. allWidth += getChildAt(i).getMeasuredWidth();
  539. }
  540. return allWidth;
  541. }
  542.  
  543. private void fillListRight(int rightEdge, final int dx) {
  544. if (mRightViewIndex >= mAdapter.getCount()) {
  545. mMaxX = mCurrentX + rightEdge - getWidth();
  546. }
  547. while (rightEdge + dx < getWidth()
  548. && mRightViewIndex < mAdapter.getCount()) {
  549.  
  550. View child = mAdapter.getView(mRightViewIndex,
  551. mRemovedViewQueue.poll(), this);
  552. addAndMeasureChild(child, -1);
  553. rightEdge += child.getMeasuredWidth();
  554.  
  555. if (mRightViewIndex == mAdapter.getCount() - 1) {
  556. mMaxX = mCurrentX + rightEdge - getWidth();
  557. }
  558.  
  559. mRightViewIndex++;
  560. }
  561. if (mMaxX < 0) mMaxX = 0;
  562. }
  563.  
  564. private void fillListLeft(int leftEdge, final int dx) {
  565. if (mLeftViewIndex < 0) {
  566. mMinX = mCurrentX + leftEdge;
  567. }
  568. while (leftEdge + dx > 0 && mLeftViewIndex >= 0) {
  569. View child = mAdapter.getView(mLeftViewIndex,
  570. mRemovedViewQueue.poll(), this);
  571. addAndMeasureChild(child, 0);
  572. leftEdge -= child.getMeasuredWidth();
  573. if (mLeftViewIndex == 0) {
  574. mMinX = mCurrentX + leftEdge;
  575. }
  576. mLeftViewIndex--;
  577. mDisplayOffset -= child.getMeasuredWidth();
  578. }
  579. if (mMinX > 0) mMinX = 0;
  580. mFirstPosition = mLeftViewIndex + 1;
  581. }
  582.  
  583. private void removeNonVisibleItems(final int dx) {
  584. View child = getChildAt(0);
  585. while (child != null && child.getRight() + dx <= 0) {
  586. mDisplayOffset += child.getMeasuredWidth();
  587. mRemovedViewQueue.offer(child);
  588. removeViewInLayout(child);
  589. mLeftViewIndex++;
  590. child = getChildAt(0);
  591. }
  592.  
  593. child = getChildAt(getChildCount() - 1);
  594. while (child != null && child.getLeft() + dx >= getWidth()) {
  595. mRemovedViewQueue.offer(child);
  596. removeViewInLayout(child);
  597. mRightViewIndex--;
  598. child = getChildAt(getChildCount() - 1);
  599. }
  600. }
  601.  
  602. private void positionItems(final int dx) {
  603. if (getChildCount() > 0) {
  604. mDisplayOffset += dx;
  605. int left = mDisplayOffset;
  606. for (int i = 0; i < getChildCount(); i++) {
  607. View child = getChildAt(i);
  608. int childWidth = child.getMeasuredWidth();
  609. child.layout(left, 0, left + childWidth,
  610. child.getMeasuredHeight());
  611. left += childWidth;
  612. }
  613. }
  614. }
  615.  
  616. /**
  617. * scroll to parameter x
  618. * @param x the destiny
  619. */
  620. public synchronized void scrollTo(int x) {
  621. mScroller.startScroll(mNextX, 0, x - mNextX, 0);
  622. requestLayout();
  623. }
  624.  
  625. @Override
  626. public boolean dispatchTouchEvent(MotionEvent ev) {
  627. boolean handled = super.dispatchTouchEvent(ev);
  628. handled |= mGesture.onTouchEvent(ev);
  629. mIsCancelOrUp = ev.getAction() == MotionEvent.ACTION_CANCEL ||
  630. ev.getAction() == MotionEvent.ACTION_UP ? true : false;
  631. return handled;
  632. }
  633.  
  634. public boolean isScrollFinish() {
  635. return mScroller.isFinished() && mIsCancelOrUp;
  636. }
  637.  
  638. public boolean isCancelOrUpNow() {
  639. return mIsCancelOrUp;
  640. }
  641.  
  642. void reportScroll(int status) {
  643. if (!Util.isNull(mOnScrolled) && status != mScrollStatus) {
  644. final int first = getFirstVisiblePosition();
  645. final int visibleCount = getLastVisiblePosition() - first;
  646. final int count = mAdapter.getCount();
  647. mOnScrolled.onScroll(this, first, visibleCount, count);
  648. }
  649. }
  650.  
  651. void reportScrollState(int status) {
  652. if (!Util.isNull(mOnScrolled) && status != mScrollStatus) {
  653. mScrollStatus = status;
  654. mOnScrolled.onScrollStateChanged(this, status);
  655. }
  656. }
  657.  
  658. protected boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
  659. float velocityY) {
  660. synchronized (HorizontalListView.this) {
  661. reportScrollState(OnScrollListener.SCROLL_FLING);
  662. mScroller.fling(mNextX, 0, (int) -velocityX, 0, mMinX, mMaxX, 0, 0);
  663. mScroller.computeScrollOffset();
  664. }
  665. requestLayout();
  666.  
  667. return true;
  668. }
  669.  
  670. protected boolean onDown(MotionEvent e) {
  671. mScroller.forceFinished(true);
  672. reportScrollState(OnScrollListener.SCROLL_IDLE);
  673. return true;
  674. }
  675.  
  676. protected boolean onScroll(MotionEvent e1, MotionEvent e2,
  677. float distanceX, float distanceY) {
  678. synchronized (HorizontalListView.this) {
  679. reportScrollState(OnScrollListener.SCROLL_TOUCH_SCROLL);
  680. // get big value when freeze. so keep it small.
  681. if (Math.abs((int) distanceX) > 30) {
  682. mNextX += distanceX > 0 ? 1 : -1;
  683. } else {
  684. mNextX += (int) distanceX;
  685. }
  686. }
  687. requestLayout();
  688.  
  689. return true;
  690. }
  691.  
  692. private OnGestureListener mOnGesture = new GestureDetector.SimpleOnGestureListener() {
  693.  
  694. @Override
  695. public boolean onDown(MotionEvent e) {
  696. return HorizontalListView.this.onDown(e);
  697. }
  698.  
  699. @Override
  700. public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
  701. float velocityY) {
  702. return HorizontalListView.this
  703. .onFling(e1, e2, velocityX, velocityY);
  704. }
  705.  
  706. @Override
  707. public boolean onScroll(MotionEvent e1, MotionEvent e2,
  708. float distanceX, float distanceY) {
  709. return HorizontalListView.this.onScroll(e1, e2, distanceX, distanceY);
  710. }
  711.  
  712. @Override
  713. public boolean onSingleTapConfirmed(MotionEvent e) {
  714. for (int i = 0; i < getChildCount(); i++) {
  715. View child = getChildAt(i);
  716. if (isEventWithinView(e, child)) {
  717. if (mOnItemClicked != null) {
  718. mOnItemClicked.onItemClick(HorizontalListView.this,
  719. child, mLeftViewIndex + 1 + i,
  720. mAdapter.getItemId(mLeftViewIndex + 1 + i));
  721. }
  722. if (mOnItemSelected != null) {
  723. mOnItemSelected.onItemSelected(HorizontalListView.this,
  724. child, mLeftViewIndex + 1 + i,
  725. mAdapter.getItemId(mLeftViewIndex + 1 + i));
  726. }
  727. break;
  728. }
  729.  
  730. }
  731. return true;
  732. }
  733.  
  734. @Override
  735. public void onLongPress(MotionEvent e) {
  736. int childCount = getChildCount();
  737. for (int i = 0; i < childCount; i++) {
  738. View child = getChildAt(i);
  739. if (isEventWithinView(e, child)) {
  740. if (mOnItemLongClicked != null) {
  741. mOnItemLongClicked.onItemLongClick(
  742. HorizontalListView.this, child, mLeftViewIndex
  743. + 1 + i,
  744. mAdapter.getItemId(mLeftViewIndex + 1 + i));
  745. }
  746. break;
  747. }
  748. }
  749. }
  750.  
  751. private boolean isEventWithinView(MotionEvent e, View child) {
  752. Rect viewRect = new Rect();
  753. int[] childPosition = new int[2];
  754. child.getLocationOnScreen(childPosition);
  755. int left = childPosition[0];
  756. int right = left + child.getWidth();
  757. int top = childPosition[1];
  758. int bottom = top + child.getHeight();
  759. viewRect.set(left, top, right, bottom);
  760. return viewRect.contains((int) e.getRawX(), (int) e.getRawY());
  761. }
  762. };
  763.  
  764. public static interface OnScrollListener {
  765.  
  766. public final static int SCROLL_IDLE = 0;
  767. public final static int SCROLL_TOUCH_SCROLL = 1;
  768. public final static int SCROLL_FLING = 2;
  769.  
  770. /**
  771. * Callback method to be invoked while the list view is being scrolled or flown. If the
  772. * view is being scrolled, this method will be called before the next frame of the scroll is
  773. * rendered. if it's being flying, it will be invoked at flying finish.</br>
  774. * In particular, it will be called before any calls to
  775. * {@link android.widget.BaseAdapter#getView(int, android.view.View, android.view.ViewGroup)}.
  776. *
  777. * @param view The view whose scroll state is being reported
  778. * @param status The current scroll state. One of {@link #SCROLL_IDLE},
  779. * {@link #SCROLL_TOUCH_SCROLL} or {@link #SCROLL_FLING}.
  780. */
  781. void onScrollStateChanged(AdapterView<?> view, int status);
  782.  
  783. /**
  784. * Callback method to be invoked when the list has been scrolled or flown. This will be
  785. * called after the scroll or fly has completed
  786. *
  787. * @param view The view whose scroll state is being reported
  788. * @param firstVisibleItem the index of the first visible cell (ignore if
  789. * visibleItemCount == 0)
  790. * @param visibleItemCount the number of visible cells
  791. * @param totalItemCount the number of items in the list adaptor
  792. */
  793. public void onScroll(AdapterView<?> view, int firstVisibleItem, int visibleItemCount,
  794. int totalItemCount);
  795. }
  796.  
  797. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement