适配器模式

2016-06-27  本文已影响42人  jacky123

前言:

定义:适配器模式是把一个类的接口变换成客户端所期待的另一种接口,从而使得原本因接口不匹配而无法一起工作的两个类能协同工作。

适配器是将两个不兼容的类融合在一起,它有点像粘合剂,将不同的东西通过一个转换使得它们能够协作起来.


Android源码的适配器模式

1.首先看ListView的父类,AbsListView。

public abstract class AbsListView extends AdapterView<ListAdapter> implements TextWatcher,
        ViewTreeObserver.OnGlobalLayoutListener, Filter.FilterListener,
        ViewTreeObserver.OnTouchModeChangeListener,
        RemoteViewsAdapter.RemoteAdapterConnectionCallback {
    ListAdapter mAdapter;
    
    /**
     * 关联到 Window时,通过 Adapter来获取 Item View 的数量、布局、数据等
     */
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();

        final ViewTreeObserver treeObserver = getViewTreeObserver();
        treeObserver.addOnTouchModeChangeListener(this);
        if (mTextFilterEnabled && mPopup != null && !mGlobalLayoutListenerAddedFilter) {
            treeObserver.addOnGlobalLayoutListener(this);
        }

        /**
         * 给设配器注册一个观察者
         */
        if (mAdapter != null && mDataSetObserver == null) {
            mDataSetObserver = new AdapterDataSetObserver();
            mAdapter.registerDataSetObserver(mDataSetObserver);

            // Data may have changed while we were detached. Refresh.
            mDataChanged = true;
            mOldItemCount = mItemCount;
            mItemCount = mAdapter.getCount();
        }
    }
    
    
    /**
     * Subclasses should NOT override this method but
     *  {@link #layoutChildren()} instead.
     */
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);

        mInLayout = true;

        final int childCount = getChildCount();
        if (changed) {
            for (int i = 0; i < childCount; i++) {
                getChildAt(i).forceLayout();
            }
            mRecycler.markChildrenDirty();
        }

        //布局 Child View
        layoutChildren();
        mInLayout = false;

        mOverscrollMax = (b - t) / OVERSCROLL_LIMIT_DIVISOR;

        // TODO: Move somewhere sane. This doesn't belong in onLayout().
        if (mFastScroll != null) {
            mFastScroll.onItemCountChanged(getChildCount(), mItemCount);
        }
    }
}

AbsListView 定义了集合视图的逻辑框架,比如 Adapter模式的应用、复用 Item View 的逻辑、布局自视图的逻辑等。

2.ListView 覆写了的 layoutChildren。

ListView 覆写了 AbsListView 中的 layoutChildren。在 layoutChildren 中根据布局模式来布局 Item View,例如有从上而下,也有从下而上开始布局的(qq聊天的气泡布局,最新的消息到窗口的最底部)。我们来看看这两种实现

  1. 从上而下填充 Item View(只是其中的一种方式)
 /**
 * 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);
    if ((mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {
        end -= 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++;
    }

    setVisibleRangeHint(mFirstPosition, mFirstPosition + getChildCount() - 1);
    return selectedView;
}

总结:

ListView 等集合控件通过 Adapter来获取 Item View 的数量、布局、数据等,在这里尤为重要的就是 View类型的对象,也就是 Item View.由于它返回的是一个 View抽象,而千变万化的 UI视图都是 View 的子类,通过依赖抽象原则和 Adapter 模式就将 Item View 的变化隔离了,保证了 AbsListView 类族的高度可定制化。在获取到 View之后,将这些 View 通过特定的布局方式设置到对应的位置,再加上 Item View 的复用机制,整个 ListView就运转起来了。

深度拓展 RecyclerView

上一篇 下一篇

猜你喜欢

热点阅读