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
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">
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);
}
}
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) {
}
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)
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