Android标题居中的Toolbar

来源:互联网 发布:视频编辑软件中文版 编辑:程序博客网 时间:2024/06/06 10:46

2017年特意写第一篇博客开个头。之前一直不写博客的原因,一个是懒,另一个是因为觉得自己没那个能力,会误导别人。但是最近特别想听听别人的意见,所以就下定决心开始写博客。废话不说,赶快开波。

前言

用过Toolbar的都知道标题是在左边的,但通常UI都要求我们把标题居中。没用过的童鞋可以看看泡网的一篇文章android:ToolBar详解(手把手教程)。我并不想自己写一个布局来充当Toolbar,因为那样会增加不少工作量。但怎样才能把Toolbar的标题居中?
有问题先google。如果你还在百度的话,我也没什么办法了。谷歌后找到这样一种方法。在原来的Toolbar里面加上一个TextView,标题居中的关键是第12行,将layout_gravity设置成center。

    <android.support.v7.widget.Toolbar        android:id="@+id/toolbar"        android:layout_width="match_parent"        android:layout_height="?attr/actionBarSize"        android:background="?attr/colorPrimary">        <TextView            android:id="@+id/toolbar_title"            style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_gravity="center"/>    </android.support.v7.widget.Toolbar>

接着再来个helper类。很简单的一个类,看看init方法就可以过了。

public class ToolbarHelper {    private TextView mTitleTextView;    private Toolbar mToolbar;    public void init(AppCompatActivity activity, Toolbar toolbar, TextView titleTextView) {        if (activity == null) {            return;        }        mTitleTextView = titleTextView;        mToolbar = toolbar;        activity.setSupportActionBar(toolbar);        // titleTextView不为null才设置actionbar不显示Title        if (titleTextView != null) {            ActionBar actionBar = activity.getSupportActionBar();            if (actionBar != null) {                // 不显示title和subTitle                actionBar.setDisplayShowTitleEnabled(false);            }        }    }    public void setTitle(@StringRes int resid) {        if (mTitleTextView != null) {            mTitleTextView.setText(resid);        }    }    public void setTitle(CharSequence title) {        if (mTitleTextView != null) {            mTitleTextView.setText(title);        }    }    public void setTitleTextColor(@ColorInt int color) {        if (mTitleTextView != null) {            mTitleTextView.setTextColor(color);        }    }    public Toolbar getToolbar() {        return mToolbar;    }    public TextView getTitleTextView() {        return mTitleTextView;    }}

然后在Activity中,最好是BaseActivity,创建一个ToolbarHelper对象。在初始化View的时候,调用toolbarHelper的init()方法。

Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);TextView titleView = (TextView) findViewById(R.id.toolbar_title);mToolbarHelper.init(this, toolbar, titleView);

接下来才是重点,重写onTitleChanged方法

    @Override    protected void onTitleChanged(CharSequence title, int color) {        super.onTitleChanged(title, color);        if (mToolbarHelper != null) {            mToolbarHelper.setTitle(title);        }    }

这样标题居中的Toolbar就搞定了。但有一点值得注意的是,不要调用toolbar自身的setTitle()方法。否则的话Toolbar自身的标题也会显示。

重点来了,CenterTitleToolbar

这样就满足了吗?不,上面这种方法太麻烦了。又要在xml里面加东西,又要改activity。能不能只改动Toolbar里面的代码,不需要动Toolbar以外的任何代码就能实现标题居中?
基于这个思路,我们要创建一个Toolbar的子类。使Toolbar的title居中有两种做法。

  • 通过反射获取其mTitleTextView属性,并修改其LayoutParams的gravity属性
  • 重写toolbar的setTitle方法,自己维护一个titleTextView,并将其居中显示。

这里我选择第二种。因为第一种使用了反射,且mTitleTextView是通过懒加载形式创建的,要考虑好反射获取的时机。OK,想好了就开工了。
先来看看Toolbar源码里的setTitle()方法

    public void setTitle(CharSequence title) {        if (!TextUtils.isEmpty(title)) {            if (mTitleTextView == null) {                final Context context = getContext();                mTitleTextView = new TextView(context);                mTitleTextView.setSingleLine();                mTitleTextView.setEllipsize(TextUtils.TruncateAt.END);                if (mTitleTextAppearance != 0) {                    mTitleTextView.setTextAppearance(context, mTitleTextAppearance);                }                if (mTitleTextColor != 0) {                    mTitleTextView.setTextColor(mTitleTextColor);                }            }            if (!isChildOrHidden(mTitleTextView)) {                addSystemView(mTitleTextView, true);            }        } else if (mTitleTextView != null && isChildOrHidden(mTitleTextView)) {            removeView(mTitleTextView);            mHiddenViews.remove(mTitleTextView);        }        if (mTitleTextView != null) {            mTitleTextView.setText(title);        }        mTitleText = title;    }

看到第3-14行就知道我刚刚为什么说mTitleTextView是通过懒加载来创建了吧。其他都看懂了,isChildOrHidden,addSystemView这两个方法做了什么?继续看源码。

    // 判断该view的父View是否为Toolbar    private boolean isChildOrHidden(View child) {        return child.getParent() == this || mHiddenViews.contains(child);    }    // 创建LayoutParams对象,并添加到Toolbar    private void addSystemView(View v, boolean allowHide) {        final ViewGroup.LayoutParams vlp = v.getLayoutParams();        final LayoutParams lp;        if (vlp == null) {            lp = generateDefaultLayoutParams();        } else if (!checkLayoutParams(vlp)) {            lp = generateLayoutParams(vlp);        } else {            lp = (LayoutParams) vlp;        }        lp.mViewType = LayoutParams.SYSTEM;        if (allowHide && mExpandedActionView != null) {            v.setLayoutParams(lp);            mHiddenViews.add(v);        } else {            addView(v, lp);        }    }

这两个方法中都有mHiddenViews,这个对于我们的需求没什么用,忽略就好了。不必每句都看懂,我们知道它大概做了什么即可。
OK,开始写我们的CenterTitleToolbar。先继承Toolbar,声明和Title相关的属性

    private TextView mTitleTextView;    private CharSequence mTitleText;    private int mTitleTextColor;    private int mTitleTextAppearance;

重写setTitle()方法。

    @Override    public void setTitle(CharSequence title) {        if (!TextUtils.isEmpty(title)) {            if (mTitleTextView == null) { // 懒加载                final Context context = getContext();                mTitleTextView = new TextView(context);                mTitleTextView.setSingleLine();                mTitleTextView.setEllipsize(TextUtils.TruncateAt.END);                if (mTitleTextAppearance != 0) {                    mTitleTextView.setTextAppearance(context, mTitleTextAppearance);                }                if (mTitleTextColor != 0) {                    mTitleTextView.setTextColor(mTitleTextColor);                }            }            if (mTitleTextView.getParent() != this) {                // 添加到Toolbar并居中显示                addCenterView(mTitleTextView);            }        } else if (mTitleTextView != null && mTitleTextView.getParent() == this) {            // 当title为空时,remove            removeView(mTitleTextView);        }        if (mTitleTextView != null) {            mTitleTextView.setText(title);        }        mTitleText = title;    }

依照原来的思路稍微的修改。代码和原来的雷同,改动的地方就只有16,18,20和22行。关键是addCenterView这个方法。标题居中就看这里了。

    private void addCenterView(View v) {        final ViewGroup.LayoutParams vlp = v.getLayoutParams();        final LayoutParams lp;        if (vlp == null) {            lp = generateDefaultLayoutParams();        } else if (!checkLayoutParams(vlp)) {            lp = generateLayoutParams(vlp);        } else {            lp = (LayoutParams) vlp;        }        lp.gravity = Gravity.CENTER;        addView(v, lp);    }

该方法与Toolbar的addSystemView()方法雷同,我基本都是直接拷过来改要改的地方,去掉了一些无用的代码。看到第12行,没错,我们前面做了那么多,就为了将gravity设置为center。

细心的童鞋会发现,setTitle()方法里还有mTitleTextAppearance 和 mTitleTextColor需要获取。没错,要想获取这两个值,我们需要重写setTitleTextAppearance()和setTitleTextColor()方法,只不过是将原来Toolbar的代码拷过来,这里就不说了。除此之外,还需要在构建方法中自己获取一次。

        final TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,                R.styleable.Toolbar, defStyleAttr, 0);        try {            final int titleTextAppearance = a.getResourceId(R.styleable.Toolbar_titleTextAppearance, 0);            if (titleTextAppearance != 0) {                setTitleTextAppearance(context, titleTextAppearance);            }            if (a.hasValue(R.styleable.Toolbar_titleTextColor)) {                setTitleTextColor(a.getColor(R.styleable.Toolbar_titleTextColor, 0xffffffff));            }        } finally {            a.recycle();        }

这里解释下为什么已经重写了setTitleTextAppearance()和setTitleTextColor()方法还需要在构造方法中获取这两个值。因为Toolbar的源码获取TextAppearance并没有调用setTitleTextAppearance()方法,导致我们自己的mTitleTextAppearance和Toolbar的不一致。还要注意下调用那两个方法的顺序。

最后

有什么错漏的麻烦指出。感谢大家。

源码地址,喜欢的Star一下:
https://github.com/benioZhang/CenterTitleToolbar

参考:
http://blog.hwangjr.com/2015/07/10/Android-ToolBar-Widget-Usage/

0 0
原创粉丝点击