亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Android用TextView實現(xiàn)跑馬燈效果代碼

 更新時間:2022年01月26日 11:05:09   作者:瀟曜  
大家好,本篇文章主要講的是Android?TextView實現(xiàn)跑馬燈效果代碼,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下

【前言】

     在Textview設置的寬度有限,而需要顯示的文字又比較多的情況下,往往需要給Textview設置跑馬燈效果才能讓用戶完整地看到所有設置的文字,所以給TextView設置跑馬燈效果的需求是很常見的

一、新手設置跑馬燈效果

1、先在xml中給Textview設置好對應的屬性

 <TextView
        android:id="@+id/tv"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/show_float"
        android:singleLine="true"
        android:ellipsize="marquee"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:marqueeRepeatLimit="-1"
        android:layout_marginTop="20dp"
        android:padding="10dp"
        android:text="歡迎來到跑馬燈新手村,這是新手示例~"
        android:textColor="@color/white"
        android:background="@drawable/com_live_rounded_rectangle"/>

2、然后在代碼中設置請求獲取焦點即可

        TextView tv = findViewById(R.id.tv);
        tv.requestFocus();

這樣設置之后,跑馬燈的效果就出來了

在這里插入圖片描述

【關(guān)鍵點講解】

1、android:layout_width 是限制為固定寬度,同時文本的長度大于所設置的寬度,要是設置android:layout_widthwrap_content, 那么Textview的寬度會隨著文本長度變長而拉寬,這樣就不能出現(xiàn)跑馬燈效果
2、android:singleLine="true"設置Textview只能一行顯示,要是不設置為true,默認會自動換行,顯示為多行,這樣的話,也不能出現(xiàn)跑馬燈效果
3、android:ellipsize="marquee"設置要是文本長度超出Textview的寬度時候,文本應該以跑馬燈效果顯示,這個是設置跑馬燈效果最關(guān)鍵的設置,android:ellipsize還可以取值start、endmiddle、none,分別是開頭顯示省略號、結(jié)尾顯示省略號、中間顯示省略號、直接截斷
4、android:focusable="true"設置Textview可以獲取焦點,跑馬燈效果需要獲取到焦點時候才生效,Textview默認是不獲取焦點的
5、android:focusableInTouchMode="true"設置在觸摸模式下可以獲取焦點,目前智能機基本都是自動進入觸摸模式,其實目前只要設置android:focusableInTouchMode="true",默認android:focusable也會變?yōu)閠rue了
6、android:marqueeRepeatLimit="-1"設置跑馬燈循環(huán)的次數(shù),-1表示無限循環(huán),不設置的話,默認是循環(huán)3次
7、 tv.requestFocus();設置獲取焦點, 只有當該view的focusable屬性為true時候才生效

【總結(jié)】

1、一定要設置android:focusableInTouchMode="true",若是只設置了android:focusable="true"android:focusableInTouchMode沒設置,那么跑馬燈效果是不生效的,因為進入觸摸模式之后,isFocusable()返回false,下面看看Texivew startMarquee()源碼就知道需要滿足什么條件才會開始跑馬燈特效:

     private void startMarquee() {
        // Do not ellipsize EditText
        if (getKeyListener() != null) return;

        if (compressText(getWidth() - getCompoundPaddingLeft() - getCompoundPaddingRight())) {
            return;
        }
		
		// 1、跑馬燈控制類沒有創(chuàng)建或者跑馬燈效果已經(jīng)停止
        if ((mMarquee == null || mMarquee.isStopped()) && 
        // 2、當前Textview是獲取到焦點或者被選中狀態(tài)
        (isFocused() || isSelected())
        // 3、文本的行數(shù)只有一行
         && getLineCount() == 1
         // 4、文本長度大于Textview的寬度 
         && canMarquee()) {

            if (mMarqueeFadeMode == MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) {
                mMarqueeFadeMode = MARQUEE_FADE_SWITCH_SHOW_FADE;
                final Layout tmp = mLayout;
                mLayout = mSavedMarqueeModeLayout;
                mSavedMarqueeModeLayout = tmp;
                setHorizontalFadingEdgeEnabled(true);
                requestLayout();
                invalidate();
            }

            if (mMarquee == null) mMarquee = new Marquee(this);
            mMarquee.start(mMarqueeRepeatLimit);
        }
    }
    
     private boolean canMarquee() {
        int width = mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight();
        return width > 0 && (mLayout.getLineWidth(0) > width
                || (mMarqueeFadeMode != MARQUEE_FADE_NORMAL && mSavedMarqueeModeLayout != null
                        && mSavedMarqueeModeLayout.getLineWidth(0) > width));
    }

二、高端玩家設置跑馬燈效果

     從上面總結(jié)的TextView跑馬燈源碼可以看到,只要isFocusable()或者isSelected()方法返回true,那么就沒必要管是否觸摸模式,是否可以獲取焦點之類的問題了,所以我們可以自定義一個類繼承于TextView,然后重寫isFocusable()直接返回true即可:

public class MarqueeTextView extends TextView {

    public MarqueeTextView(Context context) {
        super(context);
        initView(context);
    }

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

    public MarqueeTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context);
    }

    private void initView(Context context) {
        this.setEllipsize(TextUtils.TruncateAt.MARQUEE);
        this.setSingleLine(true);
        this.setMarqueeRepeatLimit(-1);
    }

    //最關(guān)鍵的部分
    public boolean isFocused() {
        return true;
    }
}

1、直接在Xml中使用自定義的MarqueeTextView,那么跑馬燈效果就出來了,無需任何額外配置

 <com.example.MarqueeTextView
        android:id="@+id/tv"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/show_float"
        android:layout_marginTop="20dp"
        android:padding="10dp"
        android:text="歡迎來到跑馬燈高端玩家局,這是高端玩法示例~"
        android:textColor="@color/white"
        android:background="@drawable/com_live_rounded_rectangle"/>

來看看效果:

在這里插入圖片描述

三、延伸閱讀

     假如有這樣一個需求:因為顯示文本的空間有限,所以只能用跑馬燈的效果來給用戶展示文本,但是在用戶完整地看完一遍文本之后,需要隱藏掉Textview,那么問題來了,我們怎么知道跑馬燈效果什么時候跑完一遍呢?先來看看Textview跑馬燈部分Marquee類的部分源碼:

       void start(int repeatLimit) {
       //重復次數(shù)設置0,那就直接停止跑馬燈
            if (repeatLimit == 0) {
                stop();
                return;
            }
           //...省略掉大部分不相關(guān)的代碼
                mChoreographer.postFrameCallback(mStartCallback);
            }
        }
       
      private Choreographer.FrameCallback mStartCallback = new Choreographer.FrameCallback() {
            @Override
            public void doFrame(long frameTimeNanos) {
                mStatus = MARQUEE_RUNNING;
                mLastAnimationMs = mChoreographer.getFrameTime();
                tick();
            }
        };
 
       void tick() {
            if (mStatus != MARQUEE_RUNNING) {
                return;
            }

            if (textView != null && (textView.isFocused() || textView.isSelected())) {
                long currentMs = mChoreographer.getFrameTime();
                long deltaMs = currentMs - mLastAnimationMs;
                mLastAnimationMs = currentMs;
                float deltaPx = deltaMs * mPixelsPerMs;
                mScroll += deltaPx;
                //要是跑馬燈滾動的距離大于最大距離,那么回到給mRestartCallback
                if (mScroll > mMaxScroll) {
                    mScroll = mMaxScroll;
                    mChoreographer.postFrameCallbackDelayed(mRestartCallback, MARQUEE_DELAY);
                } else {
                    mChoreographer.postFrameCallback(mTickCallback);
                }
                textView.invalidate();
            }
        }
        
         private Choreographer.FrameCallback mRestartCallback = new Choreographer.FrameCallback() {
            @Override
            public void doFrame(long frameTimeNanos) {
                if (mStatus == MARQUEE_RUNNING) {
                    if (mRepeatLimit >= 0) {
                        mRepeatLimit--;
                    }
                    start(mRepeatLimit);
                }
            }
        }

從上面對Marquee源碼分析可知,跑馬燈跑完一輪之后會調(diào)用到MarqueemRestartCallback對象的doFrame方法,那么我們來一招“偷龍轉(zhuǎn)鳳”,通過反射把mRestartCallback對象替換成我們自己實例化的對象,那么在跑馬燈跑完一輪之后就會回調(diào)到我們替換的對象中,這樣就實現(xiàn)了對跑馬燈效果跑完一輪的監(jiān)聽,實現(xiàn)源碼如下:

public class MarqueeTextView extends androidx.appcompat.widget.AppCompatTextView {
    private Choreographer.FrameCallback mRealRestartCallbackObj;
    private Choreographer.FrameCallback mFakeRestartCallback;
    private OnShowTextListener mOnShowTextListener;

    public MarqueeTextView(Context context, OnShowTextListener onShowTextListener) {
        super(context);
        initView(context);
        this.mOnShowTextListener = onShowTextListener;

    }

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

    public MarqueeTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context);
    }


    private void initView(Context context) {
        //繞過隱藏api的限制
        Reflection.unseal(context.getApplicationContext());

        //設置跑馬燈生效條件
        this.setEllipsize(TextUtils.TruncateAt.MARQUEE);
        this.setSingleLine(true);
        this.setFocusable(true);

        //反射設置跑馬燈監(jiān)聽
        try {
            //從TextView類中找到定義的字段mMarquee
            Field marqueeField = ReflectUtil.getDeclaredField(TextView.class, "mMarquee");
            //獲取Marquee類的構(gòu)造方法Marquee(TextView v)
            Constructor declaredConstructor = ReflectUtil.getDeclaredConstructor(Class.forName("android.widget.TextView$Marquee"), TextView.class);
            //實例化一個Marquee對象,傳入?yún)?shù)是Textview對象
            Object marqueeObj = declaredConstructor.newInstance(this);
            //從Marquee類中找到定義的字段mRestartCallback,重新開始一輪跑馬燈時候會回調(diào)到這個對象doFrame()方法
            Field restartCallbackField = ReflectUtil.getDeclaredField(Class.forName("android.widget.TextView$Marquee"), "mRestartCallback");
            //從Marquee實例對象中獲取到真實的mRestartCallback對象
            mRealRestartCallbackObj = (Choreographer.FrameCallback) restartCallbackField.get(marqueeObj);
            //構(gòu)造一個假的mRestartCallback對象,用來監(jiān)聽什么時候跑完一輪跑馬燈效果
            mFakeRestartCallback = new Choreographer.FrameCallback() {
                @Override
                public void doFrame(long frameTimeNanos) {
                    //這里還是執(zhí)行真實的mRestartCallback對象的代碼邏輯
                    mRealRestartCallbackObj.doFrame(frameTimeNanos);
                    Log.i("min77","跑馬燈文本顯示完畢");
                    //回調(diào)通知跑完一輪
                    if(MarqueeTextView.this.mOnShowTextListener != null){
                        MarqueeTextView.this.mOnShowTextListener.onComplete(0);
                    }

                }
            };
            //把假的mRestartCallback對象設置給Marquee對象,其實就是代理模式
            restartCallbackField.set(marqueeObj, mFakeRestartCallback);
            //把自己實例化的Marquee對象設置給Textview
            marqueeField.set(this, marqueeObj);


        } catch (Exception e) {
            e.printStackTrace();
            Log.e("min77",e.getMessage());
        }
    }



    //最關(guān)鍵的部分
    public boolean isFocused() {
        return true;
    }

    /**
     * 是否顯示完整文本
     */
    public interface OnShowTextListener{
        void onComplete(int delayMillisecond);

    }

}

效果如下:

在這里插入圖片描述

總結(jié)

到此這篇關(guān)于Android TextView實現(xiàn)跑馬燈效果代碼的文章就介紹到這了,更多相關(guān)Android TextView跑馬燈效果內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android Studio 打包生成APK文件方法

    Android Studio 打包生成APK文件方法

    Android Studio是谷歌推出一個Android集成開發(fā)工具,基于IntelliJ IDEA。這篇文章主要介紹了Android Studio 打包生成APK文件方法,需要的朋友可以參考下
    2018-07-07
  • 基于Android LayoutInflater的使用介紹

    基于Android LayoutInflater的使用介紹

    本篇文章小編為大家介紹,基于Android LayoutInflater的使用介紹。需要的朋友參考下
    2013-04-04
  • 掌握Android Handler消息機制核心代碼

    掌握Android Handler消息機制核心代碼

    該文主要是分析Handler消息機制的關(guān)鍵源碼,文章會從對handler有一些基本的認識開始介紹,內(nèi)容詳細,感興趣的小伙伴可以參考下
    2021-09-09
  • Android 多線程的實現(xiàn)方法總結(jié)

    Android 多線程的實現(xiàn)方法總結(jié)

    這篇文章主要介紹了Android 多線程的實現(xiàn)方法總結(jié)的相關(guān)資料,這里提供三種方法,幫助大家掌握這部分內(nèi)容,需要的朋友可以參考下
    2017-08-08
  • android自定義view之實現(xiàn)日歷界面實例

    android自定義view之實現(xiàn)日歷界面實例

    本篇文章主要介紹了android自定義view之實現(xiàn)日歷界面實例,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2017-03-03
  • android如何獲取view在布局中的高度與寬度詳解

    android如何獲取view在布局中的高度與寬度詳解

    這篇文章主要給大家介紹了關(guān)于android如何獲取view在布局中的高度與寬度的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-10-10
  • Android控件之ListView用法實例詳解

    Android控件之ListView用法實例詳解

    這篇文章主要介紹了Android控件之ListView用法,以兩則實例形式較為詳細的分析了ListView控件顯示信息列表時的具體使用技巧,需要的朋友可以參考下
    2015-09-09
  • Android自定義流式布局的實現(xiàn)示例

    Android自定義流式布局的實現(xiàn)示例

    這篇文章主要介紹了Android自定義流式布局的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-12-12
  • TabLayout+ViewPager2的簡單使用詳解

    TabLayout+ViewPager2的簡單使用詳解

    這篇文章主要為大家詳細介紹了TabLayout+ViewPager2的簡單使用,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-09-09
  • android通過配置文件設置應用安裝到SD卡上的方法

    android通過配置文件設置應用安裝到SD卡上的方法

    在AndroidManifest.xml文件的manifest里面加上一句話,就可以把應用安裝到SD卡上
    2013-11-11

最新評論