高仿《今日头条》滚动TitleBar

来源:互联网 发布:天猫和淘宝的经营范围 编辑:程序博客网 时间:2024/05/02 04:28
《今日头条》滚动TitleBar

借鉴自:http://blog.csdn.net/hantangsongming/article/details/42455219
自己详细描述了下实现方法

细节描述:按住下方viewpage 可以平滑滚动上方titlebar,红色框可以改变宽度,并且 注意了么.字体颜色是可以改变一半儿的


实现思路:原生控件的话,肯定是不支持字体颜色一半是白色,一半是黑色的,所以我们要拿到canvas,在原来的textview​上面 再画一层白色的TextView颜色,严格控制字体坐标,然后用红色框剪切canvas 只显示框内的内容
也就是说 分成了上下两层:
最下层:
第二层:
用矩形剪切后:
横向滚动条:继承HorizontalScrollView,用它可以setview加入多个item,如果用普通不能滚动的布局.你item用scrollTo方法滚动到边界的时候会发现下一个item还没draw出来
canvas上画字体:由于canvas上画字体的API很恶心,超级难用.这里用了开源的类TextDrawable,可以方便的提供字体的宽度,边界等重要信息,方便画

下面上代码:
首先是MainActivity.java
package com.example.mytitle;
 
import java.util.ArrayList;
import java.util.List;
 
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
 
public class MainActivity extends FragmentActivity {
private ViewPager viewPager;//下方的viewPager
private SmoothTabTitle title;//实现的平滑滚动title
 
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
 
}
 
private void initView() {
viewPager = (ViewPager) findViewById(R.id.viewpager);
title = (SmoothTabTitle) findViewById(R.id.title);
viewPager.setAdapter(new MyPagerAdapter(getSupportFragmentManager()));
title.setViewPager(viewPager);
}
 
public class MyPagerAdapter extends FragmentPagerAdapter {
 
private final List<String> pages = new ArrayList<String>();
 
public MyPagerAdapter(FragmentManager fm) {
super(fm);
pages.add("aaaaaaaa");//设置titlebar元素的文本内容 和个数
pages.add("bbbb");
pages.add("cccccccccccccc");
pages.add("dd");
}
 
@Override
public CharSequence getPageTitle(int position) {
return pages.get(position);
}
 
@Override
public int getCount() {
return pages.size();
}
 
@Override
public Fragment getItem(int position) {
return PagesFragment.newInstance(position);
}
 
}
 
}
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >
    <LinearLayout
        android:id="@+id/title_layout"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerVertical="true"
        android:background="@drawable/bg_title_bar"
         >
        <com.example.mytitle.SmoothTabTitle
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:clipToPadding="false"
            android:paddingLeft="6.0dip"
            android:paddingRight="6.0dip" />
    </LinearLayout>
    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_below="@+id/title_layout"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />
</RelativeLayout> 

viewPager的内容页 PagesFragment.java 
package com.example.mytitle;
 
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
 
public class PagesFragment extends Fragment {
 
private static final String ARG_POSITION = "position";
 
private int position;
 
public static PagesFragment newInstance(int position) {
PagesFragment f = new PagesFragment();
Bundle b = new Bundle();
b.putInt(ARG_POSITION, position);
f.setArguments(b);
return f;
}
 
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
 
position = getArguments().getInt(ARG_POSITION);
}
 
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
 
View view = inflater.inflate(R.layout.page_item, container, false);
TextView viewhello = (TextView) view.findViewById(R.id.pagetext);
viewhello.setText("PAGE " + (position + 1));
return view;
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
PageFragement的布局XML  page_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="fill_parent"
     >
    <TextView
        android:id="@+id/pagetext"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_gravity="center" />
</RelativeLayout> 
 
自定义的TitieBar类:SmoothTabTitle.java 
package com.example.mytitle;
 
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.TextView;
 
public class SmoothTabTitle extends HorizontalScrollView {
 
private LayoutInflater mLayoutInflater;
private ViewPager pager;
private final PageListener pageListener = new PageListener();
private int currentPosition = 0;
private float currentPositionOffset = 0f;
private LinearLayout tabsContainer;
private int tabCount;
private LinearLayout.LayoutParams defaultTabLayoutParams;
private Rect selectedRect;
private Drawable selected;
private int scrollOffset = 10;
private int lastScrollX = 0;
private TextDrawable[] drawables;// TextDrawable是一个可以画Text的Drawable对象
 
public SmoothTabTitle(Context context) {
this(context, null);
}
 
public SmoothTabTitle(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
 
public SmoothTabTitle(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
 
private void initView(Context context) {
mLayoutInflater = LayoutInflater.from(context);
drawables = new TextDrawable[3];
int i = 0;
while (i &lt; drawables.length) {
drawables[i] = new TextDrawable(getContext());
i++;
}
selectedRect = new Rect();
// scrollview的子控件高度值不足scrollview高度的时候,定义android:layout_height="fill_parent"是不起作用的,
// 必须加上fillviewport属性,当子控件的高度值大于scrollview的高度时,这个标签就没有任何意义了。
setFillViewport(true);
// 设置view是否更改,如果开发者用自定义的view,重写ondraw()应该将调用此方法设置为false,这样程序会调用自定义的布局。
setWillNotDraw(false);
// HorizontalScrollView不能放多个子控件 ,只能放一个,用一个子控件去容纳多个
tabsContainer = new LinearLayout(context);
tabsContainer.setOrientation(LinearLayout.HORIZONTAL);
tabsContainer.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
addView(tabsContainer);
 
DisplayMetrics dm = getResources().getDisplayMetrics();
// scrollOffset的默认值转变为标准尺寸COMPLEX_UNIT_DIP,10dip
scrollOffset = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, scrollOffset, dm);
 
defaultTabLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
// 绘制高亮区域作为选择指示器
selected = getResources().getDrawable(R.drawable.bg_title_selected);
}
 
public void setViewPager(ViewPager pager) {
this.pager = pager;
if (pager.getAdapter() == null) {
throw new IllegalStateException("ViewPager does not have adapter instance.");
}
pager.setOnPageChangeListener(pageListener);
notifyDataSetChanged();
}
 
// 当附加在ViewPager适配器上的数据发生变化时,应该调用该方法通知TitleBar刷新数据
public void notifyDataSetChanged() {
tabsContainer.removeAllViews();
tabCount = pager.getAdapter().getCount();
for (int i = 0; i &lt; tabCount; i++) {
addTab(i, pager.getAdapter().getPageTitle(i).toString());
}
}
 
private void addTab(final int position, String title) {
ViewGroup tab = (ViewGroup) mLayoutInflater.inflate(R.layout.title_tab_item, this, false);
TextView tabText = (TextView) tab.findViewById(R.id.tab_text);
tabText.setText(title);
tabText.setGravity(Gravity.CENTER);
tabText.setSingleLine();
tabText.setFocusable(true);
tab.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
pager.setCurrentItem(position);
}
});
 
tabsContainer.addView(tab, position, defaultTabLayoutParams);
}
 
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
calculateSelectedRect(selectedRect);
if (selected != null) {
selected.setBounds(selectedRect);
selected.draw(canvas);
}
int i = 0;
while (i &lt; tabsContainer.getChildCount()) {
// 循环画3个textview,确保i不超过当期位置的上一个和下一个
if (i &lt; currentPosition - 1 || i &gt; currentPosition + 1) {
i++;
} else {
ViewGroup childTab = (ViewGroup) tabsContainer.getChildAt(i);
TextView tab_text = (TextView) childTab.findViewById(R.id.tab_text);
if (tab_text != null) {
TextDrawable textDrawable = drawables[i - currentPosition + 1];
// int save = canvas.save();
// calculateSelectedRect(selectedRect);
canvas.clipRect(selectedRect);// 只有在这个区域内的才显示,其他内容被裁剪掉 不显示
textDrawable.setText(tab_text.getText());
textDrawable.setTextSize(0, tab_text.getTextSize());
textDrawable.setTextColor(getResources().getColor(R.color.title_tab_highlight_text));
// 根据tab_text的位置计算textDrawable的字体应该在什么位置
int left = childTab.getLeft() + tab_text.getLeft() + (tab_text.getWidth() - textDrawable.getIntrinsicWidth()) / 2 + getPaddingLeft();
int top = childTab.getTop() + tab_text.getTop() + (tab_text.getHeight() - textDrawable.getIntrinsicHeight()) / 2 + getPaddingTop();
int right = textDrawable.getIntrinsicWidth() + left;
int bottom = textDrawable.getIntrinsicHeight() + top;
 
textDrawable.setBounds(left, top, right, bottom);
textDrawable.draw(canvas);
// canvas.restoreToCount(save);
}
i++;
}
}
}
 
// 计算滑动过程中矩形高亮区域的上下左右位置
private void calculateSelectedRect(Rect rect) {
ViewGroup currentTab = (ViewGroup) tabsContainer.getChildAt(currentPosition);
TextView currentTabText = (TextView) currentTab.findViewById(R.id.tab_text);
 
float left = (float) (currentTab.getLeft() + currentTabText.getLeft());
float width = ((float) currentTabText.getWidth()) + left;
// 如果当前位置偏移&gt;0 或者当前位置是最后一个,因为是draw方法不停调用这个方法,所以下面的括号内实现了平滑滚动选中框
if (currentPositionOffset &gt; 0f && currentPosition &lt; tabCount - 1) {
ViewGroup nextTab = (ViewGroup) tabsContainer.getChildAt(currentPosition + 1);
TextView next_text = (TextView) nextTab.findViewById(R.id.tab_text);
 
float next_left = (float) (nextTab.getLeft() + next_text.getLeft());
left = left * (1.0f - currentPositionOffset) + next_left * currentPositionOffset;
width = width * (1.0f - currentPositionOffset) + currentPositionOffset * (((float) next_text.getWidth()) + next_left);
}
// 新的rect位置
int newLeft = (int) (left + getPaddingLeft());
int newTop = getPaddingTop() + currentTab.getTop() + currentTabText.getTop();
int newRight = (int) (width + getPaddingLeft());
int newBottom = currentTab.getTop() + getPaddingTop() + currentTabText.getTop() + currentTabText.getHeight();
rect.set(newLeft, newTop, newRight, newBottom);
}
 
// 滑动到某个子视图
private void scrollToChild(int position, int offset) {
 
if (tabCount == 0) {
return;
}
calculateSelectedRect(selectedRect);
int newScrollX = lastScrollX;
if (selectedRect.left &lt; getScrollX() + scrollOffset) {
newScrollX = selectedRect.left - scrollOffset;
} else if (selectedRect.right &gt; getScrollX() + getWidth() - scrollOffset) {
newScrollX = selectedRect.right - getWidth() + scrollOffset;
}
if (newScrollX != lastScrollX) {
lastScrollX = newScrollX;
scrollTo(newScrollX, 0);
}
}
 
// 计算滚动到最右边范围
private int getScrollRange() {
int range = getChildAt(0).getWidth() - getWidth() + getPaddingLeft() + getPaddingRight();
return getChildCount() &gt; 0 ? Math.max(0, range) : 0;
}
 
private class PageListener implements OnPageChangeListener {
 
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
currentPosition = position;
currentPositionOffset = positionOffset;
 
scrollToChild(position, (int) (positionOffset * tabsContainer.getChildAt(position).getWidth()));
 
invalidate();
 
}
 
@Override
public void onPageScrollStateChanged(int state) {
// if (state == ViewPager.SCROLL_STATE_IDLE) {
// if (pager.getCurrentItem() == 0) {
// // 滑动到最左边
// scrollTo(0, 0);
// }
// else if (pager.getCurrentItem() == tabCount - 1) {
// // 滑动到最右边
// scrollTo(getScrollRange(), 0);
// }
// else {
// scrollToChild(pager.getCurrentItem(), 0);
// }
// }
}
 
@Override
public void onPageSelected(int position) {
 
}
 
}
}
标题栏item的子布局XML  title_tab_item.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="fill_parent"
    android:paddingLeft="6.0dip"
    android:paddingRight="6.0dip" >
    <TextView
        android:id="@+id/tab_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:paddingBottom="4.0dip"
        android:paddingLeft="8.0dip"
        android:paddingRight="8.0dip"
        android:paddingTop="4.0dip"
        android:textColor="#ff707070"
        android:textSize="15sp" />
</FrameLayout>  

工具类: TextDrawable .java

package com.example.mytitle;
 
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.TypedValue;
 
/**
* A Drawable object that draws text.绘制文本的可绘制对象
* A TextDrawable accepts most of the same parameters that can be applied to
* {@link android.widget.TextView} for displaying and formatting text.
*TextDrawable接受了大部分跟TextView中一样的的参数 用来显示和规范文字
* Optionally, a {@link Path} may be supplied on which to draw the text. 还可以选择把文字按路径来画
*
* A TextDrawable has an intrinsic size equal to that required to draw all
* the text it has been supplied, when possible. In cases where a {@link Path}
* has been supplied, the caller must explicitly call
*
* {@link #setBounds(android.graphics.Rect) setBounds()} to provide the Drawable
* size based on the Path constraints.
*/
public class TextDrawable extends Drawable {
 
/* Platform XML constants for typeface */
private static final int SANS = 1;
private static final int SERIF = 2;
private static final int MONOSPACE = 3;
 
/* Resources for scaling values to the given device */
private Resources mResources;//为指定设备提供缩放值的Resources
/* Paint to hold most drawing primitives for the text */
private TextPaint mTextPaint;//完成text大多数图元绘制的画笔
/* Layout is used to measure and draw the text */
private StaticLayout mTextLayout; //用来测量画text的layout
/* Alignment of the text inside its bounds *///text范围内的准线
private Layout.Alignment mTextAlignment = Layout.Alignment.ALIGN_NORMAL;
/* Optional path on which to draw the text *///选择画出文本的路径
private Path mTextPath;
/* Stateful text color list *///有状态的文本颜色列表
private ColorStateList mTextColors;
/* Container for the bounds to be reported to widgets */
private Rect mTextBounds;
/* Text string to draw */
private CharSequence mText = "";//被画出的文本
 
/* Attribute lists to pull default values from the current theme */
private static final int[] themeAttributes = {
android.R.attr.textAppearance
};
private static final int[] appearanceAttributes = {
android.R.attr.textSize,
android.R.attr.typeface,
android.R.attr.textStyle,
android.R.attr.textColor
};
 
 
public TextDrawable(Context context) {
super();
//Used to load and scale resource items
mResources = context.getResources();
//Definition of this drawables size
mTextBounds = new Rect();
//Paint to use for the text
mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.density = mResources.getDisplayMetrics().density;
mTextPaint.setDither(true);
 
int textSize = 15;
ColorStateList textColor = null;
int styleIndex = -1;
int typefaceIndex = -1;
 
//Set default parameters from the current theme
TypedArray a = context.getTheme().obtainStyledAttributes(themeAttributes);
int appearanceId = a.getResourceId(0, -1);
a.recycle();
 
TypedArray ap = null;
if (appearanceId != -1) {
ap = context.obtainStyledAttributes(appearanceId, appearanceAttributes);
}
if (ap != null) {
for (int i=0; i &lt; ap.getIndexCount(); i++) {
int attr = ap.getIndex(i);
switch (attr) {
case 0: //Text Size
textSize = a.getDimensionPixelSize(attr, textSize);
break;
case 1: //Typeface
typefaceIndex = a.getInt(attr, typefaceIndex);
break;
case 2: //Text Style
styleIndex = a.getInt(attr, styleIndex);
break;
case 3: //Text Color
textColor = a.getColorStateList(attr);
break;
default:
break;
}
}
 
ap.recycle();
}
 
setTextColor(textColor != null ? textColor : ColorStateList.valueOf(0xFF000000));
setRawTextSize(textSize);
 
Typeface tf = null;
switch (typefaceIndex) {
case SANS:
tf = Typeface.SANS_SERIF;
break;
 
case SERIF:
tf = Typeface.SERIF;
break;
 
case MONOSPACE:
tf = Typeface.MONOSPACE;
break;
}
 
setTypeface(tf, styleIndex);
}
 
 
/**
* Set the text that will be displayed
* @param text Text to display
*/
public void setText(CharSequence text) {
if (text == null) text = "";
 
mText = text;
 
measureContent();
}
 
/**
* Return the text currently being displayed
*/
public CharSequence getText() {
return mText;
}
 
/**
* Return the current text size, in pixels
*/
public float getTextSize() {
return mTextPaint.getTextSize();
}
 
/**
* Set the text size. The value will be interpreted in "sp" units
* @param size Text size value, in sp
*/
public void setTextSize(float size) {
setTextSize(TypedValue.COMPLEX_UNIT_SP, size);
}
 
/**
* Set the text size, using the supplied complex units
* @param unit Units for the text size, such as dp or sp
* @param size Text size value
*/
public void setTextSize(int unit, float size) {
float dimension = TypedValue.applyDimension(unit, size,
mResources.getDisplayMetrics());
setRawTextSize(dimension);
}
 
/*
* Set the text size, in raw pixels
*/
private void setRawTextSize(float size) {
if (size != mTextPaint.getTextSize()) {
mTextPaint.setTextSize(size);
 
measureContent();
}
}
 
/**
* Return the horizontal stretch factor of the text
*/
public float getTextScaleX() {
return mTextPaint.getTextScaleX();
}
 
/**
* Set the horizontal stretch factor of the text
* @param size Text scale factor
*/
public void setTextScaleX(float size) {
if (size != mTextPaint.getTextScaleX()) {
mTextPaint.setTextScaleX(size);
measureContent();
}
}
 
/**
* Return the current text alignment setting
*/
public Layout.Alignment getTextAlign() {
return mTextAlignment;
}
 
/**
* Set the text alignment. The alignment itself is based on the text layout direction.
* For LTR text NORMAL is left aligned and OPPOSITE is right aligned.
* For RTL text, those alignments are reversed.
* @param align Text alignment value. Should be set to one of:
*
* {@link Layout.Alignment#ALIGN_NORMAL},
* {@link Layout.Alignment#ALIGN_NORMAL},
* {@link Layout.Alignment#ALIGN_OPPOSITE}.
*/
public void setTextAlign(Layout.Alignment align) {
if (mTextAlignment != align) {
mTextAlignment = align;
measureContent();
}
}
 
/**
* Sets the typeface and style in which the text should be displayed.
* Note that not all Typeface families actually have bold and italic
* variants, so you may need to use
* {@link #setTypeface(Typeface, int)} to get the appearance
* that you actually want.
*/
public void setTypeface(Typeface tf) {
if (mTextPaint.getTypeface() != tf) {
mTextPaint.setTypeface(tf);
 
measureContent();
}
}
 
/**
* Sets the typeface and style in which the text should be displayed,
* and turns on the fake bold and italic bits in the Paint if the
* Typeface that you provided does not have all the bits in the
* style that you specified.
*
*/
public void setTypeface(Typeface tf, int style) {
if (style &gt; 0) {
if (tf == null) {
tf = Typeface.defaultFromStyle(style);
} else {
tf = Typeface.create(tf, style);
}
 
setTypeface(tf);
// now compute what (if any) algorithmic styling is needed
int typefaceStyle = tf != null ? tf.getStyle() : 0;
int need = style & ~typefaceStyle;
mTextPaint.setFakeBoldText((need & Typeface.BOLD) != 0);
mTextPaint.setTextSkewX((need & Typeface.ITALIC) != 0 ? -0.25f : 0);
} else {
mTextPaint.setFakeBoldText(false);
mTextPaint.setTextSkewX(0);
setTypeface(tf);
}
}
 
/**
* Return the current typeface and style that the Paint
* using for display.
*/
public Typeface getTypeface() {
return mTextPaint.getTypeface();
}
 
/**
* Set a single text color for all states
* @param color Color value such as {@link Color#WHITE} or {@link Color#argb(int, int, int, int)}
*/
public void setTextColor(int color) {
setTextColor(ColorStateList.valueOf(color));
}
 
/**
* Set the text color as a state list
* @param colorStateList ColorStateList of text colors, such as inflated from an R.color resource
*/
public void setTextColor(ColorStateList colorStateList) {
mTextColors = colorStateList;
updateTextColors(getState());
}
 
/**
* Optional Path object on which to draw the text. If this is set,
* TextDrawable cannot properly measure the bounds this drawable will need.
* You must call {@link #setBounds(int, int, int, int) setBounds()} before
* applying this TextDrawable to any View.
*
* Calling this method with &lt;code&gt;null&lt;/code&gt; will remove any Path currently attached.
*/
public void setTextPath(Path path) {
if (mTextPath != path) {
mTextPath = path;
measureContent();
}
}
 
/**
* Internal method to take measurements of the current contents and apply
* the correct bounds when possible.
*/
private void measureContent() {
//If drawing to a path, we cannot measure intrinsic bounds
//We must resly on setBounds being called externally
if (mTextPath != null) {
//Clear any previous measurement
mTextLayout = null;
mTextBounds.setEmpty();
} else {
//Measure text bounds
double desired = Math.ceil( Layout.getDesiredWidth(mText, mTextPaint) );
mTextLayout = new StaticLayout(mText, mTextPaint, (int)desired,
mTextAlignment, 1.0f, 0.0f, false);
mTextBounds.set(0, 0, mTextLayout.getWidth(), mTextLayout.getHeight());
}
 
//We may need to be redrawn
invalidateSelf();
}
 
/**
* Internal method to apply the correct text color based on the drawable's state
*/
private boolean updateTextColors(int[] stateSet) {
int newColor = mTextColors.getColorForState(stateSet, Color.WHITE);
if (mTextPaint.getColor() != newColor) {
mTextPaint.setColor(newColor);
return true;
}
 
return false;
}
 
@Override
protected void onBoundsChange(Rect bounds) {
//Update the internal bounds in response to any external requests
mTextBounds.set(bounds);
}
 
@Override
public boolean isStateful() {
/*
* The drawable's ability to represent state is based on
* the text color list set
*/
return mTextColors.isStateful();
}
 
@Override
protected boolean onStateChange(int[] state) {
//Upon state changes, grab the correct text color
return updateTextColors(state);
}
 
@Override
public int getIntrinsicHeight() {
//Return the vertical bounds measured, or -1 if none
if (mTextBounds.isEmpty()) {
return -1;
} else {
return (mTextBounds.bottom - mTextBounds.top);
}
}
 
@Override
public int getIntrinsicWidth() {
//Return the horizontal bounds measured, or -1 if none
if (mTextBounds.isEmpty()) {
return -1;
} else {
return (mTextBounds.right - mTextBounds.left);
}
}
 
@Override
public void draw(Canvas canvas) {
final Rect bounds = getBounds();
final int count = canvas.save();
canvas.translate(bounds.left, bounds.top);
if (mTextPath == null) {
//Allow the layout to draw the text
mTextLayout.draw(canvas);
} else {
//Draw directly on the canvas using the supplied path
canvas.drawTextOnPath(mText.toString(), mTextPath, 0, 0, mTextPaint);
}
canvas.restoreToCount(count);
}
 
@Override
public void setAlpha(int alpha) {
if (mTextPaint.getAlpha() != alpha) {
mTextPaint.setAlpha(alpha);
}
}
 
@Override
public int getOpacity() {
return mTextPaint.getAlpha();
}
 
@Override
public void setColorFilter(ColorFilter cf) {
if (mTextPaint.getColorFilter() != cf) {
mTextPaint.setColorFilter(cf);
}
}
 
}
颜色:color.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="title_tab_highlight_text">#fffafafa</color>
</resources> 
 AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.mytitle"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" />
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.mytitle.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>
Drawable文件夹下 bg_title_bar.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list
  xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <solid android:color="#ffdddddd" />
        </shape>
    </item>
    <item android:bottom="0.5dip">
        <shape>
            <solid android:color="#ffeeeeee" />
        </shape>
    </item>
</layer-list>  
Drawable文件夹下 bg_title_selected.xml
<?xml version="1.0" encoding="utf-8"?>
<shape
  xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#ffd43d3d" />
    <corners android:radius="4.0dip" />
</shape>  


DEMO源码下载:mytitle.rar











1 0
原创粉丝点击