Skip to content

Conversation

@mojtaba-yekta
Copy link

@mojtaba-yekta mojtaba-yekta commented Dec 12, 2018

  • added itemIndex parameter to createView function

  • initData function has been modified

  • in createView function setOnClickListener added to tv object

@mojtaba-yekta mojtaba-yekta changed the title minor improvement in refreshItemView function minor improvement in refreshItemView function and set OnClickListener on TextView item Dec 12, 2018
@GAODBK
Copy link

GAODBK commented Feb 9, 2025

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
Copy link

GAODBK commented Feb 9, 2025

我设计的代码:

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();
}

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants