Ui 篇:ScrollViewFroLinearLayout

来源:互联网 发布:出售数据资源 编辑:程序博客网 时间:2024/06/07 00:15

先看效果图.![下拉刷新]!
下拉刷新
隐藏 Tab
linearlayout 列表

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<CharSequence>(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.         * <p>         * 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代码.

点我下载

0 0