Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 高級開發 >> android ListView使用實例

android ListView使用實例

編輯:高級開發

 Java代碼

  /*

  * Copyright (C) 2006 The android Open Source Project

  *

  * Licensed under the apache License, Version 2.0 (the "License");

  * you may not use this file except in compliance with the License.

  * You may obtain a copy of the License at

  *

  * http://www.apache.org/licenses/LICENSE-2.0

  *

  * Unless required by applicable law or agreed to in writing, software

  * distributed under the License is distributed on an "AS IS" BASIS,

  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implIEd.

  * See the License for the specific language governing permissions and

  * limitations under the License.

  */

  package android.widget;

  import android.content.Context;

  import android.content.res.TypedArray;

  import android.graphics.Canvas;

  import android.graphics.Rect;

  import android.graphics.PixelFormat;

  import android.graphics.Paint;

  import android.graphics.drawable.Drawable;

  import android.graphics.drawable.ColorDrawable;

  import android.os.Parcel;

  import android.os.Parcelable;

  import android.util.AttributeSet;

  import android.util.SparseBooleanArray;

  import android.vIEw.FocusFinder;

  import android.vIEw.KeyEvent;

  import android.vIEw.MotionEvent;

  import android.view.VIEw;

  import android.view.VIEwDebug;

  import android.view.VIEwGroup;

  import android.view.VIEwParent;

  import android.vIEw.SoundEffectConstants;

  import android.vIEw.accessibility.AccessibilityEvent;

  import com.google.android.collect.Lists;

  import com.android.internal.R;

  import Java.util.ArrayList;

  /*

  * Implementation Notes:

  接上頁

  *

  * Some terminology:

  *

  * index - index of the items that are currently visible

  * position - index of the items in the cursor

  */

  /**

  * A vIEw that shows items in a vertically scrolling list. The items

  * come from the {@link ListAdapter} associated with this vIEw.

  *

  * @attr ref android.R.styleable#ListView_entrIEs

  * @attr ref android.R.styleable#ListVIEw_divider

  * @attr ref android.R.styleable#ListVIEw_dividerHeight

  * @attr ref android.R.styleable#ListVIEw_choiceMode

  * @attr ref android.R.styleable#ListVIEw_headerDividersEnabled

  * @attr ref android.R.styleable#ListVIEw_footerDividersEnabled

  */

  public class ListView extends AbsListVIEw {

  /**

  * Used to indicate a no preference for a position type.

  */

  static final int NO_POSITION = -1;

  /**

  * Normal list that does not indicate choices

  */

  public static final int CHOICE_MODE_NONE = 0;

  /**

  * The list allows up to one choice

  */

  public static final int CHOICE_MODE_SINGLE = 1;

  /**

  * The list allows multiple choices

  */

  public static final int CHOICE_MODE_MULTIPLE = 2;

  /**

  * When arrow scrolling, ListVIEw will never scroll more than this factor

  * times the height of the list.

  */

  private static final float MAX_SCROLL_FACTOR = 0.33f;

  /**

  * When arrow scrolling, need a certain amount of pixels to prevIEw next

  * items. This is usually the fading edge, but if that is small enough,

  * we want to make sure we prevIEw at least this many pixels.

  */

  private static final int MIN_SCROLL_PREVIEW_PIXELS = 2;

  /**

  接上頁

  * A class that represents a fixed vIEw in a list, for example a header at the top

  * or a footer at the bottom.

  */

  public class FixedVIEwInfo {

  /** The vIEw to add to the list */

  public View vIEw;

  /** The data backing the vIEw. This is returned from {@link ListAdapter#getItem(int)}. */

  public Object data;

  /** true if the fixed vIEw should be selectable in the list */

  public boolean isSelectable;

  }

  private ArrayList mHeaderVIEwInfos = Lists.newArrayList();

  private ArrayList mFooterVIEwInfos = Lists.newArrayList();

  Drawable mDivider;

  int mDividerHeight;

  private boolean mIsCacheColorOpaque;

  private boolean mDividerIsOpaque;

  private boolean mClipDivider;

  private boolean mHeaderDividersEnabled;

  private boolean mFooterDividersEnabled;

  private boolean mAreAllItemsSelectable = true;

  private boolean mItemsCanFocus = false;

  private int mChoiceMode = CHOICE_MODE_NONE;

  private SparseBooleanArray mCheckStates;

  // used for temporary calculations.

  private final Rect mTempRect = new Rect();

  private Paint mDividerPaint;

  // the single allocated result per list vIEw; kinda cheesey but avoids

  // allocating these thingIEs too often.

  private ArrowScrollFocusResult mArrowScrollFocusResult = new ArrowScrollFocusResult();

  public ListVIEw(Context context) {

  this(context, null);

  }

  public ListVIEw(Context context, AttributeSet attrs) {

  this(context, attrs, com.android.internal.R.attr.listVIEwStyle);

  }

  public ListVIEw(Context context, AttributeSet attrs, int defStyle) {

  super(context, attrs, defStyle);

  TypedArray a = context.obtainStyledAttributes(attrs,

  接上頁

  com.android.internal.R.styleable.ListVIEw, defStyle, 0);

  CharSequence[] entrIEs = a.getTextArray(

  com.android.internal.R.styleable.ListView_entrIEs);

  if (entrIEs != null) {

  setAdapter(new ArrayAdapter(context,

  com.android.internal.R.layout.simple_list_item_1, entrIEs));

  }

  final Drawable d = a.getDrawable(com.android.internal.R.styleable.ListVIEw_divider);

  if (d != null) {

  // If a divider is specifIEd use its intrinsic height for divider height

  setDivider(d);

  }

  // Use the height specifIEd, zero being the default

  final int dividerHeight = a.getDimensionPixelSize(

  com.android.internal.R.styleable.ListVIEw_dividerHeight, 0);

  if (dividerHeight != 0) {

  setDividerHeight(dividerHeight);

  }

  setChoiceMode(a.getInt(R.styleable.ListVIEw_choiceMode, CHOICE_MODE_NONE));

  mHeaderDividersEnabled = a.getBoolean(R.styleable.ListVIEw_headerDividersEnabled, true);

  mFooterDividersEnabled = a.getBoolean(R.styleable.ListVIEw_footerDividersEnabled, true);

  a.recycle();

  }

  /**

  * @return The maximum amount a list vIEw will scroll in response to

  * an arrow event.

  */

  public int getMaxScrollAmount() {

  return (int) (MAX_SCROLL_FACTOR * (mBottom - mTop));

  }

  /**

  * Make sure vIEws are touching the top or bottom edge, as appropriate for

  * our gravity

  */

  private void adjustVIEwsUpOrDown() {

  final int childCount = getChildCount();

  int delta;

  if (childCount > 0) {

  VIEw child;

  if (!mStackFromBottom) {

  // Uh-oh -- we came up short. Slide all vIEws up to make them

  // align with the top

  child = getChildAt(0);

  接上頁

  delta = child.getTop() - mListPadding.top;

  if (mFirstPosition != 0) {

  // It's OK to have some space above the first item if it is

  // part of the vertical spacing

  delta -= mDividerHeight;

  }

  if (delta < 0) {

  // We only are looking to see if we are too low, not too high

  delta = 0;

  }

  } else {

  // we are too high, slide all vIEws down to align with bottom

  child = getChildAt(childCount - 1);

  delta = child.getBottom() - (getHeight() - mListPadding.bottom);

  if (mFirstPosition + childCount < mItemCount) {

  // It's OK to have some space below the last item if it is

  // part of the vertical spacing

  delta += mDividerHeight;

  }

  if (delta > 0) {

  delta = 0;

  }

  }

  if (delta != 0) {

  offsetChildrenTopAndBottom(-delta);

  }

  }

  }

  /**

  * Add a fixed view to appear at the top of the list. If addHeaderVIEw is

  * called more than once, the vIEws will appear in the order they were

  * added. VIEws added using this call can take focus if they want.

  *

  * NOTE: Call this before calling setAdapter. This is so ListVIEw can wrap

  * the supplIEd cursor with one that that will also account for header

  * vIEws.

  *

  * @param v The vIEw to add.

  * @param data Data to associate with this vIEw

  * @param isSelectable whether the item is selectable

  */

  public void addHeaderView(VIEw v, Object data, boolean isSelectable) {

  if (mAdapter != null) {

  throw new IllegalStateException(

  "Cannot add header vIEw to list -- setAdapter has already been called.");

  }

  FixedViewInfo info = new FixedVIEwInfo();

  接上頁

  info.vIEw = v;

  info.data = data;

  info.isSelectable = isSelectable;

  mHeaderVIEwInfos.add(info);

  }

  /**

  * Add a fixed view to appear at the top of the list. If addHeaderVIEw is

  * called more than once, the vIEws will appear in the order they were

  * added. VIEws added using this call can take focus if they want.

  *

  * NOTE: Call this before calling setAdapter. This is so ListVIEw can wrap

  * the supplIEd cursor with one that that will also account for header

  * vIEws.

  *

  * @param v The vIEw to add.

  */

  public void addHeaderView(VIEw v) {

  addHeaderVIEw(v, null, true);

  }

  @Override

  public int getHeaderVIEwsCount() {

  return mHeaderVIEwInfos.size();

  }

  /**

  * Removes a previously-added header vIEw.

  *

  * @param v The vIEw to remove

  * @return true if the view was removed, false if the vIEw was not a header

  * vIEw

  */

  public boolean removeHeaderView(VIEw v) {

  if (mHeaderVIEwInfos.size() > 0) {

  boolean result = false;

  if (((HeaderVIEwListAdapter) mAdapter).removeHeader(v)) {

  mDataSetObserver.onChanged();

  result = true;

  }

  removeFixedViewInfo(v, mHeaderVIEwInfos);

  return result;

  }

  return false;

  }

  private void removeFixedViewInfo(VIEw v, ArrayList where) {

  int len = where.size();

  for (int i = 0; i < len; ++i) {

  FixedVIEwInfo info = where.get(i);

  if (info.vIEw == v) {

  where.remove(i);

  break;

  }

  }

  }

  /**

  * Add a fixed view to appear at the bottom of the list. If addFooterVIEw

  接上頁

is

  * called more than once, the vIEws will appear in the order they were

  * added. VIEws added using this call can take focus if they want.

  *

  * NOTE: Call this before calling setAdapter. This is so ListVIEw can wrap

  * the supplIEd cursor with one that that will also account for header

  * vIEws.

  *

  * @param v The vIEw to add.

  * @param data Data to associate with this vIEw

  * @param isSelectable true if the footer vIEw can be selected

  */

  public void addFooterView(VIEw v, Object data, boolean isSelectable) {

  FixedViewInfo info = new FixedVIEwInfo();

  info.vIEw = v;

  info.data = data;

  info.isSelectable = isSelectable;

  mFooterVIEwInfos.add(info);

  // in the case of re-adding a footer vIEw, or adding one later on,

  // we need to notify the observer

  if (mDataSetObserver != null) {

  mDataSetObserver.onChanged();

  }

  }

  /**

  * Add a fixed view to appear at the bottom of the list. If addFooterVIEw is called more

  * than once, the views will appear in the order they were added. VIEws added using

  * this call can take focus if they want.

  *

NOTE: Call this before calling setAdapter. This is so ListView can wrap the supplIEd

  * cursor with one that that will also account for header vIEws.

  *

  *

  * @param v The vIEw to add.

  */

  public void addFooterView(VIEw v) {

  addFooterVIEw(v, null, true);

  }

  @Override

  public int getFooterVIEwsCount() {

  return mFooterVIEwInfos.size();

  }

  /**

  * Removes a previously-added footer vIEw.

  *

  * @param v The vIEw to remove

  * @return

  接上頁

  * true if the view was removed, false if the view was not a footer vIEw

  */

  public boolean removeFooterView(VIEw v) {

  if (mFooterVIEwInfos.size() > 0) {

  boolean result = false;

  if (((HeaderVIEwListAdapter) mAdapter).removeFooter(v)) {

  mDataSetObserver.onChanged();

  result = true;

  }

  removeFixedViewInfo(v, mFooterVIEwInfos);

  return result;

  }

  return false;

  }

  /**

  * Returns the adapter currently in use in this ListVIEw. The returned adapter

  * might not be the same adapter passed to {@link #setAdapter(ListAdapter)} but

  * might be a {@link WrapperListAdapter}.

  *

  * @return The adapter currently used to display data in this ListVIEw.

  *

  * @see #setAdapter(ListAdapter)

  */

  @Override

  public ListAdapter getAdapter() {

  return mAdapter;

  }

  /**

  * Sets the data behind this ListVIEw.

  *

  * The adapter passed to this method may be wrapped by a {@link WrapperListAdapter},

  * depending on the ListVIEw features currently in use. For instance, adding

  * headers and/or footers will cause the adapter to be wrapped.

  *

  * @param adapter The ListAdapter which is responsible for maintaining the

  * data backing this list and for producing a vIEw to represent an

  * item in that data set.

  *

  * @see #getAdapter()

  */

  @Override

  public void setAdapter(ListAdapter adapter) {

  if (null != mAdapter) {

  mAdapter.unregisterDataSetObserver(mDataSetObserver);

  }

  resetList();

  mRecycler.clear();

  if (mHeaderViewInfos.size() > 0|| mFooterVIEwInfos.size() > 0) {

  接上頁

  mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterVIEwInfos, adapter);

  } else {

  mAdapter = adapter;

  }

  mOldSelectedPosition = INVALID_POSITION;

  mOldSelectedRowId = INVALID_ROW_ID;

  if (mAdapter != null) {

  mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();

  mOldItemCount = mItemCount;

  mItemCount = mAdapter.getCount();

  checkFocus();

  mDataSetObserver = new AdapterDataSetObserver();

  mAdapter.registerDataSetObserver(mDataSetObserver);

  mRecycler.setViewTypeCount(mAdapter.getVIEwTypeCount());

  int position;

  if (mStackFromBottom) {

  position = lookForSelectablePosition(mItemCount - 1, false);

  } else {

  position = lookForSelectablePosition(0, true);

  }

  setSelectedPositionInt(position);

  setNextSelectedPositionInt(position);

  if (mItemCount == 0) {

  // Nothing selected

  checkSelectionChanged();

  }

  } else {

  mAreAllItemsSelectable = true;

  checkFocus();

  // Nothing selected

  checkSelectionChanged();

  }

  if (mCheckStates != null) {

  mCheckStates.clear();

  }

  requestLayout();

  }

  /**

  * The list is empty. Clear everything out.

  */

  @Override

  void resetList() {

  // The parent's resetList() will remove all vIEws from the layout so we need to

  // cleanup the state of our footers and headers

  clearRecycledState(mHeaderVIEwInfos);

  clearRecycledState(mFooterVIEwInfos);

  super.resetList();

  mLayoutMode = LAYOUT_NORMAL;

  }

  private void clearRecycledState(ArrayList infos) {

  if (infos != null) {

  final int count = infos.size();

  接上頁

  for (int i = 0; i < count; i++) {

  final View child = infos.get(i).vIEw;

  final LayoutParams p = (LayoutParams) child.getLayoutParams();

  if (p != null) {

  p.recycledHeaderFooter = false;

  }

  }

  }

  }

  /**

  * @return Whether the list needs to show the top fading edge

  */

  private boolean showingTopFadingEdge() {

  final int listTop = mScrollY + mListPadding.top;

  return (mFirstPosition > 0) || (getChildAt(0).getTop() > listTop);

  }

  /**

  * @return Whether the list needs to show the bottom fading edge

  */

  private boolean showingBottomFadingEdge() {

  final int childCount = getChildCount();

  final int bottomOfBottomChild = getChildAt(childCount - 1).getBottom();

  final int lastVisiblePosition = mFirstPosition + childCount - 1;

  final int listBottom = mScrollY + getHeight() - mListPadding.bottom;

  return (lastVisiblePosition < mItemCount - 1)

  || (bottomOfBottomChild < listBottom);

  }

  @Override

  public boolean requestChildRectangleOnScreen(VIEw child, Rect rect, boolean immediate) {

  int rectTopWithinChild = rect.top;

  // offset so rect is in coordinates of the this vIEw

  rect.offset(child.getLeft(), child.getTop());

  rect.offset(-child.getScrollX(), -child.getScrollY());

  final int height = getHeight();

  int listUnfadedTop = getScrollY();

  int listUnfadedBottom = listUnfadedTop + height;

  final int fadingEdge = getVerticalFadingEdgeLength();

  if (showingTopFadingEdge()) {

  // leave room for top fading edge as long as rect isn't at very top

  if ((mSelectedPosition > 0) || (rectTopWithinChild > fadingEdge)) {

  listUnfadedTop += fadingEdge;

  接上頁

  }

  }

  int childCount = getChildCount();

  int bottomOfBottomChild = getChildAt(childCount - 1).getBottom();

  if (showingBottomFadingEdge()) {

  // leave room for bottom fading edge as long as rect isn't at very bottom

  if ((mSelectedPosition < mItemCount - 1)

  || (rect.bottom < (bottomOfBottomChild - fadingEdge))) {

  listUnfadedBottom -= fadingEdge;

  }

  }

  int scrollYDelta = 0;

  if (rect.bottom > listUnfadedBottom && rect.top > listUnfadedTop) {

  // need to MOVE DOWN to get it in vIEw: move down just enough so

  // that the entire rectangle is in vIEw (or at least the first

  // screen size chunk).

  if (rect.height() > height) {

  // just enough to get screen size chunk on

  scrollYDelta += (rect.top - listUnfadedTop);

  } else {

  // get entire rect at bottom of screen

  scrollYDelta += (rect.bottom - listUnfadedBottom);

  }

  // make sure we aren't scrolling beyond the end of our children

  int distanceToBottom = bottomOfBottomChild - listUnfadedBottom;

  scrollYDelta = Math.min(scrollYDelta, distanceToBottom);

  } else if (rect.top < listUnfadedTop && rect.bottom < listUnfadedBottom) {

  // need to MOVE UP to get it in vIEw: move up just enough so that

  // entire rectangle is in vIEw (or at least the first screen

  // size chunk of it).

  if (rect.height() > height) {

  // screen size chunk

  scrollYDelta -= (listUnfadedBottom - rect.bottom);

  } else {

  // entire rect at top

  scrollYDelta -= (listUnfadedTop - rect.top);

  }

  // make sure we aren't scrolling any further than the top our children

  int top = getChildAt(0).getTop();

  接上頁

  int deltaToTop = top - listUnfadedTop;

  scrollYDelta = Math.max(scrollYDelta, deltaToTop);

  }

  final boolean scroll = scrollYDelta != 0;

  if (scroll) {

  scrollListItemsBy(-scrollYDelta);

  positionSelector(child);

  mSelectedTop = child.getTop();

  invalidate();

  }

  return scroll;

  }

  /**

  * {@inheritDoc}

  */

  @Override

  void fillGap(boolean down) {

  final int count = getChildCount();

  if (down) {

  final int startOffset = count > 0 ? getChildAt(count - 1).getBottom() + mDividerHeight :

  getListPaddingTop();

  fillDown(mFirstPosition + count, startOffset);

  correctTooHigh(getChildCount());

  } else {

  final int startOffset = count > 0 ? getChildAt(0).getTop() - mDividerHeight :

  getHeight() - getListPaddingBottom();

  fillUp(mFirstPosition - 1, startOffset);

  correctTooLow(getChildCount());

  }

  }

  /**

  * Fills the list from pos down to the end of the list vIEw.

  *

  * @param pos The first position to put in the list

  *

  * @param nextTop The location where the top of the item associated with pos

  * should be drawn

  *

  * @return The vIEw that is currently selected, if it happens to be in the

  * range that we draw.

  */

  private VIEw fillDown(int pos, int nextTop) {

  View selectedVIEw = null;

  int end = (mBottom - mTop) - mListPadding.bottom;

  while (nextTop < end && pos < mItemCount) {

  // is this the selected item?

  boolean selected = pos == mSelectedPosition;

  View child = makeAndAddVIEw(pos, nextTop, true, mListPadding.left, selected);

  接上頁

  nextTop = child.getBottom() + mDividerHeight;

  if (selected) {

  selectedVIEw = child;

  }

  pos++;

  }

  return selectedVIEw;

  }

  /**

  * Fills the list from pos up to the top of the list vIEw.

  *

  * @param pos The first position to put in the list

  *

  * @param nextBottom The location where the bottom of the item associated

  * with pos should be drawn

  *

  * @return The vIEw that is currently selected

  */

  private VIEw fillUp(int pos, int nextBottom) {

  View selectedVIEw = null;

  int end = mListPadding.top;

  while (nextBottom > end && pos >= 0) {

  // is this the selected item?

  boolean selected = pos == mSelectedPosition;

  View child = makeAndAddVIEw(pos, nextBottom, false, mListPadding.left, selected);

  nextBottom = child.getTop() - mDividerHeight;

  if (selected) {

  selectedVIEw = child;

  }

  pos--;

  }

  mFirstPosition = pos + 1;

  return selectedVIEw;

  }

  /**

  * Fills the list from top to bottom, starting with mFirstPosition

  *

  * @param nextTop The location where the top of the first item should be

  * drawn

  *

  * @return The vIEw that is currently selected

  */

  private VIEw fillFromTop(int nextTop) {

  mFirstPosition = Math.min(mFirstPosition, mSelectedPosition);

  mFirstPosition = Math.min(mFirstPosition, mItemCount - 1);

  if (mFirstPosition < 0) {

  mFirstPosition = 0;

  }

  return fillDown(mFirstPosition, nextTop);

  }

  /**

  * Put mSelectedPosition in the middle of the screen and then build up and

  接上頁

  * down from there. This method forces mSelectedPosition to the center.

  *

  * @param childrenTop Top of the area in which children can be drawn, as

  * measured in pixels

  * @param childrenBottom Bottom of the area in which children can be drawn,

  * as measured in pixels

  * @return Currently selected vIEw

  */

  private VIEw fillFromMiddle(int childrenTop, int childrenBottom) {

  int height = childrenBottom - childrenTop;

  int position = reconcileSelectedPosition();

  View sel = makeAndAddVIEw(position, childrenTop, true,

  mListPadding.left, true);

  mFirstPosition = position;

  int selHeight = sel.getMeasuredHeight();

  if (selHeight <= height) {

  sel.offsetTopAndBottom((height - selHeight) / 2);

  }

  fillAboveAndBelow(sel, position);

  if (!mStackFromBottom) {

  correctTooHigh(getChildCount());

  } else {

  correctTooLow(getChildCount());

  }

  return sel;

  }

  /**

  * Once the selected vIEw as been placed, fill up the visible area above and

  * below it.

  *

  * @param sel The selected vIEw

  * @param position The position corresponding to sel

  */

  private void fillAboveAndBelow(VIEw sel, int position) {

  final int dividerHeight = mDividerHeight;

  if (!mStackFromBottom) {

  fillUp(position - 1, sel.getTop() - dividerHeight);

  adjustVIEwsUpOrDown();

  fillDown(position + 1, sel.getBottom() + dividerHeight);

  } else {

  fillDown(position + 1, sel.getBottom() + dividerHeight);

  adjustVIEwsUpOrDown();

  fillUp(position - 1, sel.getTop() - dividerHeight);

  }

  }

  /**

  * Fills the grid based on positioning the new selection at a specific

  接上頁

  * location. The selection may be moved so that it does not intersect the

  * faded edges. The grid is then filled upwards and downwards from there.

  *

  * @param selectedTop Where the selected item should be

  * @param childrenTop Where to start drawing children

  * @param childrenBottom Last pixel where children can be drawn

  * @return The vIEw that currently has selection

  */

  private VIEw fillFromSelection(int selectedTop, int childrenTop, int childrenBottom) {

  int fadingEdgeLength = getVerticalFadingEdgeLength();

  final int selectedPosition = mSelectedPosition;

  VIEw sel;

  final int topSelectionPixel = getTopSelectionPixel(childrenTop, fadingEdgeLength,

  selectedPosition);

  final int bottomSelectionPixel = getBottomSelectionPixel(childrenBottom, fadingEdgeLength,

  selectedPosition);

  sel = makeAndAddVIEw(selectedPosition, selectedTop, true, mListPadding.left, true);

  // Some of the newly selected item extends below the bottom of the list

  if (sel.getBottom() > bottomSelectionPixel) {

  // Find space available above the selection into which we can scroll

  // upwards

  final int spaceAbove = sel.getTop() - topSelectionPixel;

  // Find space required to bring the bottom of the selected item

  // fully into vIEw

  final int spaceBelow = sel.getBottom() - bottomSelectionPixel;

  final int offset = Math.min(spaceAbove, spaceBelow);

  // Now offset the selected item to get it into vIEw

  sel.offsetTopAndBottom(-offset);

  } else if (sel.getTop() < topSelectionPixel) {

  // Find space required to bring the top of the selected item fully

  // into vIEw

  final int spaceAbove = topSelectionPixel - sel.getTop();

  // Find space available below the selection into which we can scroll

  接上頁

  // downwards

  final int spaceBelow = bottomSelectionPixel - sel.getBottom();

  final int offset = Math.min(spaceAbove, spaceBelow);

  // Offset the selected item to get it into vIEw

  sel.offsetTopAndBottom(offset);

  }

  // Fill in vIEws above and below

  fillAboveAndBelow(sel, selectedPosition);

  if (!mStackFromBottom) {

  correctTooHigh(getChildCount());

  } else {

  correctTooLow(getChildCount());

  }

  return sel;

  }

  /**

  * Calculate the bottom-most pixel we can draw the selection into

  *

  * @param childrenBottom Bottom pixel were children can be drawn

  * @param fadingEdgeLength Length of the fading edge in pixels, if present

  * @param selectedPosition The position that will be selected

  * @return The bottom-most pixel we can draw the selection into

  */

  private int getBottomSelectionPixel(int childrenBottom, int fadingEdgeLength,

  int selectedPosition) {

  int bottomSelectionPixel = childrenBottom;

  if (selectedPosition != mItemCount - 1) {

  bottomSelectionPixel -= fadingEdgeLength;

  }

  return bottomSelectionPixel;

  }

  /**

  * Calculate the top-most pixel we can draw the selection into

  *

  * @param childrenTop Top pixel were children can be drawn

  * @param fadingEdgeLength Length of the fading edge in pixels, if present

  * @param selectedPosition The position that will be selected

  * @return The top-most pixel we can draw the selection into

  */

  private int getTopSelectionPixel(int childrenTop, int fadingEdgeLength, int selectedPosition) {

  // first pixel we can draw the selection into

  int topSelectionPixel = childrenTop;

  接上頁

  if (selectedPosition > 0) {

  topSelectionPixel += fadingEdgeLength;

  }

  return topSelectionPixel;

  }

  /**

  * Fills the list based on positioning the new selection relative to the old

  * selection. The new selection will be placed at, above, or below the

  * location of the new selection depending on how the selection is moving.

  * The selection will then be pinned to the visible part of the screen,

  * excluding the edges that are faded. The list is then filled upwards and

  * downwards from there.

  *

  * @param oldSel The old selected vIEw. Useful for trying to put the new

  * selection in the same place

  * @param newSel The vIEw that is to become selected. Useful for trying to

  * put the new selection in the same place

  * @param delta Which way we are moving

  * @param childrenTop Where to start drawing children

  * @param childrenBottom Last pixel where children can be drawn

  * @return The vIEw that currently has selection

  */

  private View moveSelection(View oldSel, VIEw newSel, int delta, int childrenTop,

  int childrenBottom) {

  int fadingEdgeLength = getVerticalFadingEdgeLength();

  final int selectedPosition = mSelectedPosition;

  VIEw sel;

  final int topSelectionPixel = getTopSelectionPixel(childrenTop, fadingEdgeLength,

  selectedPosition);

  final int bottomSelectionPixel = getBottomSelectionPixel(childrenTop, fadingEdgeLength,

  selectedPosition);

  if (delta > 0) {

  /*

  * Case 1: Scrolling down.

  */

  /*

  * Before After

  * | | | |

  * +-------+ +-------+

  * | A | | A |

  * | 1 | => +-------+

  * +-------+ | B |

  接上頁

  * | B | | 2 |

  * +-------+ +-------+

  * | | | |

  *

  * Try to keep the top of the previously selected item where it was.

  * oldSel = A

  * sel = B

  */

  // Put oldSel (A) where it belongs

  oldSel = makeAndAddVIEw(selectedPosition - 1, oldSel.getTop(), true,

  mListPadding.left, false);

  final int dividerHeight = mDividerHeight;

  // Now put the new selection (B) below that

  sel = makeAndAddVIEw(selectedPosition, oldSel.getBottom() + dividerHeight, true,

  mListPadding.left, true);

  // Some of the newly selected item extends below the bottom of the list

  if (sel.getBottom() > bottomSelectionPixel) {

  // Find space available above the selection into which we can scroll upwards

  int spaceAbove = sel.getTop() - topSelectionPixel;

  // Find space required to bring the bottom of the selected item fully into vIEw

  int spaceBelow = sel.getBottom() - bottomSelectionPixel;

  // Don't scroll more than half the height of the list

  int halfVerticalSpace = (childrenBottom - childrenTop) / 2;

  int offset = Math.min(spaceAbove, spaceBelow);

  offset = Math.min(offset, halfVerticalSpace);

  // We placed oldSel, so offset that item

  oldSel.offsetTopAndBottom(-offset);

  // Now offset the selected item to get it into vIEw

  sel.offsetTopAndBottom(-offset);

  }

  // Fill in vIEws above and below

  if (!mStackFromBottom) {

  fillUp(mSelectedPosition - 2, sel.getTop() - dividerHeight);

  adjustVIEwsUpOrDown();

  fillDown(mSelectedPosition + 1, sel.getBottom() + dividerHeight);

  } else {

  fillDown(mSelectedPosition + 1, sel.getBottom() + dividerHeight);

  adjustVIEwsUpOrDown();

  fillUp(mSelectedPosition - 2, sel.getTop() - dividerHeight);

  接上頁

  }

  } else if (delta < 0) {

  /*

  * Case 2: Scrolling up.

  */

  /*

  * Before After

  * | | | |

  * +-------+ +-------+

  * | A | | A |

  * +-------+ => | 1 |

  * | B | +-------+

  * | 2 | | B |

  * +-------+ +-------+

  * | | | |

  *

  * Try to keep the top of the item about to become selected where it was.

  * newSel = A

  * olSel = B

  */

  if (newSel != null) {

  // Try to position the top of newSel (A) where it was before it was selected

  sel = makeAndAddVIEw(selectedPosition, newSel.getTop(), true, mListPadding.left,

  true);

  } else {

  // If (A) was not on screen and so did not have a vIEw, position

  // it above the oldSel (B)

  sel = makeAndAddVIEw(selectedPosition, oldSel.getTop(), false, mListPadding.left,

  true);

  }

  // Some of the newly selected item extends above the top of the list

  if (sel.getTop() < topSelectionPixel) {

  // Find space required to bring the top of the selected item fully into vIEw

  int spaceAbove = topSelectionPixel - sel.getTop();

  // Find space available below the selection into which we can scroll downwards

  int spaceBelow = bottomSelectionPixel - sel.getBottom();

  // Don't scroll more than half the height of the list

  int halfVerticalSpace = (childrenBottom - childrenTop) / 2;

  int offset = Math.min(spaceAbove, spaceBelow);

  offset = Math.min(offset, halfVerticalSpace);

  // Offset the selected item to get it into vIEw

  sel.offsetTopAndBottom(offset);

  }

  // Fill in vIEws above and below

  fillAboveAndBelow(sel, selectedPosition);

  } else {

  接上頁

  int oldTop = oldSel.getTop();

  /*

  * Case 3: Staying still

  */

  sel = makeAndAddVIEw(selectedPosition, oldTop, true, mListPadding.left, true);

  // We're staying still...

  if (oldTop < childrenTop) {

  // ... but the top of the old selection was off screen.

  // (This can happen if the data changes size out from under us)

  int newBottom = sel.getBottom();

  if (newBottom < childrenTop + 20) {

  // Not enough visible -- bring it onscreen

  sel.offsetTopAndBottom(childrenTop - sel.getTop());

  }

  }

  // Fill in vIEws above and below

  fillAboveAndBelow(sel, selectedPosition);

  }

  return sel;

  }

  @Override

  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

  // Sets up mListPadding

  super.onMeasure(widthMeasureSpec, heightMeasureSpec);

  int widthMode = MeasureSpec.getMode(widthMeasureSpec);

  int heightMode = MeasureSpec.getMode(heightMeasureSpec);

  int widthSize = MeasureSpec.getSize(widthMeasureSpec);

  int heightSize = MeasureSpec.getSize(heightMeasureSpec);

  int childWidth = 0;

  int childHeight = 0;

  mItemCount = mAdapter == null ? 0 : mAdapter.getCount();

  if (mItemCount > 0 && (widthMode == MeasureSpec.UNSPECIFIED ||

  heightMode == MeasureSpec.UNSPECIFIED)) {

  final View child = obtainVIEw(0);

  measureScrapChild(child, 0, widthMeasureSpec);

  childWidth = child.getMeasuredWidth();

  childHeight = child.getMeasuredHeight();

  if (recycleOnMeasure()) {

  mRecycler.addScrapVIEw(child);

  }

  }

  if (widthMode == MeasureSpec.UNSPECIFIED) {

  widthSize = mListPadding.left + mListPadding.right + childWidth +

  接上頁

  getVerticalScrollbarWidth();

  }

  if (heightMode == MeasureSpec.UNSPECIFIED) {

  heightSize = mListPadding.top + mListPadding.bottom + childHeight +

  getVerticalFadingEdgeLength() * 2;

  }

  if (heightMode == MeasureSpec.AT_MOST) {

  // TODO: after first layout we should maybe start at the first visible position, not 0

  heightSize = measureHeightOfChildren(widthMeasureSpec, 0, NO_POSITION, heightSize, -1);

  }

  setMeasuredDimension(widthSize, heightSize);

  mWidthMeasureSpec = widthMeasureSpec;

  }

  private void measureScrapChild(VIEw child, int position, int widthMeasureSpec) {

  LayoutParams p = (LayoutParams) child.getLayoutParams();

  if (p == null) {

  p = new LayoutParams(VIEwGroup.LayoutParams.FILL_PARENT,

  VIEwGroup.LayoutParams.WRAP_CONTENT, 0);

  child.setLayoutParams(p);

  }

  p.viewType = mAdapter.getItemVIEwType(position);

  int childWidthSpec = VIEwGroup.getChildMeasureSpec(widthMeasureSpec,

  mListPadding.left + mListPadding.right, p.width);

  int lpHeight = p.height;

  int childHeightSpec;

  if (lpHeight > 0) {

  childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);

  } else {

  childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);

  }

  child.measure(childWidthSpec, childHeightSpec);

  }

  /**

  * @return True to recycle the views used to measure this ListVIEw in

  * UNSPECIFIED/AT_MOST modes, false otherwise.

  * @hide

  */

  @VIEwDebug.ExportedProperty

  protected boolean recycleOnMeasure() {

  return true;

  }

  /**

  * Measures the height of the given range of children (inclusive) and

  接上頁

  * returns the height with this ListVIEw's padding and divider heights

  * included. If maxHeight is provided, the measuring will stop when the

  * current height reaches maxHeight.

  *

  * @param widthMeasureSpec The width measure spec to be given to a child's

  * {@link VIEw#measure(int, int)}.

  * @param startPosition The position of the first child to be shown.

  * @param endPosition The (inclusive) position of the last child to be

  * shown. Specify {@link #NO_POSITION} if the last child should be

  * the last available child from the adapter.

  * @param maxHeight The maximum height that will be returned (if all the

  * children don't fit in this value, this value will be

  * returned).

  * @param disallowPartialChildPosition In general, whether the returned

  * height should only contain entire children. This is more

  * powerful--it is the first inclusive position at which partial

  * children will not be allowed. Example: it looks nice to have

  * at least 3 completely visible children, and in portrait this

  * will most likely fit; but in landscape there could be times

  * when even 2 children can not be completely shown, so a value

  * of 2 (remember, inclusive) would be good (assuming

  * startPosition is 0).

  * @return The height of this ListVIEw with the given children.

  */

  final int measureHeightOfChildren(int widthMeasureSpec, int startPosition, int endPosition,

  final int maxHeight, int disallowPartialChildPosition) {

  final ListAdapter adapter = mAdapter;

  if (adapter == null) {

  return mListPadding.top + mListPadding.bottom;

  }

  // Include the padding of the list

  int returnedHeight = mListPadding.top + mListPadding.bottom;

  接上頁

  final int dividerHeight = ((mDividerHeight > 0) && mDivider != null) ? mDividerHeight : 0;

  // The previous height value that was less than maxHeight and contained

  // no partial children

  int prevHeightWithoutPartialChild = 0;

  int i;

  VIEw child;

  // mItemCount - 1 since endPosition parameter is inclusive

  endPosition = (endPosition == NO_POSITION) ? adapter.getCount() - 1 : endPosition;

  final AbsListVIEw.RecycleBin recycleBin = mRecycler;

  final boolean recyle = recycleOnMeasure();

  for (i = startPosition; i <= endPosition; ++i) {

  child = obtainVIEw(i);

  measureScrapChild(child, i, widthMeasureSpec);

  if (i > 0) {

  // Count the divider for all but one child

  returnedHeight += dividerHeight;

  }

  // Recycle the vIEw before we possibly return from the method

  if (recyle) {

  recycleBin.addScrapVIEw(child);

  }

  returnedHeight += child.getMeasuredHeight();

  if (returnedHeight >= maxHeight) {

  // We went over, figure out which height to return. If returnedHeight > maxHeight,

  // then the i'th position did not fit completely.

  return (disallowPartialChildPosition >= 0) // Disallowing is enabled (> -1)

  && (i > disallowPartialChildPosition) // We've past the min pos

  && (prevHeightWithoutPartialChild > 0) // We have a prev height

  && (returnedHeight != maxHeight) // i'th child did not fit completely

  ? prevHeightWithoutPartialChild

  : maxHeight;

  }

  if ((disallowPartialChildPosition >= 0) && (i >= disallowPartialChildPosition)) {

  prevHeightWithoutPartialChild = returnedHeight;

  }

  }

  // At this point, we went through the range of children, and they each

  接上頁

  // completely fit, so return the returnedHeight

  return returnedHeight;

  }

  @Override

  int findMotionRow(int y) {

  int childCount = getChildCount();

  if (childCount > 0) {

  for (int i = 0; i < childCount; i++) {

  VIEw v = getChildAt(i);

  if (y <= v.getBottom()) {

  return mFirstPosition + i;

  }

  }

  return mFirstPosition + childCount - 1;

  }

  return INVALID_POSITION;

  }

  /**

  * Put a specific item at a specific location on the screen and then build

  * up and down from there.

  *

  * @param position The reference vIEw to use as the starting point

  * @param top Pixel offset from the top of this vIEw to the top of the

  * reference vIEw.

  *

  * @return The selected view, or null if the selected vIEw is outside the

  * visible area.

  */

  private VIEw fillSpecific(int position, int top) {

  boolean tempIsSelected = position == mSelectedPosition;

  View temp = makeAndAddVIEw(position, top, true, mListPadding.left, tempIsSelected);

  // Possibly changed again in fillUp if we add rows above this one.

  mFirstPosition = position;

  VIEw above;

  VIEw below;

  final int dividerHeight = mDividerHeight;

  if (!mStackFromBottom) {

  above = fillUp(position - 1, temp.getTop() - dividerHeight);

  // This will correct for the top of the first vIEw not touching the top of the list

  adjustVIEwsUpOrDown();

  below = fillDown(position + 1, temp.getBottom() + dividerHeight);

  int childCount = getChildCount();

  if (childCount > 0) {

  correctTooHigh(childCount);

  }

  } else {

  below = fillDown(position + 1, temp.getBottom() + dividerHeight);

  接上頁

  // This will correct for the bottom of the last vIEw not touching the bottom of the list

  adjustVIEwsUpOrDown();

  above = fillUp(position - 1, temp.getTop() - dividerHeight);

  int childCount = getChildCount();

  if (childCount > 0) {

  correctTooLow(childCount);

  }

  }

  if (tempIsSelected) {

  return temp;

  } else if (above != null) {

  return above;

  } else {

  return below;

  }

  }

  /**

  * Check if we have dragged the bottom of the list too high (we have pushed the

  * top element off the top of the screen when we did not need to). Correct by sliding

  * everything back down.

  *

  * @param childCount Number of children

  */

  private void correctTooHigh(int childCount) {

  // First see if the last item is visible. If it is not, it is OK for the

  // top of the list to be pushed up.

  int lastPosition = mFirstPosition + childCount - 1;

  if (lastPosition == mItemCount - 1 && childCount > 0) {

  // Get the last child ...

  final VIEw lastChild = getChildAt(childCount - 1);

  // ... and its bottom edge

  final int lastBottom = lastChild.getBottom();

  // This is bottom of our drawable area

  final int end = (mBottom - mTop) - mListPadding.bottom;

  // This is how far the bottom edge of the last vIEw is from the bottom of the

  // drawable area

  int bottomOffset = end - lastBottom;

  VIEw firstChild = getChildAt(0);

  final int firstTop = firstChild.getTop();

  // Make sure we are 1) Too high, and 2) Either there are more rows above the

  // first row or the first row is scrolled off the top of the drawable area

  if (bottomOffset > 0 && (mFirstPosition > 0 || firstTop <

  接上頁

mListPadding.top)) {

  if (mFirstPosition == 0) {

  // Don't pull the top too far down

  bottomOffset = Math.min(bottomOffset, mListPadding.top - firstTop);

  }

  // Move everything down

  offsetChildrenTopAndBottom(bottomOffset);

  if (mFirstPosition > 0) {

  // Fill the gap that was opened above mFirstPosition with more rows, if

  // possible

  fillUp(mFirstPosition - 1, firstChild.getTop() - mDividerHeight);

  // Close up the remaining gap

  adjustVIEwsUpOrDown();

  }

  }

  }

  }

  /**

  * Check if we have dragged the bottom of the list too low (we have pushed the

  * bottom element off the bottom of the screen when we did not need to). Correct by sliding

  * everything back up.

  *

  * @param childCount Number of children

  */

  private void correctTooLow(int childCount) {

  // First see if the first item is visible. If it is not, it is OK for the

  // bottom of the list to be pushed down.

  if (mFirstPosition == 0 && childCount > 0) {

  // Get the first child ...

  final VIEw firstChild = getChildAt(0);

  // ... and its top edge

  final int firstTop = firstChild.getTop();

  // This is top of our drawable area

  final int start = mListPadding.top;

  // This is bottom of our drawable area

  final int end = (mBottom - mTop) - mListPadding.bottom;

  // This is how far the top edge of the first vIEw is from the top of the

  // drawable area

  int topOffset = firstTop - start;

  VIEw lastChild = getChildAt(childCount - 1);

  final int lastBottom = lastChild.getBottom();

  int lastPosition = mFirstPosition + childCount - 1;

  // Make sure we are 1) Too low, and 2) Either there are more rows below

  接上頁

the

  // last row or the last row is scrolled off the bottom of the drawable area

  if (topOffset > 0) {

  if (lastPosition < mItemCount - 1 || lastBottom > end) {

  if (lastPosition == mItemCount - 1) {

  // Don't pull the bottom too far up

  topOffset = Math.min(topOffset, lastBottom - end);

  }

  // Move everything up

  offsetChildrenTopAndBottom(-topOffset);

  if (lastPosition < mItemCount - 1) {

  // Fill the gap that was opened below the last position with more rows, if

  // possible

  fillDown(lastPosition + 1, lastChild.getBottom() + mDividerHeight);

  // Close up the remaining gap

  adjustVIEwsUpOrDown();

  }

  } else if (lastPosition == mItemCount - 1) {

  adjustVIEwsUpOrDown();

  }

  }

  }

  }

  @Override

  protected void layoutChildren() {

  final boolean blockLayoutRequests = mBlockLayoutRequests;

  if (!blockLayoutRequests) {

  mBlockLayoutRequests = true;

  } else {

  return;

  }

  try {

  super.layoutChildren();

  invalidate();

  if (mAdapter == null) {

  resetList();

  invokeOnItemScrollListener();

  return;

  }

  int childrenTop = mListPadding.top;

  int childrenBottom = mBottom - mTop - mListPadding.bottom;

  int childCount = getChildCount();

  int index;

  int delta = 0;

  VIEw sel;

  VIEw oldSel = null;

  VIEw oldFirst = null;

  VIEw newSel = null;

  View focusLayoutRestoreVIEw = null;

  // Remember stuff we will need down below

  switch (mLayoutMode) {

  case LAYOUT_SET_SELECTION:

  index = mNextSelectedPosition - mFirstPosition;

  接上頁

  if (index >= 0 && index < childCount) {

  newSel = getChildAt(index);

  }

  break;

  case LAYOUT_FORCE_TOP:

  case LAYOUT_FORCE_BOTTOM:

  case LAYOUT_SPECIFIC:

  case LAYOUT_SYNC:

  break;

  case LAYOUT_MOVE_SELECTION:

  default:

  // Remember the previously selected vIEw

  index = mSelectedPosition - mFirstPosition;

  if (index >= 0 && index < childCount) {

  oldSel = getChildAt(index);

  }

  // Remember the previous first child

  oldFirst = getChildAt(0);

  if (mNextSelectedPosition >= 0) {

  delta = mNextSelectedPosition - mSelectedPosition;

  }

  // Caution: newSel might be null

  newSel = getChildAt(index + delta);

  }

  boolean dataChanged = mDataChanged;

  if (dataChanged) {

  handleDataChanged();

  }

  // Handle the empty set by removing all vIEws that are visible

  // and calling it a day

  if (mItemCount == 0) {

  resetList();

  invokeOnItemScrollListener();

  return;

  } else if (mItemCount != mAdapter.getCount()) {

  throw new IllegalStateException("The content of the adapter has changed but "

  + "ListVIEw did not receive a notification. Make sure the content of "

  + "your adapter is not modifIEd from a background thread, but only "

  + "from the UI thread. [in ListVIEw(" + getId() + ", " + getClass()

  + ") with Adapter(" + mAdapter.getClass() + ")]");

  }

  setSelectedPositionInt(mNextSelectedPosition);

  // Pull all children into the RecycleBin.

  // These vIEws will be reused if possible

  final int firstPosition = mFirstPosition;

  final RecycleBin recycleBin = mRecycler;

  接上頁

  // reset the focus restoration

  VIEw focusLayoutRestoreDirectChild = null;

  // Don't put header or footer vIEws into the Recycler. Those are

  // already cached in mHeaderVIEws;

  if (dataChanged) {

  for (int i = 0; i < childCount; i++) {

  recycleBin.addScrapVIEw(getChildAt(i));

  if (VIEwDebug.TRACE_RECYCLER) {

  VIEwDebug.trace(getChildAt(i),

  VIEwDebug.RecyclerTraceType.MOVE_TO_SCRAP_HEAP, index, i);

  }

  }

  } else {

  recycleBin.fillActiveVIEws(childCount, firstPosition);

  }

  // take focus back to us temporarily to avoid the eventual

  // call to clear focus when removing the focused child below

  // from messing things up when VIEwRoot assigns focus back

  // to someone else

  final VIEw focusedChild = getFocusedChild();

  if (focusedChild != null) {

  // TODO: in some cases focusedChild.getParent() == null

  // we can remember the focused vIEw to restore after relayout if the

  // data hasn't changed, or if the focused position is a header or footer

  if (!dataChanged || isDirectChildHeaderOrFooter(focusedChild)) {

  focusLayoutRestoreDirectChild = focusedChild;

  // remember the specific vIEw that had focus

  focusLayoutRestoreVIEw = findFocus();

  if (focusLayoutRestoreVIEw != null) {

  // tell it we are going to mess with it

  focusLayoutRestoreVIEw.onStartTemporaryDetach();

  }

  }

  requestFocus();

  }

  // Clear out old vIEws

  //removeAllVIEwsInLayout();

  detachAllVIEwsFromParent();

  switch (mLayoutMode) {

  case LAYOUT_SET_SELECTION:

  if (newSel != null) {

  sel = fillFromSelection(newSel.getTop(), childrenTop, childrenBottom);

  接上頁

  } else {

  sel = fillFromMiddle(childrenTop, childrenBottom);

  }

  break;

  case LAYOUT_SYNC:

  sel = fillSpecific(mSyncPosition, mSpecificTop);

  break;

  case LAYOUT_FORCE_BOTTOM:

  sel = fillUp(mItemCount - 1, childrenBottom);

  adjustVIEwsUpOrDown();

  break;

  case LAYOUT_FORCE_TOP:

  mFirstPosition = 0;

  sel = fillFromTop(childrenTop);

  adjustVIEwsUpOrDown();

  break;

  case LAYOUT_SPECIFIC:

  sel = fillSpecific(reconcileSelectedPosition(), mSpecificTop);

  break;

  case LAYOUT_MOVE_SELECTION:

  sel = moveSelection(oldSel, newSel, delta, childrenTop, childrenBottom);

  break;

  default:

  if (childCount == 0) {

  if (!mStackFromBottom) {

  final int position = lookForSelectablePosition(0, true);

  setSelectedPositionInt(position);

  sel = fillFromTop(childrenTop);

  } else {

  final int position = lookForSelectablePosition(mItemCount - 1, false);

  setSelectedPositionInt(position);

  sel = fillUp(mItemCount - 1, childrenBottom);

  }

  } else {

  if (mSelectedPosition >= 0 && mSelectedPosition < mItemCount) {

  sel = fillSpecific(mSelectedPosition,

  oldSel == null ? childrenTop : oldSel.getTop());

  } else if (mFirstPosition < mItemCount) {

  sel = fillSpecific(mFirstPosition,

  oldFirst == null ? childrenTop : oldFirst.getTop());

  } else {

  sel = fillSpecific(0, childrenTop);

  }

  }

  break;

  }

  // Flush any cached vIEws that did not get reused above

  recycleBin.scrapActiveVIEws();

  if (sel != null) {

  // the current selected item should get focus if items

  接上頁

  // are focusable

  if (mItemsCanFocus && hasFocus() && !sel.hasFocus()) {

  final boolean focusWasTaken = (sel == focusLayoutRestoreDirectChild &&

  focusLayoutRestoreVIEw.requestFocus()) || sel.requestFocus();

  if (!focusWasTaken) {

  // selected item didn't take focus, fine, but still want

  // to make sure something else outside of the selected vIEw

  // has focus

  final VIEw focused = getFocusedChild();

  if (focused != null) {

  focused.clearFocus();

  }

  positionSelector(sel);

  } else {

  sel.setSelected(false);

  mSelectorRect.setEmpty();

  }

  } else {

  positionSelector(sel);

  }

  mSelectedTop = sel.getTop();

  } else {

  if (mTouchMode > TOUCH_MODE_DOWN && mTouchMode < TOUCH_MODE_SCROLL) {

  VIEw child = getChildAt(mMotionPosition - mFirstPosition);

  if (child != null) positionSelector(child);

  } else {

  mSelectedTop = 0;

  mSelectorRect.setEmpty();

  }

  // even if there is not selected position, we may need to restore

  // focus (i.e. something focusable in touch mode)

  if (hasFocus() && focusLayoutRestoreVIEw != null) {

  focusLayoutRestoreVIEw.requestFocus();

  }

  }

  // tell focus vIEw we are done mucking with it, if it is still in

  // our view hIErarchy.

  if (focusLayoutRestoreVIEw != null

  && focusLayoutRestoreVIEw.getWindowToken() != null) {

  focusLayoutRestoreVIEw.onFinishTemporaryDetach();

  }

  mLayoutMode = LAYOUT_NORMAL;

  mDat

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved