WheelView icon indicating copy to clipboard operation
WheelView copied to clipboard

minor improvement in refreshItemView function and set OnClickListener on TextView item

Open mojtaba-yekta opened this issue 7 years ago • 2 comments

  • added itemIndex parameter to createView function

  • initData function has been modified

  • in createView function setOnClickListener added to tv object

mojtaba-yekta avatar Dec 12 '18 06:12 mojtaba-yekta

public static final int OFF_SET_DEFAULT = 2;

设置OFF_SET_DEFAULT=2,将组件滚动到最后一个,出现报错: java.lang.IndexOutOfBoundsException: Index 18 out of bounds for length 17

能不能帮忙提供思路

Set OFF_SET_DEFAULT=2 and scroll the component to the last one, and an error message appears java.lang.IndexOutOfBoundsException: Index 18 out of bounds for length 17

Can you help with ideas

GAODBK avatar Feb 09 '25 13:02 GAODBK

我设计的代码:

public class WheelView extends ScrollView { public static final String TAG = WheelView.class.getSimpleName();

public static class OnWheelViewListener {
    public void onSelected(int selectedIndex, String item) {
    }
}


private Context context;
private LinearLayout views;

public WheelView(Context context) {
    super(context);
    init(context);
}

public WheelView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
}

public WheelView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(context);
}

List<String> items;

public void setItems(List<String> list) {
    if (items == null) {
        items = new ArrayList<>();
    }
    items.clear();
    items.addAll(list);

    for (int i = 0; i < offset; i++) {
        items.add(0, "");
        items.add("");
    }

    initData();
}


public static final int OFF_SET_DEFAULT = 2;
int offset = OFF_SET_DEFAULT;
int displayItemCount; // 每页显示的数量
int selectedIndex = 1;


private void init(Context context) {
    this.context = context;
    this.setVerticalScrollBarEnabled(false);
    this.setFadingEdgeLength(0);
    this.setOverScrollMode(OVER_SCROLL_NEVER);

    views = new LinearLayout(context);
    views.setOrientation(LinearLayout.VERTICAL);
    this.addView(views);

    scrollerTask = () -> {

        int newY = getScrollY();
        if (initialY - newY == 0) { // stopped
            final int remainder = initialY % itemHeight;
            final int divided = initialY / itemHeight;

            if (remainder == 0) {
                selectedIndex = divided + offset;

                onSeletedCallBack();
            } else {
                if (remainder > itemHeight / 2) {
                    WheelView.this.post(() -> {
                        WheelView.this.smoothScrollTo(0, initialY - remainder + itemHeight);
                        selectedIndex = divided + offset + 1;
                        onSeletedCallBack();
                    });
                } else {
                    WheelView.this.post(() -> {
                        WheelView.this.smoothScrollTo(0, initialY - remainder);
                        selectedIndex = divided + offset;
                        onSeletedCallBack();
                    });
                }
            }
        } else {
            initialY = getScrollY();
            WheelView.this.postDelayed(scrollerTask, newCheck);
        }
    };
}

int initialY;
Runnable scrollerTask;
int newCheck = 50;

public void startScrollerTask() {

    initialY = getScrollY();
    this.postDelayed(scrollerTask, newCheck);
}

private void initData() {
    displayItemCount = offset * 2 + 1;

    for (int i = 0; i < items.size(); i++) {
        views.addView(createView(items.get(i), i - offset));
    }

    refreshItemView(0);
    //postDelayed(scrollerTask, newCheck);
}

int itemHeight = 0;

private View createView(String item, int itemIndex) {
    TextView tv = new TextView(context);
    tv.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));

    tv.setSingleLine(true);
    tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);

    tv.setText(item);
    tv.setTag(itemIndex);
    tv.setGravity(Gravity.CENTER);

    int padding = dip2px(15);
    tv.setPadding(padding, padding, padding, padding);

    if (0 == itemHeight) {
        itemHeight = getViewMeasuredHeight(tv);
        Log.d(TAG, "itemHeight: " + itemHeight);

        views.setLayoutParams(new LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                itemHeight * displayItemCount,
                Gravity.CENTER_HORIZONTAL
        ));
        views.setGravity(Gravity.CENTER);

        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) this.getLayoutParams();
        this.setLayoutParams(new LinearLayout.LayoutParams(
                lp.width,
                itemHeight * displayItemCount
        ));
    }

    tv.setOnClickListener(v -> {
        int itemIndex1 = (int) v.getTag();
        setSeletion(itemIndex1);
    });
    return tv;
}


@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
    super.onScrollChanged(l, t, oldl, oldt);
    refreshItemView(t);

    if (t > oldt) {

// Log.d(TAG, "向下滚动"); scrollDirection = SCROLL_DIRECTION_DOWN; } else { // Log.d(TAG, "向上滚动"); scrollDirection = SCROLL_DIRECTION_UP; } }

private void refreshItemView(int y) {
    int divided = y / itemHeight;
    int remainder = y % itemHeight;
    int position = divided + offset;

    if (remainder > itemHeight / 2) {
        position = divided + offset + 1;
    }
    int childSize = views.getChildCount();
    for (int i = 0; i < childSize; i++) {
        TextView itemView = (TextView) views.getChildAt(i);
        if (null == itemView) {
            return;
        }
        if (position == i) {
            itemView.setTextColor(Color.parseColor("#0288ce"));
        } else {
            itemView.setTextColor(Color.parseColor("#bbbbbb"));
        }
    }
}

/**
 * 获取选中区域的边界
 */
int[] selectedAreaBorder;

private int[] obtainSelectedAreaBorder() {
    if (null == selectedAreaBorder) {
        selectedAreaBorder = new int[2];
        selectedAreaBorder[0] = itemHeight * offset;
        selectedAreaBorder[1] = itemHeight * (offset + 1);
    }
    return selectedAreaBorder;
}


int scrollDirection = -1;
private static final int SCROLL_DIRECTION_UP = 0;
private static final int SCROLL_DIRECTION_DOWN = 1;

Paint paint;
int viewWidth;

@Override
public void setBackgroundDrawable(Drawable background) {

    if (viewWidth == 0) {
        viewWidth = views.getWidth();
        Log.d(TAG, "viewWidth: " + viewWidth);
    }

    if (null == paint) {
        paint = new Paint();
        paint.setColor(Color.parseColor("#83cde6"));
        paint.setStrokeWidth(dip2px(1f));
    }

    background = new Drawable() {
        @Override
        public void draw(Canvas canvas) {
            canvas.drawLine(
                    (float) (viewWidth) / 6,
                    obtainSelectedAreaBorder()[0],
                    (float) (viewWidth * 5) / 6,
                    obtainSelectedAreaBorder()[0],
                    paint);

            canvas.drawLine(
                    (float) (viewWidth) / 6,
                    obtainSelectedAreaBorder()[1],
                    (float) (viewWidth * 5) / 6,
                    obtainSelectedAreaBorder()[1],
                    paint);
        }

        @Override
        public void setAlpha(int alpha) {

        }

        @Override
        public void setColorFilter(ColorFilter cf) {

        }

        @Override
        public int getOpacity() {
            return PixelFormat.UNKNOWN;
        }
    };


    super.setBackgroundDrawable(background);

}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    Log.d(TAG, "w: " + w + ", h: " + h + ", oldw: " + oldw + ", oldh: " + oldh);
    viewWidth = w;
    setBackgroundDrawable(null);
}

/**
 * 选中回调
 */
private void onSeletedCallBack() {
    try {
        if (onWheelViewListener != null) {
            onWheelViewListener.onSelected(selectedIndex, items.get(selectedIndex));
        }
    } catch (Exception e) {
        Log.e(TAG, "onSeletedCallBack 出错:" + e.getMessage(), e);
    }
}

public void setSeletion(int position) {
    final int p = position;
    selectedIndex = p + offset;
    this.post(() -> WheelView.this.smoothScrollTo(0, p * itemHeight));
}

@Override
public void fling(int velocityY) {
    super.fling(velocityY / 3);
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_UP) {

        startScrollerTask();
    }
    return super.onTouchEvent(ev);
}

private OnWheelViewListener onWheelViewListener;

public void setOnWheelViewListener(OnWheelViewListener onWheelViewListener) {
    this.onWheelViewListener = onWheelViewListener;
}

private int dip2px(float dpValue) {
    final float scale = context.getResources().getDisplayMetrics().density;
    return (int) (dpValue * scale + 0.5f);
}

private int getViewMeasuredHeight(View view) {
    int width = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    int expandSpec = View.MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, View.MeasureSpec.AT_MOST);
    view.measure(width, expandSpec);
    return view.getMeasuredHeight();
}

}

GAODBK avatar Feb 09 '25 14:02 GAODBK