Marquee title in Toolbar / ActionBar in Android with Lollipop SDK?

后端 未结 5 1619
清歌不尽
清歌不尽 2021-01-04 19:38

I\'ve tried several different approaches, including the one found here (which in turn led me to trying both of the top answers to this question), as well as using reflection

相关标签:
5条回答
  • 2021-01-04 20:15

    Kotlin solution to set MARQUEE for both Title and Subtitle TextViews (it just finds all TextViews inside Toolbar):

    findViewById<Toolbar>(R.id.action_bar)?.let {
        setToolbarTextViewsMarquee(it)
    }
    
    fun setToolbarTextViewsMarquee(toolbar: Toolbar) {
        for (child in toolbar.children) {
            if (child is TextView) {
                setMarquee(child)
            }
        }
    }
    
    fun setMarquee(textView: TextView) {
        textView.ellipsize = TextUtils.TruncateAt.MARQUEE
        textView.isSelected = true
        textView.marqueeRepeatLimit = -1
    }
    

    So it's not necessary to add Toolbar view (android.support.v7.widget.Toolbar or androidx.appcompat.widget.Toolbar) to xml layout

    You can use the default Toolbar which AppCompat theme automatically adds:

    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    
    0 讨论(0)
  • 2021-01-04 20:17

    create custom toolbar and apply title and subtitle marquee effect:

    public class MarqueeToolbar extends Toolbar {
    
    TextView title, subTitle;
    
    public MarqueeToolbar(Context context) {
        super(context);
    }
    
    public MarqueeToolbar(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
    public MarqueeToolbar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    
    @Override
    public void setTitle(CharSequence title) {
    
            reflected = reflectTitle();
    
        super.setTitle(title);
        selectTitle();
    }
    
    @Override
    public void setTitle(int resId) {
        if (!reflected) {
            reflected = reflectTitle();
        }
        super.setTitle(resId);
        selectTitle();
    }
    
    boolean reflected = false;
    private boolean reflectTitle() {
        try {
            Field field = Toolbar.class.getDeclaredField("mTitleTextView");
            field.setAccessible(true);
            title = (TextView) field.get(this);
            title.setEllipsize(TextUtils.TruncateAt.MARQUEE);
            title.setMarqueeRepeatLimit(-1);
            return true;
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
            return false;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            return false;
        } catch (NullPointerException e) {
            e.printStackTrace();
            return false;
        }
    }
    
    public void selectTitle() {
        if (title != null)
            title.setSelected(true);
    }
    
    // ------------ for Subtitle ----------
    
    @Override
    
    public void setSubtitle(CharSequence subTitle) {
        if (!reflectedSub) {
            reflectedSub = reflectSubTitle();
        }
        super.setSubtitle(subTitle);
        selectSubtitle();
    }
    
    
    @Override
    public void setSubtitle(int resId) {
        if (!reflected) {
            reflectedSub = reflectSubTitle();
        }
        super.setSubtitle(resId);
        selectSubtitle();
    }
    
    boolean reflectedSub = false;
    private boolean reflectSubTitle() {
        try {
            Field field = Toolbar.class.getDeclaredField("mSubtitleTextView");
            field.setAccessible(true);
            subTitle = (TextView) field.get(this);
            subTitle.setEllipsize(TextUtils.TruncateAt.MARQUEE);
            subTitle.setMarqueeRepeatLimit(-1);
            return true;
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
            return false;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            return false;
        } catch (NullPointerException e) {
            e.printStackTrace();
            return false;
        }
    }
    
    public void selectSubtitle() {
        if (subTitle != null)
            subTitle.setSelected(true);
    }
    
    }
    
    0 讨论(0)
  • 2021-01-04 20:22

    Get the title TextView object from declared field name of TextView in Toolbar class and Marquee title of toolbar.

        TextView titleTextView = null;
    
        try {
            Field f = toolbar.getClass().getDeclaredField("mTitleTextView");
            f.setAccessible(true);
            titleTextView = (TextView) f.get(toolbar);
    
            titleTextView.setEllipsize(TruncateAt.MARQUEE);
            titleTextView.setFocusable(true);
            titleTextView.setFocusableInTouchMode(true);
            titleTextView.requestFocus();
            titleTextView.setSingleLine(true);
            titleTextView.setSelected(true);
            titleTextView.setMarqueeRepeatLimit(-1);
    
        } catch (NoSuchFieldException e) {
        } catch (IllegalAccessException e) {
        }
    
    0 讨论(0)
  • 2021-01-04 20:25

    Try to put a TextView inside the Toolbar:

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:minHeight="?attr/actionBarSize" >
    
        <TextView
            android:id="@+id/toolbar_title"
            android:text="This will run the marquee animation forever"
            android:textSize="@dimen/abc_text_size_title_material_toolbar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="marquee"
            android:marqueeRepeatLimit="marquee_forever"
            android:scrollHorizontally="true"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:singleLine="true" />
    
    </android.support.v7.widget.Toolbar>
    

    And then, use the Toolbar as an ActionBar and clear/disable its title:

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    getSupportActionBar().setTitle(null); // or, setDisplayShowTitleEnabled(false)
    
    0 讨论(0)
  • 2021-01-04 20:38

    Figured it out eventually, it was because, from what I understand, TextViews that are set marquee need to be selected before they will actually start marqueeing. I updated my MarqueeToolbar class that I posted in the question, which can be found in this Gist: https://gist.github.com/InsanityOnABun/95c0757f2f527cc50e39

    0 讨论(0)
提交回复
热议问题