自定义VerticalTextView滚动功能失效,附代码求助解决方案
解决VerticalTextView跑马灯滚动失效的问题
看起来你自定义的VerticalTextView因为重写了onDraw方法,跳过了原生TextView处理跑马灯(marquee)的核心逻辑,导致滚动功能失效。下面我来帮你分析问题并给出修复方案:
问题根源
你的onDraw方法直接调用getLayout().draw(canvas)绘制文本,但原生TextView的跑马灯效果依赖于内部的marquee布局计算和偏移处理,你没有处理这些逻辑,也没有调用原生的marquee相关绘制流程,所以滚动不会生效。另外,原生的marquee是为水平文本设计的,旋转后的垂直文本需要适配偏移逻辑。
修复后的VerticalTextView实现
修改你的自定义View,加入marquee的适配逻辑:
public class VerticalTextView extends TextView { private final boolean topDown; public VerticalTextView(Context context, AttributeSet attrs) { super(context, attrs); // 可选:从自定义属性读取topDown配置,这里默认设为false TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.VerticalTextView); topDown = a.getBoolean(R.styleable.VerticalTextView_topDown, false); a.recycle(); // 确保View支持聚焦,这是触发marquee的必要条件之一 setFocusable(true); setFocusableInTouchMode(true); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(heightMeasureSpec, widthMeasureSpec); setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth()); } @Override protected void onDraw(Canvas canvas) { TextPaint textPaint = getPaint(); textPaint.setColor(getCurrentTextColor()); textPaint.drawableState = getDrawableState(); canvas.save(); // 执行画布旋转,保持原有的垂直文本逻辑 if (topDown) { canvas.translate(getWidth(), 0); canvas.rotate(90); } else { canvas.translate(0, getHeight()); canvas.rotate(-90); } // 适配marquee的偏移:原生scrollX对应水平偏移,旋转后转为垂直方向的偏移 int scrollOffset = getScrollX(); if (!topDown) { scrollOffset = -scrollOffset; } canvas.translate(getCompoundPaddingLeft() - scrollOffset, getExtendedPaddingTop()); // 使用marquee专用的Layout(如果当前处于跑马灯状态) Layout layout = getLayout(); if (isMarqueeFloating()) { layout = getMarquee(); } if (layout != null) { layout.draw(canvas); } canvas.restore(); } @Override public boolean isFocused() { // 让选中状态也能触发marquee,不需要强制获得焦点 return isSelected() || super.isFocused(); } }
调整使用代码
注意移除ScrollingMovementMethod(它是用于手动滚动的,和自动marquee冲突),并确保文本长度足够触发滚动:
VerticalTextView image = new VerticalTextView(context,null); // 必须设置足够长的文本,超过View的显示宽度(旋转后的宽度即原View的高度) image.setText("这是一段需要垂直滚动的超长测试文本,长度要超过VerticalTextView的显示范围才能触发跑马灯"); image.setEllipsize(TextUtils.TruncateAt.MARQUEE); image.setSingleLine(true); image.setMarqueeRepeatLimit(-1); // 无限重复滚动 image.setSelected(true); // 关键:必须设置选中状态 image.setFreezesText(true); // 移除这行:image.setMovementMethod(new ScrollingMovementMethod());
额外注意事项
- 文本长度必须超过
VerticalTextView的显示宽度(也就是旋转后的宽度,对应原布局中的高度),否则不会触发跑马灯。 - 确保
setSelected(true)被正确设置,这是触发marquee滚动的核心开关之一。 - 如果需要在布局中使用自定义属性,记得在
res/values/attrs.xml中添加:<declare-styleable name="VerticalTextView"> <attr name="topDown" format="boolean"/> </declare-styleable>
内容的提问来源于stack exchange,提问作者pavani
相关产品推荐
相关产品推荐

