自定义TextView解决事件冲突TextView不能获取焦点问题

本文介绍了一种自定义TextView的方法,旨在解决当存在事件冲突时TextView无法获取焦点的问题。通过实现Runnable接口并重写onDraw方法,创建了一个带有跑马灯效果的TextView,允许在触摸模式下聚焦并启用marquee滚动。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;

import com.bluezhang.zhufengfm.BuildConfig;

/**
 * Author: blueZhang
 * DATE:2015/10/25
 * Time: 17:35
 * email:bluezhang521@163.com
 */

/**
 * 自定义TextView的跑马灯的效果
 * 用于解决如果出现事件冲突TextView不能够获取焦点
 * 如果可以获取焦点那么可以使用如下代码
 *
<pre>
           android:layout_width="100dip"
           android:layout_height="wrap_content"
           android:layout_gravity="center"
           android:text="走马灯效果的演示"
           android:singleLine="true"
           android:ellipsize="marquee"
           android:focusable="true"
           android:focusableInTouchMode="true"
          <com.bluezhang.zhufengfm.widgets.NewTextView
               android:id="@+id/playtrackui_textview_titile_id"
               android:layout_width="160dp"
               android:layout_height="wrap_content"
               android:layout_centerVertical="true"
               android:layout_marginLeft="30dp"
               android:layout_toRightOf="@id/playtrackui_imageview_back_id"
               android:ellipsize="marquee"
               android:singleLine="true"
               android:text="Title"
               android:textColor="@color/dimgrey"
              android:textSize="17sp"

    />



 <pre/> * */
public class NewTextView extends TextView implements Runnable {
    private int currentScrollX;// 当前滚动的位置
    private boolean isStop = false;
    private int textWidth;
    private boolean isMeasure = false;

    public NewTextView(Context context) {
        super(context);
    }

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

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

    @Override
    protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
        super.onDraw(canvas);
        if (!isMeasure) {// 文字宽度只需获取一次就可以了
            getTextWidth();
            isMeasure = true;
        }
    }

    /**
     * 获取文字宽度
     */
    private void getTextWidth() {
        Paint paint = this.getPaint();
        String str = this.getText().toString();
        textWidth = (int) paint.measureText(str);
    }

    @Override
    public void run() {
        currentScrollX += 1;// 滚动速度
        scrollTo(currentScrollX, 0);
        if (isStop) {
            return;
        }
        if (getScrollX() >= (this.getWidth() + textWidth)) {
            scrollTo(-(textWidth + 160), 0);
            currentScrollX = -textWidth - 160;
            if (BuildConfig.DEBUG) Log.d("NewTextView", "条件成立");
        }
        postDelayed(this, 5);
    }

    // 开始滚动
    public void startScroll() {
        isStop = false;
        this.removeCallbacks(this);
        post(this);
    }

    // 停止滚动
    public void stopScroll() {
        isStop = true;
    }

    // 从头开始滚动
    public void startFor0() {
        currentScrollX = -textWidth - 160;
        startScroll();
    }
}



<think>我们将在Android中实现TextView的滚动显示功能,特别是当文本过长时自动垂直滚动。根据引用内容,有几种方法可以实现: 1. **使用ScrollView包裹TextView**:这是最简单的方法,当文本超过TextView的高度时,ScrollView会提供滚动条。但这种方法需要手动设置TextView的最大高度(通过设置maxLines或固定高度),或者让ScrollView处理滚动。 2. **自定义TextView实现滚动**:如引用[1]中提到的,自定义TextView并重写isFocused()方法返回true,使其可以获取焦点并滚动。但这种方法通常用于水平滚动。 3. **使用垂直滚动的自定义TextView**:如引用[3]中提到的,使用自定义的VerticalTextView来实现类似广告的垂直滚动效果。 4. **实现平滑的自动滚动**:如引用[4]中,使用定时器(如RxJava)让TextView的内容自动平滑滚动。 根据需求“文本过长自动垂直滚动”,我们推荐使用ScrollView包裹TextView的方式,因为这是最常用且简单的。但如果需要自动滚动(无需用户手动滚动),则可以采用定时器的方式。 ### 方法一:使用ScrollView(手动滚动) 布局文件(activity_main.xml): ```xml <?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true"> <TextView android:id="@+id/textView" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/long_text" /> </ScrollView> ``` 注意:将长文本放在string资源文件中,避免在布局文件中写大段文字。 ### 方法二:自动滚动到底部(当动态追加文本时) 如果文本是动态追加的,并且希望自动滚动到最新内容(如日志显示),可以参考引用[2]中的方法,在每次追加文本后调用ScrollView的fullScroll方法。 代码示例(MainActivity.java): ```java public class MainActivity extends AppCompatActivity { private TextView textView; private ScrollView scrollView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = findViewById(R.id.textView); scrollView = findViewById(R.id.scrollView); // 动态追加文本 Button button = findViewById(R.id.button); button.setOnClickListener(v -> { appendText("New text added at: " + System.currentTimeMillis() + "\n"); }); } private void appendText(String text) { textView.append(text); // 滚动到底部 scrollView.post(() -> scrollView.fullScroll(ScrollView.FOCUS_DOWN)); } } ``` 布局文件(使用ScrollView和Button): ```xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ScrollView android:id="@+id/scrollView" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:fillViewport="true"> <TextView android:id="@+id/textView" android:layout_width="match_parent" android:layout_height="wrap_content" /> </ScrollView> <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Add Text" /> </LinearLayout> ``` ### 方法三:实现自动平滑滚动(无需用户操作) 如果需要文本自动向上滚动(如滚动新闻),我们可以使用定时器来不断改变ScrollView的滚动位置。参考引用[4]的方法,使用RxJava定时器(也可以使用Handler)。 在Kotlin中实现(MainActivity.kt): ```kotlin class MainActivity : AppCompatActivity() { private lateinit var scrollView: ScrollView private var currentY = 0 private var disposable: Disposable? = null private var canAutoScroll = true override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) scrollView = findViewById(R.id.scrollView) val textView = findViewById<TextView>(R.id.textView) // 设置长文本 textView.text = getString(R.string.long_text) // 设置触摸监听,当用户触摸时停止自动滚动,离开后继续 scrollView.setOnTouchListener { _, event -> when (event.action) { MotionEvent.ACTION_DOWN -> canAutoScroll = false MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> canAutoScroll = true } false } } override fun onResume() { super.onResume() startAutoScroll() } override fun onPause() { super.onPause() stopAutoScroll() } private fun startAutoScroll() { disposable = Observable.interval(50, TimeUnit.MILLISECONDS) .observeOn(AndroidSchedulers.mainThread()) .subscribe { if (canAutoScroll) { currentY += 2 // 每次滚动2像素 scrollView.scrollTo(0, currentY) } } } private fun stopAutoScroll() { disposable?.dispose() } } ``` 注意:这种方法需要添加RxJava依赖: ```gradle implementation 'io.reactivex.rxjava3:rxandroid:3.0.0' implementation 'io.reactivex.rxjava3:rxjava:3.0.0' ``` ### 注意事项 1. **布局高度**:确保ScrollView有固定的高度(比如使用layout_weight或固定dp值),否则可能无法滚动。 2. **性能**:如果文本非常大,考虑使用RecyclerView代替TextView,因为TextView渲染大文本可能会影响性能。 3. **自动滚动的控制**:在用户交互时(如触摸滚动)应暂停自动滚动,避免冲突。 ### 相关问题 1. 如何实现TextView的水平滚动?[^1] 2. 如何实现类似新闻的垂直滚动公告板?[^3] 3. 如何优化大文本在TextView中的显示性能?[^2] 4. 如何实现TextView的淡入淡出滚动效果? 5. 在RecyclerView中如何实现自动滚动? 以上方法可以根据实际需求选择使用。对于简单的长文本显示,方法一就足够了;对于需要动态追加文本并自动滚动的场景(如日志),使用方法二;对于需要自动向上滚动的广告或公告,使用方法三。</think>### Android 实现 TextView 自动垂直滚动功能 在 Android 中实现 TextView 的自动垂直滚动功能,可以通过以下几种方法实现: --- #### 方法一:使用 ScrollView + TextView(基础滚动) 这是最简单的方式,适合静态长文本滚动: ```xml <!-- activity_main.xml --> <ScrollView android:layout_width="match_parent" android:layout_height="200dp" <!-- 固定高度触发滚动 --> android:fillViewport="true"> <TextView android:id="@+id/longText" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/long_text" /> <!-- 长文本资源 --> </ScrollView> ``` ```java // MainActivity.java public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView textView = findViewById(R.id.longText); textView.setMovementMethod(new ScrollingMovementMethod()); // 启用滚动 } } ``` --- #### 方法二:动态追加文本自动滚动(日志场景) 适合需要动态添加内容的场景(如日志显示): ```xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ScrollView android:id="@+id/scrollView" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> <TextView android:id="@+id/logView" android:layout_width="match_parent" android:layout_height="wrap_content" /> </ScrollView> <Button android:id="@+id/addButton" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="添加新内容"/> </LinearLayout> ``` ```java // 动态添加文本并自动滚动到底部 private void appendTextAndScroll(String newText) { logView.append(newText + "\n"); // 延迟滚动确保视图已更新 scrollView.post(() -> scrollView.fullScroll(View.FOCUS_DOWN)); } // 按钮点击示例 addButton.setOnClickListener(v -> appendTextAndScroll("新日志: " + System.currentTimeMillis()) ); ``` --- #### 方法三:平滑自动滚动(广告/公告效果) 实现类似新闻跑马灯的平滑滚动效果: ```kotlin // 使用属性动画实现平滑滚动 fun startAutoScroll(textView: TextView, scrollView: ScrollView) { val animator = ValueAnimator.ofInt(0, textView.height - scrollView.height) animator.duration = 10000 // 10秒完成滚动 animator.addUpdateListener { scrollView.scrollTo(0, it.animatedValue as Int) } animator.repeatCount = ValueAnimator.INFINITE // 无限循环 animator.repeatMode = ValueAnimator.RESTART // 到底部后回到顶部 animator.start() } // 在onCreate中调用 startAutoScroll(logView, scrollView) ``` --- #### 方法四:自定义垂直滚动 TextView(高级) 实现类似引用[3]的垂直滚动效果: 1. **自定义 VerticalTextView**: ```java public class VerticalTextView extends AppCompatTextView { public VerticalTextView(Context context) { super(context); } // 重写onDraw实现垂直滚动 @Override protected void onDraw(Canvas canvas) { TextPaint textPaint = getPaint(); textPaint.setColor(getCurrentTextColor()); canvas.save(); // 垂直绘制文本 canvas.translate(getWidth(), 0); canvas.rotate(90); // 计算滚动位置 int scrollY = getScrollY(); Layout layout = getLayout(); // 绘制可见部分文本 layout.draw(canvas, null, null, 0); canvas.restore(); } } ``` 2. **布局中使用**: ```xml <cn.example.VerticalTextView android:id="@+id/verticalText" android:layout_width="match_parent" android:layout_height="200dp" android:textSize="16sp" android:singleLine="false"/> ``` --- ### 关键配置说明 1. **启用滚动功能**: ```java textView.setMovementMethod(new ScrollingMovementMethod()); ``` 2. **控制滚动速度**: ```kotlin // 在平滑滚动方法中调整 animator.duration = 15000 // 时间越长速度越慢 ``` 3. **处理触摸事件**(引用[4]): ```kotlin scrollView.setOnTouchListener { _, event -> when (event.action) { MotionEvent.ACTION_DOWN -> pauseAutoScroll() MotionEvent.ACTION_UP -> resumeAutoScroll() } false } ``` 4. **性能优化**: ```java // 限制最大行数防止内存问题 textView.setMaxLines(1000); ``` --- ### 相关问题 1. 如何实现 TextView 的水平滚动效果?[^1] 2. 如何优化长文本在 TextView 中的显示性能?[^2] 3. 如何实现类似新闻的无限循环滚动效果?[^3] 4. 如何动态改变 TextView 的滚动速度?[^4] 5. 在 RecyclerView 中如何实现自动滚动效果?[^2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值