binbinyang-----自定义VIEW.刻度尺.左右滑动选择对应数值

来源:互联网 发布:淘宝商品排行榜怎么看 编辑:程序博客网 时间:2024/05/05 16:24

 很多APP.如今会用到横向刻度尺,或是纵向刻度尺....比如在个人资料填入.或是减肥APP里面...随处可见

今天我带来一个 

先发,我录制的动态GIF效果图

放代码


主Activity

public class MainActivity extends AppCompatActivity implements  HorizontalPicker.OnItemSelected, HorizontalPicker.OnItemClicked {    HorizontalPicker pick;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //数据类型(0 卡路里,100-2000, 1:步数 2000-20000 2;公里:1-20        //默认选中数        pick  =(HorizontalPicker)findViewById(R.id.picker);        pick.setDataType(2,"10");        pick.setOnItemClickedListener(this);        pick.setOnItemSelectedListener(this);    }    @Override    public void onItemClicked(int index) {        Toast.makeText(this, index+"", 1).show();    }    @Override    public void onItemSelected(String item) {        Toast.makeText(this, item, 1).show();    }}


xml布局

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"              xmlns:app="http://schemas.android.com/apk/res-auto"              xmlns:tools="http://schemas.android.com/tools"              android:layout_width="match_parent"              android:layout_height="match_parent"              android:background="#FFFFFF"              android:orientation="vertical"               >    <com.example.yangbin.pickm.HorizontalPicker        android:id="@+id/picker"        android:layout_width="match_parent"        android:layout_height="80dp"        android:layout_marginTop="30dp"        android:background="#FFFFFF"        android:ellipsize="marquee"        android:focusable="true"        android:focusableInTouchMode="true"        android:marqueeRepeatLimit="2"        android:paddingBottom="16dp"        android:paddingTop="16dp"        android:textColor="#727272"        android:textSize="22sp"        app:dividerSize="0dp"        app:sideItems="2" />    <com.example.yangbin.pickm.MyScaleView        android:layout_width="wrap_content"        android:layout_height="15dp" /></LinearLayout>


自定义 

HorizontalPicker
/* * Copyright 2014 Blaž Šolar * * 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 com.example.yangbin.pickm;import android.animation.ArgbEvaluator;import android.annotation.TargetApi;import android.content.Context;import android.content.res.ColorStateList;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Rect;import android.graphics.RectF;import android.os.Build;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.os.Parcel;import android.os.Parcelable;import android.support.v4.text.TextDirectionHeuristicCompat;import android.support.v4.text.TextDirectionHeuristicsCompat;import android.support.v4.view.ViewCompat;import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;import android.support.v4.widget.ExploreByTouchHelper;import android.text.BoringLayout;import android.text.Layout;import android.text.TextPaint;import android.text.TextUtils;import android.util.AttributeSet;import android.view.KeyEvent;import android.view.MotionEvent;import android.view.VelocityTracker;import android.view.View;import android.view.ViewConfiguration;import android.view.accessibility.AccessibilityEvent;import android.view.animation.DecelerateInterpolator;import android.widget.EdgeEffect;import android.widget.OverScroller;import java.lang.ref.WeakReference;import java.util.ArrayList;import java.util.List;/** * Created by Blaž Šolar on 24/01/14. */public class HorizontalPicker extends View {    public static final String TAG = "HorizontalTimePicker";    /**     * The coefficient by which to adjust (divide) the max fling velocity.     */    private static final int SELECTOR_MAX_FLING_VELOCITY_ADJUSTMENT = 4;    /**     * The the duration for adjusting the selector wheel.     */    private static final int SELECTOR_ADJUSTMENT_DURATION_MILLIS = 800;    /**     * Determines speed during touch scrolling.     */    private VelocityTracker mVelocityTracker;    /**     * @see ViewConfiguration#getScaledMinimumFlingVelocity()     */    private int mMinimumFlingVelocity;    /**     * @see ViewConfiguration#getScaledMaximumFlingVelocity()     */    private int maximumFlingVelocity;    private final int overscrollDistance;    private int touchSlop;    private CharSequence[] values;    private BoringLayout[] layouts;    private TextPaint textPaint;    private BoringLayout.Metrics boringMetrics;    private TextUtils.TruncateAt ellipsize;    private int itemWidth;    private RectF itemClipBounds;    private RectF itemClipBoundsOffset;    private float lastDownEventX;    private OverScroller flingScrollerX;    private OverScroller adjustScrollerX;    private int previousScrollerX;    private boolean scrollingX;    private int pressedItem = -1;    private ColorStateList textColor;    private OnItemSelected onItemSelected;    private OnItemClicked onItemClicked;    private int selectedItem;    private EdgeEffect leftEdgeEffect;    private EdgeEffect rightEdgeEffect;    private Marquee marquee;    private int marqueeRepeatLimit = 3;    private float dividerSize = 0;    private int sideItems = 1;    private TextDirectionHeuristicCompat textDir;    private final PickerTouchHelper touchHelper;    private Paint paint;    private int mWidth;    private int mHeight;    private String[] arrays;    private int mDataType = 0;    public void setDataType(int type, String value) {        mDataType = type;        setValues(getData(mDataType));        setSelectedItem(value);        invalidate();    }    public int getDataType() {        return mDataType;    }    private void init() {        paint = new Paint();        paint.setColor(Color.GRAY);        paint.setAntiAlias(true);        paint.setStrokeWidth(2);    }    public HorizontalPicker(Context context) {        this(context, null);    }    public HorizontalPicker(Context context, AttributeSet attrs) {        this(context, attrs, R.attr.horizontalPickerStyle);    }    public HorizontalPicker(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        init();        // create the selector wheel paint        TextPaint paint = new TextPaint();        paint.setAntiAlias(true);        textPaint = paint;        TypedArray a = context.getTheme().obtainStyledAttributes(                attrs,                R.styleable.HorizontalPicker,                defStyle, 0        );        int ellipsize = 3; // END default value        int sideItems = this.sideItems;        try {            textColor = a.getColorStateList(R.styleable.HorizontalPicker_android_textColor);            if (textColor == null) {                textColor = ColorStateList.valueOf(0xFF000000);            }            ellipsize = a.getInt(R.styleable.HorizontalPicker_android_ellipsize, ellipsize);            marqueeRepeatLimit = a.getInt(R.styleable.HorizontalPicker_android_marqueeRepeatLimit, marqueeRepeatLimit);            dividerSize = a.getDimension(R.styleable.HorizontalPicker_dividerSize, dividerSize);            sideItems = a.getInt(R.styleable.HorizontalPicker_sideItems, sideItems);            float textSize = a.getDimension(R.styleable.HorizontalPicker_android_textSize, -1);            if (textSize > -1) {                setTextSize(textSize);            }        } finally {            a.recycle();        }        switch (ellipsize) {            case 1:                setEllipsize(TextUtils.TruncateAt.START);                break;            case 2:                setEllipsize(TextUtils.TruncateAt.MIDDLE);                break;            case 3:                setEllipsize(TextUtils.TruncateAt.END);                break;            case 4:                setEllipsize(TextUtils.TruncateAt.MARQUEE);                break;        }        Paint.FontMetricsInt fontMetricsInt = textPaint.getFontMetricsInt();        boringMetrics = new BoringLayout.Metrics();        boringMetrics.ascent = fontMetricsInt.ascent;        boringMetrics.bottom = fontMetricsInt.bottom;        boringMetrics.descent = fontMetricsInt.descent;        boringMetrics.leading = fontMetricsInt.leading;        boringMetrics.top = fontMetricsInt.top;        boringMetrics.width = itemWidth;        setWillNotDraw(false);        flingScrollerX = new OverScroller(context);        adjustScrollerX = new OverScroller(context, new DecelerateInterpolator(2.5f));        // initialize constants        ViewConfiguration configuration = ViewConfiguration.get(context);        touchSlop = configuration.getScaledTouchSlop();        mMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity();        maximumFlingVelocity = configuration.getScaledMaximumFlingVelocity()                / SELECTOR_MAX_FLING_VELOCITY_ADJUSTMENT;        overscrollDistance = configuration.getScaledOverscrollDistance();        previousScrollerX = Integer.MIN_VALUE;        //********添加数据**********        setValues(getData(getDataType()));        setSideItems(sideItems);        touchHelper = new PickerTouchHelper(this);        ViewCompat.setAccessibilityDelegate(this, touchHelper);    }    /**     * 自定义数据     *     * @return     */    private String[] getData(int type) {        List<String> list = new ArrayList<>();        if (type == 1) {            arrays = new String[19];            for (int i = 2000; i <= 20000; i += 1000) {                list.add(i + "");            }            for (int k = 0; k < 19; k++) {                arrays[k] = list.get(k);            }        } else {            if (type == 0) {                arrays = new String[20];                for (int i = 100; i <= 2000; i += 100) {                    list.add(i + "");                }            } else if (type == 2) {                arrays = new String[20];                for (int i = 1; i <= 20; i += 1) {                    list.add(i + "");                }            }            for (int k = 0; k < 20; k++) {                arrays[k] = list.get(k);            }        }        return arrays;    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        int width = MeasureSpec.getSize(widthMeasureSpec);        int heightSize = MeasureSpec.getSize(heightMeasureSpec);        int height;        if (heightMode == MeasureSpec.EXACTLY) {            height = heightSize;        } else {            Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();            int heightText = (int) (Math.abs(fontMetrics.ascent) + Math.abs(fontMetrics.descent));            heightText += getPaddingTop() + getPaddingBottom();            if (heightMode == MeasureSpec.AT_MOST) {                height = Math.min(heightSize, heightText);            } else {                height = heightText;            }        }        setMeasuredDimension(width, height);    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        mWidth = getWidth();        mHeight = getHeight();        int saveCount = canvas.getSaveCount();        canvas.save();        int selectedItem = this.selectedItem;        float itemWithPadding = itemWidth + dividerSize;        // translate horizontal to center        canvas.translate(itemWithPadding * sideItems, 0);        if (values != null) {            for (int i = 0; i < values.length; i++) {                // set text color for item                textPaint.setColor(getTextColor(i));                // get text layout                BoringLayout layout = layouts[i];                int saveCountHeight = canvas.getSaveCount();                canvas.save();                float x = 0;                float lineWidth = layout.getLineWidth(0);                if (lineWidth > itemWidth) {                    if (isRtl(values[i])) {                        x += (lineWidth - itemWidth) / 2;                    } else {                        x -= (lineWidth - itemWidth) / 2;                    }                }                if (marquee != null && i == selectedItem) {                    x += marquee.getScroll();                }                // translate vertically to center                canvas.translate(-x, (canvas.getHeight() - layout.getHeight()) / 2);                RectF clipBounds;                if (x == 0) {                    clipBounds = itemClipBounds;                } else {                    clipBounds = itemClipBoundsOffset;                    clipBounds.set(itemClipBounds);                    clipBounds.offset(x, 0);                }                canvas.clipRect(clipBounds);                layout.draw(canvas);                if (marquee != null && i == selectedItem && marquee.shouldDrawGhost()) {                    canvas.translate(marquee.getGhostOffset(), 0);                    layout.draw(canvas);                }                // restore vertical translation                canvas.restoreToCount(saveCountHeight);                // 画刻度线                paint.setColor(getTextColor(i));                canvas.drawLine(itemWidth / 2, mHeight - 20, itemWidth / 2, mHeight - 45, paint);                // translate horizontal for 1 item                canvas.translate(itemWithPadding, 0);            }        }        // restore horizontal translation        canvas.restoreToCount(saveCount);        drawEdgeEffect(canvas, leftEdgeEffect, 270);        drawEdgeEffect(canvas, rightEdgeEffect, 90);    }    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)    @Override    public void onRtlPropertiesChanged(int layoutDirection) {        super.onRtlPropertiesChanged(layoutDirection);        textDir = getTextDirectionHeuristic();    }    /**     * TODO cache values     *     * @param text     * @return     */    private boolean isRtl(CharSequence text) {        if (textDir == null) {            textDir = getTextDirectionHeuristic();        }        return textDir.isRtl(text, 0, text.length());    }    private TextDirectionHeuristicCompat getTextDirectionHeuristic() {        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {            return TextDirectionHeuristicsCompat.FIRSTSTRONG_LTR;        } else {            // Always need to resolve layout direction first            final boolean defaultIsRtl = (getLayoutDirection() == LAYOUT_DIRECTION_RTL);            switch (getTextDirection()) {                default:                case TEXT_DIRECTION_FIRST_STRONG:                    return (defaultIsRtl ? TextDirectionHeuristicsCompat.FIRSTSTRONG_RTL :                            TextDirectionHeuristicsCompat.FIRSTSTRONG_LTR);                case TEXT_DIRECTION_ANY_RTL:                    return TextDirectionHeuristicsCompat.ANYRTL_LTR;                case TEXT_DIRECTION_LTR:                    return TextDirectionHeuristicsCompat.LTR;                case TEXT_DIRECTION_RTL:                    return TextDirectionHeuristicsCompat.RTL;                case TEXT_DIRECTION_LOCALE:                    return TextDirectionHeuristicsCompat.LOCALE;            }        }    }    private void remakeLayout() {        if (layouts != null && layouts.length > 0 && getWidth() > 0) {            for (int i = 0; i < layouts.length; i++) {                layouts[i].replaceOrMake(values[i], textPaint, itemWidth,                        Layout.Alignment.ALIGN_CENTER, 1f, 1f, boringMetrics, false, ellipsize,                        itemWidth);            }        }    }    private void drawEdgeEffect(Canvas canvas, EdgeEffect edgeEffect, int degrees) {        if (canvas == null || edgeEffect == null || (degrees != 90 && degrees != 270)) {            return;        }        if (!edgeEffect.isFinished()) {            final int restoreCount = canvas.getSaveCount();            final int width = getWidth();            final int height = getHeight();            canvas.rotate(degrees);            if (degrees == 270) {                canvas.translate(-height, Math.max(0, getScrollX()));            } else { // 90                canvas.translate(0, -(Math.max(getScrollRange(), getScaleX()) + width));            }            edgeEffect.setSize(height, width);            if (edgeEffect.draw(canvas)) {                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {                    postInvalidateOnAnimation();                } else {                    postInvalidate();                }            }            canvas.restoreToCount(restoreCount);        }    }    /**     * Calculates text color for specified item based on its position and state.     *     * @param item Index of item to get text color for     * @return Item text color     */    private int getTextColor(int item) {        int scrollX = getScrollX();        // set color of text        int color = textColor.getDefaultColor();        int itemWithPadding = (int) (itemWidth + dividerSize);        if (scrollX > itemWithPadding * item - itemWithPadding / 2 &&                scrollX < itemWithPadding * (item + 1) - itemWithPadding / 2) {            int position = scrollX - itemWithPadding / 2;            color = getColor(position, item);        } else if (item == pressedItem) {            color = textColor.getColorForState(new int[]{android.R.attr.state_pressed}, color);        }        return color;    }    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);        calculateItemSize(w, h);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        if (!isEnabled()) {            return false;        }        if (mVelocityTracker == null) {            mVelocityTracker = VelocityTracker.obtain();        }        mVelocityTracker.addMovement(event);        int action = event.getActionMasked();        switch (action) {            case MotionEvent.ACTION_MOVE:                float currentMoveX = event.getX();                int deltaMoveX = (int) (lastDownEventX - currentMoveX);                if (scrollingX ||                        (Math.abs(deltaMoveX) > touchSlop) && values != null && values.length > 0) {                    if (!scrollingX) {                        deltaMoveX = 0;                        pressedItem = -1;                        scrollingX = true;                        getParent().requestDisallowInterceptTouchEvent(true);                        stopMarqueeIfNeeded();                    }                    final int range = getScrollRange();                    if (overScrollBy(deltaMoveX, 0, getScrollX(), 0, range, 0,                            overscrollDistance, 0, true)) {                        mVelocityTracker.clear();                    }                    final float pulledToX = getScrollX() + deltaMoveX;                    if (pulledToX < 0) {                        leftEdgeEffect.onPull((float) deltaMoveX / getWidth());                        if (!rightEdgeEffect.isFinished()) {                            rightEdgeEffect.onRelease();                        }                    } else if (pulledToX > range) {                        rightEdgeEffect.onPull((float) deltaMoveX / getWidth());                        if (!leftEdgeEffect.isFinished()) {                            leftEdgeEffect.onRelease();                        }                    }                    lastDownEventX = currentMoveX;                    invalidate();                }                break;            case MotionEvent.ACTION_DOWN:                if (!adjustScrollerX.isFinished()) {                    adjustScrollerX.forceFinished(true);                } else if (!flingScrollerX.isFinished()) {                    flingScrollerX.forceFinished(true);                } else {                    scrollingX = false;                }                lastDownEventX = event.getX();                if (!scrollingX) {                    pressedItem = getPositionFromTouch(event.getX());                }                invalidate();                break;            case MotionEvent.ACTION_UP:                VelocityTracker velocityTracker = mVelocityTracker;                velocityTracker.computeCurrentVelocity(1000, maximumFlingVelocity);                int initialVelocityX = (int) velocityTracker.getXVelocity();                if (scrollingX && Math.abs(initialVelocityX) > mMinimumFlingVelocity) {                    flingX(initialVelocityX);                } else if (values != null) {                    float positionX = event.getX();                    if (!scrollingX) {                        int itemPos = getPositionOnScreen(positionX);                        int relativePos = itemPos - sideItems;                        if (relativePos == 0) {                            selectItem();                        } else {                            smoothScrollBy(relativePos);                        }                    } else if (scrollingX) {                        finishScrolling();                    }                }                mVelocityTracker.recycle();                mVelocityTracker = null;                if (leftEdgeEffect != null) {                    leftEdgeEffect.onRelease();                    rightEdgeEffect.onRelease();                }            case MotionEvent.ACTION_CANCEL:                pressedItem = -1;                invalidate();                if (leftEdgeEffect != null) {                    leftEdgeEffect.onRelease();                    rightEdgeEffect.onRelease();                }                break;        }        return true;    }    private void selectItem() {        // post to the UI Thread to avoid potential interference with the OpenGL Thread        if (onItemClicked != null) {            post(new Runnable() {                @Override                public void run() {                    onItemClicked.onItemClicked(getSelectedItem());                }            });        }        adjustToNearestItemX();    }    @Override    public boolean onKeyDown(int keyCode, KeyEvent event) {        if (!isEnabled()) {            return super.onKeyDown(keyCode, event);        }        switch (keyCode) {            case KeyEvent.KEYCODE_DPAD_CENTER:            case KeyEvent.KEYCODE_ENTER:                selectItem();                return true;            case KeyEvent.KEYCODE_DPAD_LEFT:                smoothScrollBy(-1);                return true;            case KeyEvent.KEYCODE_DPAD_RIGHT:                smoothScrollBy(1);                return true;            default:                return super.onKeyDown(keyCode, event);        }    }    @Override    protected boolean dispatchHoverEvent(MotionEvent event) {        if (touchHelper.dispatchHoverEvent(event)) {            return true;        }        return super.dispatchHoverEvent(event);    }    @Override    public void computeScroll() {        computeScrollX();    }    @Override    public void getFocusedRect(Rect r) {        super.getFocusedRect(r); // TODO this should only be current item    }    public void setOnItemSelectedListener(OnItemSelected onItemSelected) {        this.onItemSelected = onItemSelected;    }    public void setOnItemClickedListener(OnItemClicked onItemClicked) {        this.onItemClicked = onItemClicked;    }    public int getSelectedItem() {        int x = getScrollX();        return getPositionFromCoordinates(x);    }    public void setSelectedItem(int index) {        selectedItem = index;        scrollToItem(index);    }    /**     * 设置选中项     *     * @param item     */    public void setSelectedItem(String item) {        selectedItem = getIndex(item);        scrollToItem(selectedItem);    }    /**     * 根据数据返回相应的下标     *     * @param item     * @return     */    private int getIndex(String item) {        for (int i = 0; i < arrays.length - 1; i++) {            if (arrays[i].equals(item))                return i;        }        return 0;    }    public int getMarqueeRepeatLimit() {        return marqueeRepeatLimit;    }    public void setMarqueeRepeatLimit(int marqueeRepeatLimit) {        this.marqueeRepeatLimit = marqueeRepeatLimit;    }    /**     * @return Number of items on each side of current item.     */    public int getSideItems() {        return sideItems;    }    public void setSideItems(int sideItems) {        if (this.sideItems < 0) {            throw new IllegalArgumentException("Number of items on each side must be grater or equal to 0.");        } else if (this.sideItems != sideItems) {            this.sideItems = sideItems;            calculateItemSize(getWidth(), getHeight());        }    }    /**     * @return     */    public CharSequence[] getValues() {        return values;    }    /**     * Sets values to choose from     *     * @param values New values to choose from     */    public void setValues(CharSequence[] values) {        if (this.values != values) {            this.values = values;            if (this.values != null) {                layouts = new BoringLayout[this.values.length];                for (int i = 0; i < layouts.length; i++) {                    layouts[i] = new BoringLayout(this.values[i], textPaint, itemWidth, Layout.Alignment.ALIGN_CENTER,                            1f, 1f, boringMetrics, false, ellipsize, itemWidth);                }            } else {                layouts = new BoringLayout[0];            }            // start marque only if has already been measured            if (getWidth() > 0) {                startMarqueeIfNeeded();            }            requestLayout();            invalidate();        }    }    @Override    protected void onRestoreInstanceState(Parcelable state) {        if (!(state instanceof SavedState)) {            super.onRestoreInstanceState(state);            return;        }        SavedState ss = (SavedState) state;        super.onRestoreInstanceState(ss.getSuperState());        setSelectedItem(ss.mSelItem);    }    @Override    protected Parcelable onSaveInstanceState() {        Parcelable superState = super.onSaveInstanceState();        SavedState savedState = new SavedState(superState);        savedState.mSelItem = selectedItem;        return savedState;    }    @Override    public void setOverScrollMode(int overScrollMode) {        if (overScrollMode != OVER_SCROLL_NEVER) {            Context context = getContext();            leftEdgeEffect = new EdgeEffect(context);            rightEdgeEffect = new EdgeEffect(context);        } else {            leftEdgeEffect = null;            rightEdgeEffect = null;        }        super.setOverScrollMode(overScrollMode);    }    public TextUtils.TruncateAt getEllipsize() {        return ellipsize;    }    public void setEllipsize(TextUtils.TruncateAt ellipsize) {        if (this.ellipsize != ellipsize) {            this.ellipsize = ellipsize;            remakeLayout();            invalidate();        }    }    @Override    protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {        super.scrollTo(scrollX, scrollY);        if (!flingScrollerX.isFinished() && clampedX) {            flingScrollerX.springBack(scrollX, scrollY, 0, getScrollRange(), 0, 0);        }    }    @Override    protected void drawableStateChanged() {        super.drawableStateChanged(); //TODO    }    private int getPositionFromTouch(float x) {        return getPositionFromCoordinates((int) (getScrollX() - (itemWidth + dividerSize) * (sideItems + .5f) + x));    }    private void computeScrollX() {        OverScroller scroller = flingScrollerX;        if (scroller.isFinished()) {            scroller = adjustScrollerX;            if (scroller.isFinished()) {                return;            }        }        if (scroller.computeScrollOffset()) {            int currentScrollerX = scroller.getCurrX();            if (previousScrollerX == Integer.MIN_VALUE) {                previousScrollerX = scroller.getStartX();            }            int range = getScrollRange();            if (previousScrollerX >= 0 && currentScrollerX < 0) {                leftEdgeEffect.onAbsorb((int) scroller.getCurrVelocity());            } else if (previousScrollerX <= range && currentScrollerX > range) {                rightEdgeEffect.onAbsorb((int) scroller.getCurrVelocity());            }            overScrollBy(currentScrollerX - previousScrollerX, 0, previousScrollerX, getScrollY(),                    getScrollRange(), 0, overscrollDistance, 0, false);            previousScrollerX = currentScrollerX;            if (scroller.isFinished()) {                onScrollerFinishedX(scroller);            }            postInvalidate();//            postInvalidateOnAnimation(); // TODO        }    }    private void flingX(int velocityX) {        previousScrollerX = Integer.MIN_VALUE;        flingScrollerX.fling(getScrollX(), getScrollY(), -velocityX, 0, 0,                (int) (itemWidth + dividerSize) * (values.length - 1), 0, 0, getWidth() / 2, 0);        invalidate();    }    private void adjustToNearestItemX() {        int x = getScrollX();        int item = Math.round(x / (itemWidth + dividerSize * 1f));        if (item < 0) {            item = 0;        } else if (item > values.length) {            item = values.length;        }        selectedItem = item;        int itemX = (itemWidth + (int) dividerSize) * item;        int deltaX = itemX - x;        previousScrollerX = Integer.MIN_VALUE;        adjustScrollerX.startScroll(x, 0, deltaX, 0, SELECTOR_ADJUSTMENT_DURATION_MILLIS);        invalidate();    }    private void calculateItemSize(int w, int h) {        int items = sideItems * 2 + 1;        int totalPadding = ((int) dividerSize * (items - 1));        itemWidth = (w - totalPadding) / items;        itemClipBounds = new RectF(0, 0, itemWidth, h);        itemClipBoundsOffset = new RectF(itemClipBounds);        scrollToItem(selectedItem);        remakeLayout();        startMarqueeIfNeeded();    }    private void onScrollerFinishedX(OverScroller scroller) {        if (scroller == flingScrollerX) {            finishScrolling();        }    }    private void finishScrolling() {        adjustToNearestItemX();        scrollingX = false;        startMarqueeIfNeeded();        // post to the UI Thread to avoid potential interference with the OpenGL Thread        if (onItemSelected != null) {            post(new Runnable() {                @Override                public void run() {//                    onItemSelected.onItemSelected(getPositionFromCoordinates(getScrollX()));                    onItemSelected.onItemSelected(arrays[getPositionFromCoordinates(getScrollX())]);                }            });        }    }    private void startMarqueeIfNeeded() {        stopMarqueeIfNeeded();        int item = getSelectedItem();        if (layouts != null && layouts.length > item) {            Layout layout = layouts[item];            if (ellipsize == TextUtils.TruncateAt.MARQUEE                    && itemWidth < layout.getLineWidth(0)) {                marquee = new Marquee(this, layout, isRtl(values[item]));                marquee.start(marqueeRepeatLimit);            }        }    }    private void stopMarqueeIfNeeded() {        if (marquee != null) {            marquee.stop();            marquee = null;        }    }    private int getPositionOnScreen(float x) {        return (int) (x / (itemWidth + dividerSize));    }    private void smoothScrollBy(int i) {        int deltaMoveX = (itemWidth + (int) dividerSize) * i;        deltaMoveX = getRelativeInBound(deltaMoveX);        previousScrollerX = Integer.MIN_VALUE;        flingScrollerX.startScroll(getScrollX(), 0, deltaMoveX, 0);        stopMarqueeIfNeeded();        invalidate();    }    /**     * Calculates color for specific position on time picker     * 修改选中颜色     *     * @param scrollX     * @return     */    private int getColor(int scrollX, int position) {        int itemWithPadding = (int) (itemWidth + dividerSize);        float proportion = Math.abs(((1f * scrollX % itemWithPadding) / 2) / (itemWithPadding / 2f));        if (proportion > .5) {            proportion = (proportion - .5f);        } else {            proportion = .5f - proportion;        }        proportion *= 2;        int defaultColor;        int selectedColor;        if (pressedItem == position) {            defaultColor = textColor.getColorForState(new int[]{android.R.attr.state_pressed}, textColor.getDefaultColor());//            selectedColor = textColor.getColorForState(new int[]{android.R.attr.state_pressed, android.R.attr.state_selected}, defaultColor);            selectedColor = Color.RED;        } else {            defaultColor = textColor.getDefaultColor();//            selectedColor = textColor.getColorForState(new int[]{android.R.attr.state_selected}, defaultColor);            selectedColor = Color.RED;        }        return (Integer) new ArgbEvaluator().evaluate(proportion, selectedColor, defaultColor);    }    /**     * Sets text size for items     *     * @param size New item text size in px.     */    private void setTextSize(float size) {        if (size != textPaint.getTextSize()) {            textPaint.setTextSize(size);            requestLayout();            invalidate();        }    }    /**     * Calculates item from x coordinate position.     *     * @param x Scroll position to calculate.     * @return Selected item from scrolling position in {param x}     */    private int getPositionFromCoordinates(int x) {        return Math.round(x / (itemWidth + dividerSize));    }    /**     * Scrolls to specified item.     *     * @param index Index of an item to scroll to     */    private void scrollToItem(int index) {        scrollTo((itemWidth + (int) dividerSize) * index, 0);        // invalidate() not needed because scrollTo() already invalidates the view    }    /**     * Calculates relative horizontal scroll position to be within our scroll bounds.     *     * @param x Relative scroll position to calculate     * @return Current scroll position + {param x} if is within our scroll bounds, otherwise it     * will return min/max scroll position.     */    private int getRelativeInBound(int x) {        int scrollX = getScrollX();        return getInBoundsX(scrollX + x) - scrollX;    }    /**     * Calculates x scroll position that is still in range of view scroller     *     * @param x Scroll position to calculate.     * @return {param x} if is within bounds of over scroller, otherwise it will return min/max     * value of scoll position.     */    private int getInBoundsX(int x) {        if (x < 0) {            x = 0;        } else if (x > ((itemWidth + (int) dividerSize) * (values.length - 1))) {            x = ((itemWidth + (int) dividerSize) * (values.length - 1));        }        return x;    }    private int getScrollRange() {        int scrollRange = 0;        if (values != null && values.length != 0) {            scrollRange = Math.max(0, ((itemWidth + (int) dividerSize) * (values.length - 1)));        }        return scrollRange;    }    public interface OnItemSelected {        //        public void onItemSelected(int index);        public void onItemSelected(String item);    }    public interface OnItemClicked {        public void onItemClicked(int index);    }    private static final class Marquee extends Handler {        // TODO: Add an option to configure this        private static final float MARQUEE_DELTA_MAX = 0.07f;        private static final int MARQUEE_DELAY = 1200;        private static final int MARQUEE_RESTART_DELAY = 1200;        private static final int MARQUEE_RESOLUTION = 1000 / 30;        private static final int MARQUEE_PIXELS_PER_SECOND = 30;        private static final byte MARQUEE_STOPPED = 0x0;        private static final byte MARQUEE_STARTING = 0x1;        private static final byte MARQUEE_RUNNING = 0x2;        private static final int MESSAGE_START = 0x1;        private static final int MESSAGE_TICK = 0x2;        private static final int MESSAGE_RESTART = 0x3;        private final WeakReference<HorizontalPicker> mView;        private final WeakReference<Layout> mLayout;        private byte mStatus = MARQUEE_STOPPED;        private final float mScrollUnit;        private float mMaxScroll;        private float mMaxFadeScroll;        private float mGhostStart;        private float mGhostOffset;        private float mFadeStop;        private int mRepeatLimit;        private float mScroll;        private boolean mRtl;        Marquee(HorizontalPicker v, Layout l, boolean rtl) {            final float density = v.getContext().getResources().getDisplayMetrics().density;            float scrollUnit = (MARQUEE_PIXELS_PER_SECOND * density) / MARQUEE_RESOLUTION;            if (rtl) {                mScrollUnit = -scrollUnit;            } else {                mScrollUnit = scrollUnit;            }            mView = new WeakReference<HorizontalPicker>(v);            mLayout = new WeakReference<Layout>(l);            mRtl = rtl;        }        @Override        public void handleMessage(Message msg) {            switch (msg.what) {                case MESSAGE_START:                    mStatus = MARQUEE_RUNNING;                    tick();                    break;                case MESSAGE_TICK:                    tick();                    break;                case MESSAGE_RESTART:                    if (mStatus == MARQUEE_RUNNING) {                        if (mRepeatLimit >= 0) {                            mRepeatLimit--;                        }                        start(mRepeatLimit);                    }                    break;            }        }        void tick() {            if (mStatus != MARQUEE_RUNNING) {                return;            }            removeMessages(MESSAGE_TICK);            final HorizontalPicker view = mView.get();            final Layout layout = mLayout.get();            if (view != null && layout != null && (view.isFocused() || view.isSelected())) {                mScroll += mScrollUnit;                if (Math.abs(mScroll) > mMaxScroll) {                    mScroll = mMaxScroll;                    if (mRtl) {                        mScroll *= -1;                    }                    sendEmptyMessageDelayed(MESSAGE_RESTART, MARQUEE_RESTART_DELAY);                } else {                    sendEmptyMessageDelayed(MESSAGE_TICK, MARQUEE_RESOLUTION);                }                view.invalidate();            }        }        void stop() {            mStatus = MARQUEE_STOPPED;            removeMessages(MESSAGE_START);            removeMessages(MESSAGE_RESTART);            removeMessages(MESSAGE_TICK);            resetScroll();        }        private void resetScroll() {            mScroll = 0.0f;            final HorizontalPicker view = mView.get();            if (view != null) view.invalidate();        }        void start(int repeatLimit) {            if (repeatLimit == 0) {                stop();                return;            }            mRepeatLimit = repeatLimit;            final HorizontalPicker view = mView.get();            final Layout layout = mLayout.get();            if (view != null && layout != null) {                mStatus = MARQUEE_STARTING;                mScroll = 0.0f;                final int textWidth = view.itemWidth;                final float lineWidth = layout.getLineWidth(0);                final float gap = textWidth / 3.0f;                mGhostStart = lineWidth - textWidth + gap;                mMaxScroll = mGhostStart + textWidth;                mGhostOffset = lineWidth + gap;                mFadeStop = lineWidth + textWidth / 6.0f;                mMaxFadeScroll = mGhostStart + lineWidth + lineWidth;                if (mRtl) {                    mGhostOffset *= -1;                }                view.invalidate();                sendEmptyMessageDelayed(MESSAGE_START, MARQUEE_DELAY);            }        }        float getGhostOffset() {            return mGhostOffset;        }        float getScroll() {            return mScroll;        }        float getMaxFadeScroll() {            return mMaxFadeScroll;        }        boolean shouldDrawLeftFade() {            return mScroll <= mFadeStop;        }        boolean shouldDrawGhost() {            return mStatus == MARQUEE_RUNNING && Math.abs(mScroll) > mGhostStart;        }        boolean isRunning() {            return mStatus == MARQUEE_RUNNING;        }        boolean isStopped() {            return mStatus == MARQUEE_STOPPED;        }    }    public static class SavedState extends BaseSavedState {        private int mSelItem;        public SavedState(Parcelable superState) {            super(superState);        }        private SavedState(Parcel in) {            super(in);            mSelItem = in.readInt();        }        @Override        public void writeToParcel(Parcel dest, int flags) {            super.writeToParcel(dest, flags);            dest.writeInt(mSelItem);        }        @Override        public String toString() {            return "HorizontalPicker.SavedState{"                    + Integer.toHexString(System.identityHashCode(this))                    + " selItem=" + mSelItem                    + "}";        }        @SuppressWarnings("hiding")        public static final Creator<SavedState> CREATOR                = new Creator<SavedState>() {            public SavedState createFromParcel(Parcel in) {                return new SavedState(in);            }            public SavedState[] newArray(int size) {                return new SavedState[size];            }        };    }    private static class PickerTouchHelper extends ExploreByTouchHelper {        private HorizontalPicker mPicker;        public PickerTouchHelper(HorizontalPicker picker) {            super(picker);            mPicker = picker;        }        @Override        protected int getVirtualViewAt(float x, float y) {            float itemWidth = mPicker.itemWidth + mPicker.dividerSize;            float position = mPicker.getScrollX() + x - itemWidth * mPicker.sideItems;            float item = position / itemWidth;            if (item < 0 || item > mPicker.values.length) {                return INVALID_ID;            }            return (int) item;        }        @Override        protected void getVisibleVirtualViews(List<Integer> virtualViewIds) {            float itemWidth = mPicker.itemWidth + mPicker.dividerSize;            float position = mPicker.getScrollX() - itemWidth * mPicker.sideItems;            int first = (int) (position / itemWidth);            int items = mPicker.sideItems * 2 + 1;            if (position % itemWidth != 0) { // if start next item is starting to appear on screen                items++;            }            if (first < 0) {                items += first;                first = 0;            } else if (first + items > mPicker.values.length) {                items = mPicker.values.length - first;            }            for (int i = 0; i < items; i++) {                virtualViewIds.add(first + i);            }        }        @Override        protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) {            event.setContentDescription(mPicker.values[virtualViewId]);        }        @Override        protected void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfoCompat node) {            float itemWidth = mPicker.itemWidth + mPicker.dividerSize;            float scrollOffset = mPicker.getScrollX() - itemWidth * mPicker.sideItems;            int left = (int) (virtualViewId * itemWidth - scrollOffset);            int right = left + mPicker.itemWidth;            node.setContentDescription(mPicker.values[virtualViewId]);            node.setBoundsInParent(new Rect(left, 0, right, mPicker.getHeight()));            node.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);        }        @Override        protected boolean onPerformActionForVirtualView(int virtualViewId, int action, Bundle arguments) {            return false;        }    }}
自定义
MyScaleView
package com.example.yangbin.pickm;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Path;import android.util.AttributeSet;import android.view.View;/** * Created by Administrator on 2016/9/2 0002. */public class MyScaleView extends View {    private Paint paint;    private int mWidth;    private int mHeight;    public MyScaleView(Context context) {        super(context);        init();    }    public MyScaleView(Context context, AttributeSet attrs) {        super(context, attrs);        init();    }    public MyScaleView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    private void init() {        paint = new Paint();        paint.setColor(Color.parseColor("#7E7E7E"));        paint.setAntiAlias(true);        paint.setStrokeWidth(2);    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        mWidth = getWidth();        mHeight = getHeight();        // 画一条线        canvas.drawLine(0f, mHeight, mWidth, mHeight, paint);        Path path = new Path();        path.moveTo(mWidth / 2, mHeight - 30);// 此点为多边形的起点        path.lineTo(mWidth / 2 - 20, mHeight);        path.lineTo(mWidth / 2 + 20, mHeight);        path.close(); // 使这些点构成封闭的多边形        canvas.drawPath(path, paint);    }    private int dp2px(int value) {        float v = getContext().getResources().getDisplayMetrics().density;        return (int) (v * value + 0.5f);    }}



0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 送钱给老师不收怎么办 上古卷轴5杀人了怎么办 嘴唇上长白色泡怎么办 下嘴唇老是起皮怎么办 孩子怕黑胆子小怎么办 小孩不吃饭怎么办偏瘦 我21岁现在缺钱怎么办 斗鱼直播卡顿怎么办 斗鱼怎么办卡怎么设置 无线网不能用了怎么办 率土之滨流浪后怎么办 率土之滨围洛阳怎么办 率土之滨没资源怎么办 竞彩改期的比赛怎么办 变性人老了会怎么办 冰箱放阳台直晒怎么办 喝了冰牛奶胃痛怎么办 空腹喝咖啡胃疼怎么办 空腹吃柿子胃疼怎么办 mac重启卡住了怎么办 快玩下载速度慢怎么办 微信消息不提示怎么办 车被物业锁了怎么办 去香港办的团签怎么办 香港个人签证g签怎么办 诛仙3挂机掉线怎么办 大神f2开不了机怎么办 昆仑账号忘记了怎么办 三星手机wifi信号弱怎么办 6个月的宝宝缺钙怎么办 半岁宝宝坐不稳怎么办 你宝宝老不睡觉怎么办 三岁宝宝摸咪咪怎么办 宝宝很困又不睡怎么办 两岁宝宝摸咪咪怎么办 失眠怎么办如何快速睡眠小偏方 9岁儿童睡不着觉怎么办 2岁儿童睡不着觉怎么办 多梦头晕没精神怎么办 晚上睡眠不好老做梦怎么办 睡醒后喉咙干痛怎么办