Marquee title in Toolbar / ActionBar in Android with Lollipop SDK?
Asked Answered
A

5

10

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 to get access to the TextView and setting the relevant methods. Both attempts failed, the former resulting in no text at all being set to the title (and I was setting the text to the proper textview element), the latter setting the text and removing the ellipse, but not marqueeing at all. Below is my reflection attempt.

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;
        }
    }
}
Athey answered 24/11, 2014 at 2:43 Comment(0)
A
4

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

Athey answered 4/1, 2015 at 3:37 Comment(0)
P
14

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) {
    }
Paz answered 5/3, 2015 at 13:37 Comment(3)
getting this : Attempt to invoke virtual method 'void android.widget.TextView.setEllipsize(android.text.TextUtils$TruncateAt)' on a null object referenceRoehm
Works for me on android 7.0.Kwarteng
worked without the options menu but not with an option menuPreparator
P
6

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)
Pinckney answered 18/12, 2014 at 22:58 Comment(1)
nice code but didnt work in kitkat and above. is there something else i can do?Motorize
A
6

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">
Azzieb answered 29/1, 2019 at 19:22 Comment(0)
A
4

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

Athey answered 4/1, 2015 at 3:37 Comment(0)
E
0

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

}
Embarrass answered 24/5, 2016 at 10:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.