先看效果图.![下拉刷新]!


package zhuxiaohao.com.cn.slidingtabforlistview.custom;import android.content.Context;import android.util.AttributeSet;import android.widget.ScrollView;/** * Project Name:zhuxiaohao.com.cn.slidingtabforlistview.custom * File Name: SlidingTabForListview * Date:15/8/7上午12:3108 * blog:http://blog.csdn.net/qq718799510?viewmode=contents * Copyright (c) 2015, zhuxiaohao All Rights Reserved. */public class CustomScrollView extends ScrollView {    private Callbacks mCallbacks;    public CustomScrollView(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    protected void onScrollChanged(int l, int t, int oldl, int oldt) {        super.onScrollChanged(l, t, oldl, oldt);        if (mCallbacks != null) {            mCallbacks.onScrollChanged(t);        }    }    @Override    public boolean onTouchEvent(android.view.MotionEvent ev) {        if (mCallbacks != null) {            switch (ev.getActionMasked()) {                case android.view.MotionEvent.ACTION_DOWN:                    mCallbacks.onDownMotionEvent();                    break;                case android.view.MotionEvent.ACTION_UP:                case android.view.MotionEvent.ACTION_CANCEL:                    mCallbacks.onUpOrCancelMotionEvent();                    break;            }        }        return super.onTouchEvent(ev);    }    @Override    public int computeVerticalScrollRange() {        return super.computeVerticalScrollRange();    }    public void setCallbacks(Callbacks listener) {        mCallbacks = listener;    }    /**     * Callback  is interface     */    public static interface Callbacks {        public void onScrollChanged(int scrollY);        public void onDownMotionEvent();        public void onUpOrCancelMotionEvent();    }}这里重写 scrollview 监听 scroll事件时候置顶 Tab.
package zhuxiaohao.com.cn.slidingtabforlistview.custom;import android.content.Context;import android.content.res.TypedArray;import android.graphics.drawable.Drawable;import android.os.Build.VERSION;import android.os.Build.VERSION_CODES;import android.util.AttributeSet;import android.widget.LinearLayout;/** * Project Name:zhuxiaohao.com.cn.slidingtabforlistview.custom * File Name: SlidingTabForListview * Date:15/8/7上午12:2608 * blog:http://blog.csdn.net/qq718799510?viewmode=contents * Copyright (c) 2015, zhuxiaohao All Rights Reserved. */public class CustomLinearLayout extends LinearLayout {    private static final int[] R_styleable_LinearLayout = new int[] {        /* 0 */ android.R.attr.divider,        /* 1 */ android.R.attr.measureWithLargestChild,        /* 2 */ android.R.attr.showDividers,        /* 3 */ android.R.attr.dividerPadding,    };    private static final int LinearLayout_divider = 0;    private static final int LinearLayout_measureWithLargestChild = 1;    private static final int LinearLayout_showDividers = 2;    private static final int LinearLayout_dividerPadding = 3;    /**     * Don't show any dividers.     */    public static final int SHOW_DIVIDER_NONE = 0;    /**     * Show a divider at the beginning of the group.     */    public static final int SHOW_DIVIDER_BEGINNING = 1;    /**     * Show dividers between each item in the group.     */    public static final int SHOW_DIVIDER_MIDDLE = 2;    /**     * Show a divider at the end of the group.     */    public static final int SHOW_DIVIDER_END = 4;    private static final boolean IS_HONEYCOMB = VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB;    private Drawable mDivider;    protected int mDividerWidth;    protected int mDividerHeight;    private int mShowDividers;    private int mDividerPadding;    private boolean mClipDivider;    private boolean mUseLargestChild;    public CustomLinearLayout(Context context, AttributeSet attrs) {        super(context, attrs);        TypedArray a = context.obtainStyledAttributes(attrs, /*com.android.internal.R.styleable.*/R_styleable_LinearLayout);        setDividerDrawable(a.getDrawable(/*com.android.internal.R.styleable.*/LinearLayout_divider));        mShowDividers = a.getInt(/*com.android.internal.R.styleable.*/LinearLayout_showDividers, SHOW_DIVIDER_NONE);        mDividerPadding = a.getDimensionPixelSize(/*com.android.internal.R.styleable.*/LinearLayout_dividerPadding, 0);        mUseLargestChild = a.getBoolean(/*com.android.internal.R.styleable.*/LinearLayout_measureWithLargestChild, false);        a.recycle();    }    /**     * Set how dividers should be shown between items in this layout     *     * @param showDividers One or more of {@link #SHOW_DIVIDER_BEGINNING},     *                     {@link #SHOW_DIVIDER_MIDDLE}, or {@link #SHOW_DIVIDER_END},     *                     or {@link #SHOW_DIVIDER_NONE} to show no dividers.     */    public void setShowDividers(int showDividers) {        if (showDividers != mShowDividers) {            requestLayout();            invalidate(); //XXX This is required if you are toggling a divider off        }        mShowDividers = showDividers;    }    /**     * @return A flag set indicating how dividers should be shown around items.     * @see #setShowDividers(int)     */    public int getShowDividers() {        return mShowDividers;    }    /**     * Set a drawable to be used as a divider between items.     * @param divider Drawable that will divide each item.     * @see #setShowDividers(int)     */    public void setDividerDrawable(Drawable divider) {        if (divider == mDivider) {            return;        }        mDivider = divider;        mClipDivider = divider instanceof android.graphics.drawable.ColorDrawable;        if (divider != null) {            mDividerWidth = divider.getIntrinsicWidth();            mDividerHeight = divider.getIntrinsicHeight();        } else {            mDividerWidth = 0;            mDividerHeight = 0;        }        setWillNotDraw(divider == null);        requestLayout();    }    /**     * Set padding displayed on both ends of dividers.     *     * @param padding Padding value in pixels that will be applied to each end     *     * @see #setShowDividers(int)     * @see #setDividerDrawable(Drawable)     * @see #getDividerPadding()     */    public void setDividerPadding(int padding) {        mDividerPadding = padding;    }    /**     * Get the padding size used to inset dividers in pixels     *     * @see #setShowDividers(int)     * @see #setDividerDrawable(Drawable)     * @see #setDividerPadding(int)     */    public int getDividerPadding() {        return mDividerPadding;    }    /**     * Get the width of the current divider drawable.     *     * @hide Used internally by framework.     */    public int getDividerWidth() {        return mDividerWidth;    }    @Override    protected void measureChildWithMargins(android.view.View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {        final int index = indexOfChild(child);        final int orientation = getOrientation();        final LayoutParams params = (LayoutParams) child.getLayoutParams();        if (hasDividerBeforeChildAt(index)) {            if (orientation == VERTICAL) {                //Account for the divider by pushing everything up                params.topMargin = mDividerHeight;            } else {                //Account for the divider by pushing everything left                params.leftMargin = mDividerWidth;            }        }        final int count = getChildCount();        if (index == count - 1) {            if (hasDividerBeforeChildAt(count)) {                if (orientation == VERTICAL) {                    params.bottomMargin = mDividerHeight;                } else {                    params.rightMargin = mDividerWidth;                }            }        }        super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);    }    @Override    protected void onDraw(android.graphics.Canvas canvas) {        if (mDivider != null) {            if (getOrientation() == VERTICAL) {                drawDividersVertical(canvas);            } else {                drawDividersHorizontal(canvas);            }        }        super.onDraw(canvas);    }    void drawDividersVertical(android.graphics.Canvas canvas) {        final int count = getChildCount();        for (int i = 0; i < count; i++) {            final android.view.View child = getChildAt(i);            if (child != null && child.getVisibility() != GONE) {                if (hasDividerBeforeChildAt(i)) {                    final LayoutParams lp = (LayoutParams) child.getLayoutParams();                    final int top = child.getTop() - lp.topMargin/* - mDividerHeight*/;                    drawHorizontalDivider(canvas, top);                }            }        }        if (hasDividerBeforeChildAt(count)) {            final android.view.View child = getChildAt(count - 1);            int bottom = 0;            if (child == null) {                bottom = getHeight() - getPaddingBottom() - mDividerHeight;            } else {                //final LayoutParams lp = (LayoutParams) child.getLayoutParams();                bottom = child.getBottom()/* + lp.bottomMargin*/;            }            drawHorizontalDivider(canvas, bottom);        }    }    void drawDividersHorizontal(android.graphics.Canvas canvas) {        final int count = getChildCount();        for (int i = 0; i < count; i++) {            final android.view.View child = getChildAt(i);            if (child != null && child.getVisibility() != GONE) {                if (hasDividerBeforeChildAt(i)) {                    final LayoutParams lp = (LayoutParams) child.getLayoutParams();                    final int left = child.getLeft() - lp.leftMargin/* - mDividerWidth*/;                    drawVerticalDivider(canvas, left);                }            }        }        if (hasDividerBeforeChildAt(count)) {            final android.view.View child = getChildAt(count - 1);            int right = 0;            if (child == null) {                right = getWidth() - getPaddingRight() - mDividerWidth;            } else {                //final LayoutParams lp = (LayoutParams) child.getLayoutParams();                right = child.getRight()/* + lp.rightMargin*/;            }            drawVerticalDivider(canvas, right);        }    }    void drawHorizontalDivider(android.graphics.Canvas canvas, int top) {        if(mClipDivider && !IS_HONEYCOMB) {            canvas.save();            canvas.clipRect(getPaddingLeft() + mDividerPadding, top,                    getWidth() - getPaddingRight() - mDividerPadding, top + mDividerHeight);            mDivider.draw(canvas);            canvas.restore();        } else {            mDivider.setBounds(getPaddingLeft() + mDividerPadding, top,                    getWidth() - getPaddingRight() - mDividerPadding, top + mDividerHeight);            mDivider.draw(canvas);        }    }    void drawVerticalDivider(android.graphics.Canvas canvas, int left) {        if(mClipDivider && !IS_HONEYCOMB) {            canvas.save();            canvas.clipRect(left, getPaddingTop() + mDividerPadding,                    left + mDividerWidth, getHeight() - getPaddingBottom() - mDividerPadding);            mDivider.draw(canvas);            canvas.restore();        } else {            mDivider.setBounds(left, getPaddingTop() + mDividerPadding,                    left + mDividerWidth, getHeight() - getPaddingBottom() - mDividerPadding);            mDivider.draw(canvas);        }    }    /**     * Determines where to position dividers between children.     *     * @param childIndex Index of child to check for preceding divider     * @return true if there should be a divider before the child at childIndex     * @hide Pending API consideration. Currently only used internally by the system.     */    protected boolean hasDividerBeforeChildAt(int childIndex) {        if (childIndex == 0) {            return (mShowDividers & SHOW_DIVIDER_BEGINNING) != 0;        } else if (childIndex == getChildCount()) {            return (mShowDividers & SHOW_DIVIDER_END) != 0;        } else if ((mShowDividers & SHOW_DIVIDER_MIDDLE) != 0) {            boolean hasVisibleViewBefore = false;            for (int i = childIndex - 1; i >= 0; i--) {                if (getChildAt(i).getVisibility() != GONE) {                    hasVisibleViewBefore = true;                    break;                }            }            return hasVisibleViewBefore;        }        return false;    }    /**     * When true, all children with a weight will be considered having     * the minimum size of the largest child. If false, all children are     * measured normally.     *     * @return True to measure children with a weight using the minimum     *         size of the largest child, false otherwise.     *     * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild     */    public boolean isMeasureWithLargestChildEnabled() {        return mUseLargestChild;    }    /**     * When set to true, all children with a weight will be considered having     * the minimum size of the largest child. If false, all children are     * measured normally.     *     * Disabled by default.     *     * @param enabled True to measure children with a weight using the     *        minimum size of the largest child, false otherwise.     *     * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild     */    public void setMeasureWithLargestChildEnabled(boolean enabled) {        mUseLargestChild = enabled;    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        if (mUseLargestChild) {            final int orientation = getOrientation();            switch (orientation) {                case HORIZONTAL:                    useLargestChildHorizontal();                    break;                case VERTICAL:                    useLargestChildVertical();                    break;            }        }    }    private void useLargestChildHorizontal() {        final int childCount = getChildCount();        // Find largest child width        int largestChildWidth = 0;        for (int i = 0; i < childCount; i++) {            final android.view.View child = getChildAt(i);            largestChildWidth = Math.max(child.getMeasuredWidth(), largestChildWidth);        }        int totalWidth = 0;        // Re-measure childs        for (int i = 0; i < childCount; i++) {            final android.view.View child = getChildAt(i);            if (child == null || child.getVisibility() == android.view.View.GONE) {                continue;            }            final LayoutParams lp =                    (LayoutParams) child.getLayoutParams();            float childExtra = lp.weight;            if (childExtra > 0) {                child.measure(                        MeasureSpec.makeMeasureSpec(largestChildWidth,                                MeasureSpec.EXACTLY),                        MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(),                                MeasureSpec.EXACTLY));                totalWidth += largestChildWidth;            } else {                totalWidth += child.getMeasuredWidth();            }            totalWidth += lp.leftMargin + lp.rightMargin;        }        totalWidth += getPaddingLeft() + getPaddingRight();        setMeasuredDimension(totalWidth, getMeasuredHeight());    }    private void useLargestChildVertical() {        final int childCount = getChildCount();        // Find largest child width        int largestChildHeight = 0;        for (int i = 0; i < childCount; i++) {            final android.view.View child = getChildAt(i);            largestChildHeight = Math.max(child.getMeasuredHeight(), largestChildHeight);        }        int totalHeight = 0;        // Re-measure childs        for (int i = 0; i < childCount; i++) {            final android.view.View child = getChildAt(i);            if (child == null || child.getVisibility() == android.view.View.GONE) {                continue;            }            final LayoutParams lp =                    (LayoutParams) child.getLayoutParams();            float childExtra = lp.weight;            if (childExtra > 0) {                child.measure(                        MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(),                                MeasureSpec.EXACTLY),                        MeasureSpec.makeMeasureSpec(largestChildHeight,                                MeasureSpec.EXACTLY));                totalHeight += largestChildHeight;            } else {                totalHeight += child.getMeasuredHeight();            }            totalHeight += lp.leftMargin + lp.rightMargin;        }        totalHeight += getPaddingLeft() + getPaddingRight();        setMeasuredDimension(getMeasuredWidth(), totalHeight);    }}

重写 linearlayout 让他具备 listview功能.

package zhuxiaohao.com.cn.slidingtabforlistview.custom;import android.content.Context;import android.content.res.TypedArray;import android.database.DataSetObserver;import android.util.AttributeSet;import android.view.SoundEffectConstants;import android.view.View;import android.widget.FrameLayout;import android.widget.ListAdapter;/** * Project Name:zhuxiaohao.com.cn.slidingtabforlistview.custom * File Name: SlidingTabForListview * Date:15/8/7上午12:2908 * blog:http://blog.csdn.net/qq718799510?viewmode=contents * Copyright (c) 2015, zhuxiaohao All Rights Reserved. */public class LinearListView extends CustomLinearLayout {    private static final int[] R_styleable_LinearListView = new int[] {            android.R.attr.entries,            zhuxiaohao.com.cn.slidingtabforlistview.R.attr.dividerThickness    };    private static final int LinearListView_entries = 0;    private static final int LinearListView_dividerThickness = 1;    private View mEmptyView;    private ListAdapter mAdapter;    private boolean mAreAllItemsSelectable;    private OnItemClickListener mOnItemClickListener;    private DataSetObserver mDataObserver = new DataSetObserver() {        @Override        public void onChanged() {            setupChildren();        }        @Override        public void onInvalidated() {            setupChildren();        }    };    public LinearListView(Context context) {        this(context, null);    }    public LinearListView(Context context, AttributeSet attrs) {        super(context, attrs);        TypedArray a = context.obtainStyledAttributes(attrs,                R_styleable_LinearListView);        // Use the thickness specified, zero being the default        final int thickness = a.getDimensionPixelSize(                LinearListView_dividerThickness, 0);        if (thickness != 0) {            setDividerThickness(thickness);        }        CharSequence[] entries = a.getTextArray(LinearListView_entries);        if (entries != null) {            setAdapter(new android.widget.ArrayAdapter(context,                    android.R.layout.simple_list_item_1, entries));        }        a.recycle();    }    @Override    public void setOrientation(int orientation) {        if (orientation != getOrientation()) {            int tmp = mDividerHeight;            mDividerHeight = mDividerWidth;            mDividerWidth = tmp;        }        super.setOrientation(orientation);    }    /**     * Set the divider thickness size in pixel. That means setting the divider     * height if the layout has an HORIZONTAL orientation and setting the     * divider width otherwise.     *     * @param thickness     *            The divider thickness in pixel.     */    public void setDividerThickness(int thickness) {        if (getOrientation() == VERTICAL) {            mDividerHeight = thickness;        } else {            mDividerWidth = thickness;        }        requestLayout();    }    public ListAdapter getAdapter() {        return mAdapter;    }    /**     * Sets the data behind this LinearListView.     *     * @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()     */    public void setAdapter(ListAdapter adapter) {        if (mAdapter != null) {            mAdapter.unregisterDataSetObserver(mDataObserver);        }        mAdapter = adapter;        if (mAdapter != null) {            mAdapter.registerDataSetObserver(mDataObserver);            mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();        }        setupChildren();    }    /**     * Interface definition for a callback to be invoked when an item in this     * LinearListView has been clicked.     */    public interface OnItemClickListener {        /**         * Callback method to be invoked when an item in this LinearListView has         * been clicked.         * 

* Implementers can call getItemAtPosition(position) if they need to * access the data associated with the selected item. * * @param parent * The LinearListView where the click happened. * @param view * The view within the LinearListView that was clicked (this * will be a view provided by the adapter) * @param position * The position of the view in the adapter. * @param id * The row id of the item that was clicked. */ void onItemClick(LinearListView parent, View view, int position, long id); } /** * Register a callback to be invoked when an item in this LinearListView has * been clicked. * * @param listener * The callback that will be invoked. */ public void setOnItemClickListener(OnItemClickListener listener) { mOnItemClickListener = listener; } /** * @return The callback to be invoked with an item in this LinearListView has * been clicked, or null id no callback has been set. */ public final OnItemClickListener getOnItemClickListener() { return mOnItemClickListener; } /** * Call the OnItemClickListener, if it is defined. * * @param view * The view within the LinearListView that was clicked. * @param position * The position of the view in the adapter. * @param id * The row id of the item that was clicked. * @return True if there was an assigned OnItemClickListener that was * called, false otherwise is returned. */ public boolean performItemClick(View view, int position, long id) { if (mOnItemClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); mOnItemClickListener.onItemClick(this, view, position, id); return true; } return false; } /** * Sets the view to show if the adapter is empty */ public void setEmptyView(View emptyView) { mEmptyView = emptyView; final ListAdapter adapter = getAdapter(); final boolean empty = ((adapter == null) || adapter.isEmpty()); updateEmptyStatus(empty); } /** * When the current adapter is empty, the LinearListView can display a special * view call the empty view. The empty view is used to provide feedback to * the user that no data is available in this LinearListView. * * @return The view to show if the adapter is empty. */ public View getEmptyView() { return mEmptyView; } /** * Update the status of the list based on the empty parameter. If empty is * true and we have an empty view, display it. In all the other cases, make * sure that the layout is VISIBLE and that the empty view is GONE (if * it's not null). */ private void updateEmptyStatus(boolean empty) { if (empty) { if (mEmptyView != null) { mEmptyView.setVisibility(View.VISIBLE); setVisibility(View.GONE); } else { // If the caller just removed our empty view, make sure the list // view is visible setVisibility(View.VISIBLE); } } else { if (mEmptyView != null) mEmptyView.setVisibility(View.GONE); setVisibility(View.VISIBLE); } } private void setupChildren() { removeAllViews(); updateEmptyStatus((mAdapter == null) || mAdapter.isEmpty()); if (mAdapter == null) { return; } for (int i = 0; i < mAdapter.getCount(); i++) { View child = mAdapter.getView(i, null, this); if (mAreAllItemsSelectable || mAdapter.isEnabled(i)) { child.setOnClickListener(new InternalOnClickListener(i)); } addViewInLayout(child, -1, child.getLayoutParams(), true); } } /** * Internal OnClickListener that this view associate of each of its children * so that they can respond to OnItemClick listener's events. Avoid setting * an OnClickListener manually. If you need it you can wrap the child in a * simple {@link FrameLayout}. */ private class InternalOnClickListener implements OnClickListener { int mPosition; public InternalOnClickListener(int position) { mPosition = position; } @Override public void onClick(View v) { if ((mOnItemClickListener != null) && (mAdapter != null)) { mOnItemClickListener.onItemClick(LinearListView.this, v, mPosition, mAdapter.getItemId(mPosition)); } } }}

实现 linearlayout,让他可以像 listview 一样 setadapter,适配器要注意下要这样写.

minflater.inflate(R.layout.list_item, parent, false);

如果你这样写

minflater.inflate(R.layout.list_item,  false);

会报错.
好了,不细说了,具体看代码,有注释.不是我半夜起来写代码,而是我还在加班,抽点时间把博客补齐一下.有时间我会代码继续更新,github 会继续更新该 ui代码.

点我下载

更多相关文章

  1. 【Android】问题记录
  2. Android(安卓)TextView 丰富多彩的字体样式代码
  3. fragment中加载高德地图出现滑动冲突解决。
  4. Android(安卓)项目中常用到的第三方组件
  5. Android获取当前时间与星期几
  6. android 自带的日期控件 DatePicker
  7. android使用opengl es2.0播放视频
  8. 将网页嵌入到android应用中
  9. android WheelView时间选择器

随机推荐

  1. Android(安卓)IPC 通讯机制源码分析
  2. Android之Handler用法总结
  3. Android(安卓)中Popwindow弹出菜单的两种
  4. [置顶] 我的Android进阶之旅------>Andro
  5. android 使用Intent传递数据之静态变量
  6. AndroidManifest.xml学习
  7. Android中图像和图像处理
  8. Android(安卓)写一个属于自己的Rxjava(二)
  9. Android最佳实践之高效的应用导航
  10. android 值得学习的网站