1. 程式人生 > >Android 自定義跑馬燈 實現超長文字,滾動完當前在繼續切換下一條

Android 自定義跑馬燈 實現超長文字,滾動完當前在繼續切換下一條

1 前言

最近專案上有一個跑馬燈的需求。

需求:

  • 無限滾動,可以自動切換下一條
  • 如果當前的文字超過一屏,則滾動完當前再切換下一條

第一點很簡單,但是第二點就比較蛋疼了,看了網上很多輪子都沒有太合適的,於是自己寫了一個。 記錄總結一下Android 跑馬燈的實現方式,和我自定義跑馬燈的思路。

原始碼已託管到Github:https://github.com/ieewbbwe/MarqueeView
先看下最後得效果圖吧:

這裡寫圖片描述

2 內容

2.1 需求實現

2.1.1 使用RecycleView + 自定義跑馬燈

思路:
1. 利用橫向RecycleView實現排列
2. smoothScroll實現滑動 
3. 內嵌跑馬燈實現標題超長的滾動

2.1.4 ViewFlipper + 自定義跑馬燈

這個實現方式是好基友告訴我的,很nice了,原理也是巢狀。
因為使用了ViwFilpper 因此想要改變滑動方向很簡單。直用該進入\退出動畫即可

思路:
1. 外層使用ViewFlipper切分View並且滾動
2. 內層使用自定義跑馬燈滾動

2.1.3 自定義控制元件,Draw() 出滾動效果

思路
1. draw出前後兩筆文字
2. 利用view的重繪,不斷更新文字位置實現滾動

2.2 跑馬燈的實現方式

2.2.1 TextView 設定Marquee

<TextView
        android:id
="@+id/marqueeNormal" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:ellipsize="marquee" android:focusable="true" android:focusableInTouchMode="true" android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true" android:text="我是普通的TextView跑馬燈~跑啊跑~!" />

灰常簡單,主要是這幾個熟悉:

 android:ellipsize="marquee"
 android:marqueeRepeatLimit="marquee_forever"
 android:singleLine="true"

但是!!有些時候會無效!因為跑馬燈要跑起來需要獲取到焦點,但是由於介面複雜,有時候焦點你好控制!TextView宣告只有再isFocus的時候才會走跑馬燈,具體的原始碼自己去看了。

那麼這種情況的終極解決方案是!直接繼承TextView,並Override isFocused(),永久返回True。就可以了,但是還會有彈出Dialog,螢幕不亮等時候會出現問題。

最終解決如下,實測可用:

public class MarqueeText3 extends AppCompatTextView {
    public MarqueeText3(Context context) {
        this(context,null);
    }

    public MarqueeText3(Context context, AttributeSet attrs) {
        super(context, attrs);
        //設定單行
        setSingleLine();
        //設定Ellipsize
        setEllipsize(TextUtils.TruncateAt.MARQUEE);
        //獲取焦點
        setFocusable(true);
        //走馬燈的重複次數,-1代表無限重複
        setMarqueeRepeatLimit(1);
        //強制獲得焦點
        setFocusableInTouchMode(true);

    }

    @Override
    public boolean isFocused() {
        return true;
    }

    @Override
    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
        if (focused) {
            super.onFocusChanged(focused, direction, previouslyFocusedRect);
        }
    }

    @Override
    public void onWindowFocusChanged(boolean hasWindowFocus) {
        if (hasWindowFocus)
            super.onWindowFocusChanged(hasWindowFocus);
    }

}

參考:TextView中的跑馬燈不動

2.2.2 自定義控制元件-使用ViewFlipper

2.2.3 自定義控制元件-使用Scroller 滾動

2.2.4 自定義控制元件-使用ScrollTo()

2.2.5 自定義控制元件-Canvas Draw()

3 總結

總的來說,就兩種思路:

  1. 外層滾動巢狀內層滾動
  2. 繪製當前和下一個,滾動

使用手感:

使用自定義Draw的方式 可控性高,靈活,但是容易出錯,計算方式比較麻煩,例子中寫的還不完善;

使用巢狀的方式簡單,快速,可控性不高,比如滾動時的停頓時間。

點選事件

還有一個需要注意的是,draw方法的時候,因為沒有控制好點選的問題,必須再切換的時候做到迅速,不然會有一個錯誤情況:當第一條未滾動出螢幕,但第二條一家滑入一部分的時候,點選會出現錯誤,不清楚當前是屬於第一條還是第二條。

參考:

https://github.com/sunfusheng/MarqueeView

https://github.com/shenjiajun53/CustomizedViews