我尝试了几种不同的方法,包括找到here的方法(这反过来让我尝试了this问题的两个最佳答案),以及使用反射来获取访问权限到TextView并设置相关方法。两次尝试均失败,前者导致根本没有文本被设置为标题(我将文本设置为正确的textview元素),后者设置文本并删除椭圆,但根本没有绘制。以下是我的反思尝试。
import android.content.Context;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.TextView;
import android.widget.Toast;
import java.lang.reflect.Field;
public class MarqueeToolbar extends Toolbar {
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) {
if (!reflected) {
reflected = reflectTitle();
}
super.setTitle(title);
}
@Override
public void setTitle(int resId) {
if (!reflected) {
reflected = reflectTitle();
}
super.setTitle(resId);
}
boolean reflected = false;
private boolean reflectTitle() {
try {
Field field = Toolbar.class.getDeclaredField("mTitleTextView");
field.setAccessible(true);
TextView titleView = (TextView) field.get(this);
titleView.setEllipsize(TextUtils.TruncateAt.MARQUEE);
titleView.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;
}
}
}
答案 0 :(得分:9)
从TextView
类中的TextView
的已声明字段名称和工具栏的Marquee标题中获取标题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) {
}
答案 1 :(得分:6)
尝试将TextView放在工具栏中:
<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>
然后,使用工具栏作为ActionBar并清除/禁用其标题:
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setTitle(null); // or, setDisplayShowTitleEnabled(false)
答案 2 :(得分:3)
最终想出来,这是因为,根据我的理解,设置选框的TextViews需要在实际开始选框之前被选中。我更新了我在问题中发布的MarqueeToolbar类,可以在此Gist中找到:https://gist.github.com/InsanityOnABun/95c0757f2f527cc50e39
答案 3 :(得分:1)
Kotlin解决方案为标题和字幕TextViews设置MARQUEE
(它只是在工具栏中找到所有TextViews):
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
}
因此不必将工具栏视图(android.support.v7.widget.Toolbar
或androidx.appcompat.widget.Toolbar
)添加到xml布局
您可以使用AppCompat主题自动添加的默认工具栏:
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
答案 4 :(得分:0)
创建自定义工具栏并应用标题和字幕选框效果:
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);
}
}