自定義View-6-拖動按鈕複雜版

效果圖

這裏寫圖片描述

View代碼

第一步:自定義屬性
在values文件夾下的attrs.xml文件下添加代碼

<declare-styleable name="DragHoriView">
        <!--橫向節點數量-->
        <attr name="hor_number" format="integer"/>
        <!--節點文字,用中文狀態下的“,”分隔-->
        <attr name="nodestext" format="string"/>
        <!--文字大小-->
        <attr name="text_size" format="float"/>
        <!--文字顏色-->
        <attr name="text_color" format="color"/>
        <!--可拖動圖片-->
        <attr name="drag_icon" format="reference"/>
        <!--標題底下的圖標-->
        <attr name="type_icon" format="reference"/>
        <!--節點顏色-->
        <attr name="circle_color" format="color"/>
    </declare-styleable>

第二步:自定義圓形

public class CircleView extends View {
    /**
     * 默認顏色
     */
    private final int DEFAULT_COLOR = Color.LTGRAY;
    /**
     * 默認半徑dp
     */
    private final float DEFAULT_RADIUS = 32;
    private int mColor;
    private Paint mCirclePaint;
    private float mRadius;
    private float mCenterX;
    private float mCenterY;

    public CircleView(Context context)
    {
        this(context, null);
    }

    public CircleView(Context context, AttributeSet attrs)
    {
        this(context, attrs, 0);
    }

    public CircleView(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.DragView);
        mColor = array.getColor(R.styleable.DragHoriView_circle_color,DEFAULT_COLOR);
        mCirclePaint = new Paint();
        mCirclePaint.setColor(mColor);

        mCenterY = mCenterX = mRadius = getMeasuredWidth() == 0?DEFAULT_RADIUS:getMeasuredWidth()/2;
        array.recycle();
    }

    public float getRadius(){
        return mRadius;
    }

    public int getColor()
    {
        return mColor;
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        canvas.drawCircle(mCenterX,mCenterY,mRadius,mCirclePaint);
    }
}

第三步:自定義View

public class DragHoriView extends RelativeLayout implements View.OnTouchListener {
    private final String TAG = "DragHoriView";
    /**
     * 默認文字大小
     */
    private final float DEFAULT_TEXT_SIZE = 16;
    /**
     * 默認字體顏色
     */
    private final int DEFAULT_TEXT_COLOR = Color.GRAY;
    /**
     * 橫向節點數量
     */
    private int mHorNum;
    /**
     * 字體大小
     */
    private float mTextSize;
    /**
     * 字體顏色
     */
    private int mTextColor;
    /**
     * 每個節點的文字
     */
    private String[] mTexts;
    /**
     * 當前X座標
     */
    private float mCurX;
    /**
     * 圖片
     */
    private Drawable mIcon;
    /**
     * title底部的圖標
     */
    private Drawable mTypeIcon;

    private float mStartX;
    /**
     * 可移動的最小值
     */
    private float mMinX;
    /**
     * 可移動的最大值
     */
    private float mMaxX;
    /**
     * 橫線的寬度
     */
    private int mHorWidth;
    /**
     * 橫線高度
     */
    private int mHorHeight;
    /**
     * 圓的半徑
     */
    private int mCRadius;
    /**
     * 拖動控件的寬度(此處爲直徑)
     */
    private int mDragWidth;
    /**
     * 拖動控件的高度
     */
    private int mDragHeight;
    /**
     * 文字的高度
     */
    private int mTextHeight;
    /**
     * 文字的寬度
     */
    private int mTextWidth;
    /**
     * 控件本身的寬度
     */
    private int mWidth;
    /**
     * 文字距離頂部的距離
     */
    private int mTextTop;
    /**
     * 文字和拖動View的間距
     */
    private int mCenterSpace;

    private int mSelectPosition;

    private int[] mRanges;

    private ImageView mDragView;

    public DragHoriView(Context context) {
        this(context, null);
    }

    public DragHoriView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DragHoriView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.DragHoriView);
        mTextColor = array.getColor(R.styleable.DragHoriView_text_color, DEFAULT_TEXT_COLOR);
        mTextSize = array.getFloat(R.styleable.DragHoriView_text_size, DEFAULT_TEXT_SIZE);
        mIcon = array.getDrawable(R.styleable.DragHoriView_drag_icon);
        mTypeIcon = array.getDrawable(R.styleable.DragHoriView_type_icon);
        String text = array.getString(R.styleable.DragHoriView_nodestext);
        if (text != null && !text.equals("")) {
            mTexts = text.split(",");
            mHorNum = mTexts.length;
        }
        array.recycle();
        initView(attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mWidth = MeasureSpec.getSize(widthMeasureSpec);
        int hegith = MeasureSpec.getSize(heightMeasureSpec);
        int count = getChildCount();
        //邊距
        mCenterSpace = dp2px(getContext(), 8);
        for (int i = 0; i < count; i++) {
            View view = getChildAt(i);
            LayoutParams rParams;
            if (view instanceof CircleView) {
                if (mCRadius == 0) {
                    mCRadius = (int) ((CircleView) view).getRadius();
                }

            } else if (view instanceof TextView) {

                if (mTextHeight == 0) {
                    mTextHeight = spTopx(getContext(), mTextSize + 2);
                    String text = ((TextView) view).getText().toString();
                    mTextWidth =spTopx(getContext(), mTextSize * text.length());
                }

            } else if (view instanceof ImageView) {

                if (mDragHeight == 0) {
                    mDragHeight = mDragWidth = dp2px(getContext(), 50);
                    rParams = new LayoutParams(mDragWidth, mDragWidth);
                    view.setLayoutParams(rParams);
                }

            } else {
                if (mHorWidth == 0) {
                    //橫線
                    mHorWidth = mWidth * 3 / 8;
                    mHorHeight = mCRadius * 2 / 3;
                    rParams = new LayoutParams(mHorWidth, mHorHeight);
                    view.setLayoutParams(rParams);
                }
            }
        }
        mTextTop = (hegith - (mTextHeight + mCenterSpace + mDragHeight)) / 2;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (changed) {
            int count = getChildCount();
            int width = r - l;
            int space = mHorWidth / (mHorNum - 1);

            int dTop = mTextTop + mTextHeight + mCenterSpace;
            int cTop = dTop + mDragHeight / 2 - mCRadius;
            int hTop = dTop + mDragHeight / 2 - mHorHeight / 2;

            int hLeft = (mWidth - mHorWidth) / 2;
            int cLeft = hLeft - mCRadius;
            int tLeft = hLeft - mTextWidth / 2;
            int dLeft = hLeft - mDragWidth / 2;
            if (mRanges == null) {
                mRanges = new int[mHorNum];
            }
            int j = 0;
            for (int i = 0; i < count; i++) {
                View view = getChildAt(i);

                if (view instanceof CircleView) {
                    cLeft = cLeft + space * j;
                    int cRight = cLeft + mCRadius * 2;
                    int cBottom = cTop + mCRadius * 2;

                    view.layout(cLeft, cTop, cRight, cBottom);

                    //賦值最小值爲拖動空間本身的左邊
                    mMinX = dLeft;
                    Log.v(TAG, "mMinX = " + mMinX);

                    mRanges[j] = (cLeft + cRight) / 2;
                    j++;
                } else if (view instanceof TextView) {
                    String text = ((TextView) view).getText().toString();
                    mTextWidth = spTopx(getContext(), mTextSize * text.length());
                    int tBottom = mTextTop + mTextHeight;
                    tLeft = tLeft + space * (j - 1);
                    int tRight = tLeft + mTextWidth;
                    view.layout(tLeft, mTextTop, tRight, tBottom);

                } else if (view instanceof ImageView) {

                    view.layout(dLeft, dTop, dLeft + mDragWidth, dTop + mDragHeight);

                } else {

                    //橫線
                    view.layout(hLeft, hTop, hLeft + mHorWidth, hTop + mHorHeight);
                    //賦值最大值爲橫線的右邊加上拖動控件的寬度的一半
                    mMaxX = width - hLeft - mDragWidth / 2;
                    Log.v(TAG, "mMaxX = " + mMaxX);
                }
            }
        }
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (v instanceof ImageView) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:

                    mStartX = (int) event.getRawX();
                    mCurX = v.getTranslationX();
                    Log.v(TAG, "mStartX = " + mStartX);
                    v.setPressed(true);
                    break;

                case MotionEvent.ACTION_MOVE:
                    float x = mCurX + event.getRawX() - mStartX;
                    if (x >= 0 && x <= mMaxX - mMinX) {
                        v.setTranslationX(mCurX + event.getRawX() - mStartX);
                    }
                    break;

                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:

                    int max;
                    int min;
                    int length = mRanges.length;
                    float curX = v.getTranslationX();
                    for (int i = 0; i < length; i++) {
                        if (i > 0 && mRanges[i] - mMinX > curX) {
                            max = mRanges[i];
                            min = mRanges[i - 1];
                            float center = (max + min) / 2 - mMinX - mDragWidth / 2;
                            if (curX >= center) {
                                //超過一半
                                setAnim(max - mMinX - mDragWidth / 2, i);
                            } else if (curX < center) {
                                setAnim(min - mMinX - mDragWidth / 2, i - 1);
                            } else {
                                //剛好拖到節點
                                if (mOnNodeSelect != null) {
                                    if (mSelectPosition != i) {
                                        mOnNodeSelect.onNodeSelect(mSelectPosition);
                                    }
                                }
                            }
                            break;
                        }
                    }
                    v.setPressed(false);
                    break;
            }
        } else {
            switch (event.getAction()) {
                case MotionEvent.ACTION_UP:
                    int length = mRanges.length;

                    int nodeX = (v.getLeft() + v.getRight()) / 2;
                    for (int i = 0; i < length; i++) {
                        if (nodeX == mRanges[i]) {
                            setAnim(mRanges[i] - mMinX - mDragWidth / 2, i);
                            break;
                        }
                    }

                    break;
            }
        }
        return true;
    }

    private void setAnim(float moveX, final int scrollPosition) {
        ObjectAnimator animator = ObjectAnimator.ofFloat(mDragView, "translationX", mDragView.getTranslationX(), moveX);
        animator.setDuration(300);
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                if (mSelectPosition != scrollPosition) {
                    mSelectPosition = scrollPosition;
                    if (mOnNodeSelect != null) {
                        mOnNodeSelect.onNodeSelect(mSelectPosition);
                    }
                }
            }
        });
        animator.start();
    }

    private void initView(AttributeSet attrs) {
        CircleView circleView = null;
        for (int i = 0; i < mHorNum; i++) {
            TextView textView = insTextView();
            textView.setText(mTexts[i]);
            //小圓點
            circleView = new CircleView(getContext(), attrs);
            addView(circleView);
            addView(textView);

            textView.setOnTouchListener(this);
            circleView.setOnTouchListener(this);
        }

        //橫線
        View view = new View(getContext());
        view.setBackgroundColor(circleView.getColor());
        view.setOnTouchListener(this);
        addView(view);
        //可拖動view
        mDragView = new ImageView(getContext());
        mDragView.setImageDrawable(mIcon);
        mDragView.setOnTouchListener(this);
        addView(mDragView);
    }

    private TextView insTextView() {
        TextView textView = new TextView(getContext());
        textView.setTextSize(mTextSize);
        textView.setTextColor(mTextColor);
        return textView;
    }


    private OnNodeSelect mOnNodeSelect;

    public void setNodeSelectListener(OnNodeSelect onNodeSelect) {
        mOnNodeSelect = onNodeSelect;
    }

    public interface OnNodeSelect {
        void onNodeSelect(int position);
    }

    /**
     * 根據手機的分辨率從dp 的單位 轉成爲px(像素)
     */
    public  int dp2px(Context context, float dpValue)
    {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    /**
     * 將sp值轉換爲px值,保證文字大小不變
     */
    public  int spTopx(Context context, float spValue)
    {
        final float scale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (spValue * scale + 0.5f);
    }


}

使用方法

 <com.pengkv.apple.weight.DragHoriView
        android:id="@+id/dhv_select_type"
        android:layout_width="match_parent"
        android:layout_height="84dp"
        android:background="#f5f5f5"
        app:nodestext="簡單,困難"
        app:text_size="14"
        android:layout_margin="10dp"
        app:text_color="#333333"
        app:drag_icon="@drawable/ic_drag"
        app:circle_color="#D7D7D7"/>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章