控件:
package com.rainsong.toutiaotabdemo;
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 CategoryTabStrip extends HorizontalScrollView {
private LayoutInflater mLayoutInflater;
private final PageListener pageListener = new PageListener();
private ViewPager pager;
private LinearLayout tabsContainer;
private int tabCount;
private int currentPosition = 0;
private float currentPositionOffset = 0f;
private Rect indicatorRect;
private LinearLayout.LayoutParams defaultTabLayoutParams;
private int scrollOffset = 10;
private int lastScrollX = 0;
private Drawable indicator;
private TextDrawable[] drawables;
private Drawable left_edge;
private Drawable right_edge;
public CategoryTabStrip(Context context) {
this(context, null);
}
public CategoryTabStrip(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CategoryTabStrip(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mLayoutInflater = LayoutInflater.from(context);
drawables = new TextDrawable[3];
int i = 0;
while (i < drawables.length) {
drawables[i] = new TextDrawable(getContext());
i++;
}
indicatorRect = new Rect();
//使View填充满View的宽度,HorizontalScrollView类方法
setFillViewport(true);
//设置view是否更改,如果开发者用自定义的view,重写ondraw()应该将调用此方法设置为false,这样程序会调用自定义的布局。
setWillNotDraw(false);
tabsContainer = new LinearLayout(context);
tabsContainer.setOrientation(LinearLayout.HORIZONTAL);
tabsContainer.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
addView(tabsContainer);
//代码中dp值转换成px
DisplayMetrics dm = getResources().getDisplayMetrics();
scrollOffset = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, scrollOffset, dm);
defaultTabLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
// 绘制高亮区域作为滑动分页指示器
indicator = getResources().getDrawable(R.drawable.bg_category_indicator);
// 左右边界阴影效果
left_edge = getResources().getDrawable(R.drawable.ic_category_left_edge);
right_edge = getResources().getDrawable(R.drawable.ic_category_right_edge);
}
/**
* 绑定与CategoryTabStrip控件对应的ViewPager控件,实现联动
* @param pager
*/
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适配器上的数据发生变化时,应该调用该方法通知CategoryTabStrip刷新数据
public void notifyDataSetChanged() {
tabsContainer.removeAllViews();
tabCount = pager.getAdapter().getCount();
for (int i = 0; i < tabCount; i++) {
addTab(i, pager.getAdapter().getPageTitle(i).toString());
}
}
private void addTab(final int position, String title) {
ViewGroup tab = (ViewGroup)mLayoutInflater.inflate(R.layout.category_tab, this, false);
TextView category_text = (TextView) tab.findViewById(R.id.category_text);
category_text.setText(title);
category_text.setGravity(Gravity.CENTER);
category_text.setSingleLine();
category_text.setFocusable(true);
category_text.setTextColor(getResources().getColor(R.color.category_tab_text));
tab.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// pager.setCurrentItem(position);
pager.setCurrentItem(position,false);//不需要滑动
}
});
tabsContainer.addView(tab, position, defaultTabLayoutParams);
}
/**
* 计算滑动过程中矩形高亮区域的上下左右位置
* @param rect
*/
private void calculateIndicatorRect(Rect rect) {
ViewGroup currentTab = (ViewGroup)tabsContainer.getChildAt(currentPosition);
TextView category_text = (TextView) currentTab.findViewById(R.id.category_text);
float left = (float) (currentTab.getLeft() + category_text.getLeft());
float width = ((float) category_text.getWidth()) + left;
if (currentPositionOffset > 0f && currentPosition < tabCount - 1) {
ViewGroup nextTab = (ViewGroup)tabsContainer.getChildAt(currentPosition + 1);
TextView next_category_text = (TextView) nextTab.findViewById(R.id.category_text);
float next_left = (float) (nextTab.getLeft() + next_category_text.getLeft());
left = left * (1.0f - currentPositionOffset) + next_left * currentPositionOffset;
width = width * (1.0f - currentPositionOffset) + currentPositionOffset * (((float) next_category_text.getWidth()) + next_left);
}
rect.set(((int) left) + getPaddingLeft(), getPaddingTop() + currentTab.getTop() + category_text.getTop(),
((int) width) + getPaddingLeft(), currentTab.getTop() + getPaddingTop() + category_text.getTop() + category_text.getHeight());
}
// 计算滚动范围
private int getScrollRange() {
return getChildCount() > 0 ? Math.max(0, getChildAt(0).getWidth() - getWidth() + getPaddingLeft() + getPaddingRight()) : 0;
}
private void scrollToChild(int position, int offset) {
if (tabCount == 0) {
return;
}
calculateIndicatorRect(indicatorRect);
int newScrollX = lastScrollX;
if (indicatorRect.left < getScrollX() + scrollOffset) {
newScrollX = indicatorRect.left - scrollOffset;
} else if (indicatorRect.right > getScrollX() + getWidth() - scrollOffset) {
newScrollX = indicatorRect.right - getWidth() + scrollOffset;
}
if (newScrollX != lastScrollX) {
lastScrollX = newScrollX;
scrollTo(newScrollX, 0);
}
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
calculateIndicatorRect(indicatorRect);
if(indicator != null) {
indicator.setBounds(indicatorRect);
indicator.draw(canvas);
}
int i = 0;
while (i < tabsContainer.getChildCount()) {
if (i < currentPosition - 1 || i > currentPosition + 1) {
i++;
} else {
ViewGroup tab = (ViewGroup)tabsContainer.getChildAt(i);
TextView category_text = (TextView) tab.findViewById(R.id.category_text);
if (category_text != null) {
TextDrawable textDrawable = drawables[i - currentPosition + 1];
int save = canvas.save();
calculateIndicatorRect(indicatorRect);
canvas.clipRect(indicatorRect);
textDrawable.setText(category_text.getText());
textDrawable.setTextSize(0, category_text.getTextSize());
textDrawable.setTextColor(getResources().getColor(R.color.category_tab_highlight_text));
int left = tab.getLeft() + category_text.getLeft() + (category_text.getWidth() - textDrawable.getIntrinsicWidth()) / 2 + getPaddingLeft();
int top = tab.getTop() + category_text.getTop() + (category_text.getHeight() - textDrawable.getIntrinsicHeight()) / 2 + getPaddingTop();
textDrawable.setBounds(left, top, textDrawable.getIntrinsicWidth() + left, textDrawable.getIntrinsicHeight() + top);
textDrawable.draw(canvas);
canvas.restoreToCount(save);
}
i++;
}
}
i = canvas.save();
int top = getScrollX();
int height = getHeight();
int width = getWidth();
canvas.translate((float) top, 0.0f);
if (left_edge == null || top <= 0) {
if (right_edge == null || top >= getScrollRange()) {
canvas.restoreToCount(i);
}
right_edge.setBounds(width - right_edge.getIntrinsicWidth(), 0, width, height);
right_edge.draw(canvas);
canvas.restoreToCount(i);
}
left_edge.setBounds(0, 0, left_edge.getIntrinsicWidth(), height);
left_edge.draw(canvas);
if (right_edge == null || top >= getScrollRange()) {
canvas.restoreToCount(i);
}
right_edge.setBounds(width - right_edge.getIntrinsicWidth(), 0, width, height);
right_edge.draw(canvas);
canvas.restoreToCount(i);
}
private class PageListener implements OnPageChangeListener {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// 当页面在滑动的时候会调用此方法,在滑动被停止之前,此方法会一直得到调用。
// position :当前页面,及你点击滑动的页面
// positionOffset:当前页面偏移的百分比
// positionOffsetPixels:当前页面偏移的像素位置
currentPosition = position;
currentPositionOffset = positionOffset;
scrollToChild(position, (int) (positionOffset * tabsContainer.getChildAt(position).getWidth()));
invalidate();
}
@Override
public void onPageScrollStateChanged(int state) {
// state ==1的时辰默示正在滑动,
// state==2的时辰默示滑动完毕了,
// state==0的时辰默示什么都没做。
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) {
}
}
}
控件引入:
package com.rainsong.toutiaotabdemo;
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.
*
* 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;
/* Paint to hold most drawing primitives for the text */
private TextPaint mTextPaint;
/* Layout is used to measure and draw the text */
private StaticLayout mTextLayout;
/* Alignment of the text inside its bounds */
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 < 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 > 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 <code>null</code> 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);
}
}
}
,主页面引入:
package com.rainsong.toutiaotabdemo;
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 CategoryTabStrip tabs;
private ViewPager viewPager;
private MyPagerAdapter adapter;
//这里没有进行任何处理,那么是如何保证,在activity被回收的时候,再次回到activity的时候,会显示被回收前的页面
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tabs = (CategoryTabStrip) findViewById(R.id.category_strip);
viewPager = (ViewPager) findViewById(R.id.view_pager);
adapter = new MyPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
tabs.setViewPager(viewPager);
}
public class MyPagerAdapter extends FragmentPagerAdapter {
private final List<String> datas = new ArrayList<String>();
public MyPagerAdapter(FragmentManager fm) {
super(fm);
datas.add(getString(R.string.category_hot));
datas.add("\u672c\u5730");
datas.add(getString(R.string.category_video));
datas.add(getString(R.string.category_society));
datas.add(getString(R.string.category_entertainment));
datas.add(getString(R.string.category_tech));
datas.add(getString(R.string.category_finance));
datas.add(getString(R.string.category_military));
datas.add(getString(R.string.category_world));
datas.add("红袖添香");
datas.add(getString(R.string.category_image_ppmm));
datas.add(getString(R.string.category_health));
datas.add(getString(R.string.category_government));
}
@Override
public CharSequence getPageTitle(int position) {
return datas.get(position);
}
@Override
public int getCount() {
return datas.size();
}
@Override
public Fragment getItem(int position) {
//加载被点击页面和相邻的2个页面
return NewsFragment.newInstance(position);
}
}
}
填充Fragment:
package com.rainsong.toutiaotabdemo;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.FrameLayout.LayoutParams;
import android.widget.TextView;
import android.widget.Toast;
public class NewsFragment extends Fragment {
private static final String ARG_POSITION = "position";
private int position;
public static NewsFragment newInstance(int position) {
NewsFragment f = new NewsFragment();
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) {
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
FrameLayout fl = new FrameLayout(getActivity());
fl.setLayoutParams(params);
final int margin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, getResources()
.getDisplayMetrics());
TextView v = new TextView(getActivity());
params.setMargins(margin, margin, margin, margin);
v.setLayoutParams(params);
v.setGravity(Gravity.CENTER);
v.setText("PAGE " + (position + 1));
Toast.makeText(getActivity(), position+"", Toast.LENGTH_SHORT).show();
fl.addView(v);
return fl;
}
}
2个布局文件
控件布局1:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout android:paddingLeft="6.0dip"
android:paddingRight="6.0dip"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView android:textSize="@dimen/category_tab_text"
android:textColor="@color/category_tab_text"
android:layout_gravity="center"
android:id="@+id/category_text"
android:paddingLeft="8.0dip"
android:paddingTop="4.0dip"
android:paddingRight="8.0dip"
android:paddingBottom="4.0dip"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
主页面布局2:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/activity_bg_color" >
<RelativeLayout
android:id="@+id/title_bar"
style="@style/main_title_bar_style" >
<FrameLayout
android:id="@+id/top_head_container"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:paddingLeft="10.0dip"
android:paddingRight="10.0dip" >
<ImageView
android:id="@+id/top_head"
android:layout_width="@dimen/head_size"
android:layout_height="@dimen/head_size"
android:layout_gravity="center_vertical"
android:background="@drawable/bg_head"
android:contentDescription="@string/app_name"
android:padding="2.0dip"
android:scaleType="fitXY"
android:src="@drawable/default_round_head" />
</FrameLayout>
<ImageView
android:id="@+id/top_more"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="12.0dip"
android:contentDescription="@string/app_name"
android:gravity="center"
android:scaleType="centerInside"
android:src="@drawable/right_drawer" />
<RelativeLayout
android:id="@+id/title_click_layout"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_centerInParent="true"
android:paddingLeft="13.0dip" >
<FrameLayout
android:id="@+id/title_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true" >
<ImageView
android:id="@+id/title_recent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:contentDescription="@string/app_name"
android:src="@drawable/title" />
</FrameLayout>
<ImageView
android:id="@+id/top_refresh"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/title_parent"
android:contentDescription="@string/app_name"
android:padding="3.0dip"
android:src="@drawable/refreshicon_titlebar" />
</RelativeLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/category_layout"
android:layout_width="fill_parent"
android:layout_height="@dimen/top_category_height"
android:layout_below="@id/title_bar"
android:background="@drawable/bg_category_bar" >
<ImageView
android:id="@+id/icon_category"
android:layout_width="@dimen/top_category_height"
android:layout_height="@dimen/top_category_height"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:contentDescription="@string/app_name"
android:scaleType="center"
android:src="@drawable/ic_category_expand" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="@dimen/top_category_height"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_toLeftOf="@id/icon_category" >
<com.rainsong.toutiaotabdemo.CategoryTabStrip
android:id="@+id/category_strip"
android:layout_width="wrap_content"
android:layout_height="@dimen/top_category_height"
android:clipToPadding="false"
android:paddingLeft="6.0dip"
android:paddingRight="6.0dip" />
</LinearLayout>
</RelativeLayout>
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="@id/category_layout" />
</RelativeLayout>
引入的values有点多:
1.attrs.xml文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="windowActionBar" format="boolean" />
</resources>
2colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="activity_bg_color">#fffafafa</color>
<color name="top_category_bar_background">#ffeeeeee</color>
<color name="divider">#ffdddddd</color>
<color name="category_tab_text">#ff707070</color>
<color name="category_tab_text_dark">#fffafafa</color>
<color name="category_tab_highlight_text">#fffafafa</color>
<color name="category_tab_highlight_text_dark">#ffd43d3d</color>
<color name="category_tab_highlight_bg">#ffd43d3d</color>
<color name="category_tab_highlight_dark_bg">#fffafafa</color>
</resources>
3.dimens.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="activity_bg_color">#fffafafa</color>
<color name="top_category_bar_background">#ffeeeeee</color>
<color name="divider">#ffdddddd</color>
<color name="category_tab_text">#ff707070</color>
<color name="category_tab_text_dark">#fffafafa</color>
<color name="category_tab_highlight_text">#fffafafa</color>
<color name="category_tab_highlight_text_dark">#ffd43d3d</color>
<color name="category_tab_highlight_bg">#ffd43d3d</color>
<color name="category_tab_highlight_dark_bg">#fffafafa</color>
</resources>
4.String s.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">今日头条</string>
<string name="action_settings">Settings</string>
<string name="hello_world">Hello world!</string>
<string name="category_all">推荐</string>
<string name="category_all_my">推荐</string>
<string name="category_society">社会</string>
<string name="category_subscribe">订阅</string>
<string name="category_video">视频</string>
<string name="category_health">健康</string>
<string name="category_sports">体育</string>
<string name="category_tech">科技</string>
<string name="category_car">汽车</string>
<string name="category_entertainment">娱乐</string>
<string name="category_finance">财经</string>
<string name="category_military">军事</string>
<string name="category_world">国际</string>
<string name="category_hot">热点</string>
<string name="category_positive">正能量</string>
<string name="category_essay_joke">段子</string>
<string name="category_image_funny">趣图</string>
<string name="category_image_ppmm">美女</string>
<string name="category_movie">电影</string>
<string name="category_digital">数码</string>
<string name="category_news_fashion">时尚</string>
<string name="category_rumor">辟谣</string>
<string name="category_marvel">奇葩</string>
<string name="category_news_game">游戏</string>
<string name="category_news_travel">旅游</string>
<string name="category_news_baby">育儿</string>
<string name="category_fitness">减肥</string>
<string name="category_news_regimen">养生</string>
<string name="category_news_food">美食</string>
<string name="category_government">政务</string>
<string name="category_news_history">历史</string>
<string name="category_news_discovery">探索</string>
<string name="category_news_story">故事</string>
<string name="category_news_essay">美文</string>
<string name="category_emotion">情感</string>
<string name="category_essay_saying">语录</string>
<string name="category_image_wonderful">美图</string>
<string name="category_news_house">家居</string>
<string name="category_news_home">房产</string>
<string name="category_funny">搞笑</string>
<string name="category_news_astrology">星座</string>
<string name="category_news_culture">文化</string>
<string name="category_graduate">毕业生</string>
</resources>
5.styles.xml
<resources>
<style name="AppBaseTheme" parent="android:Theme.Light">
</style>
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<item name="android:windowNoTitle">true</item>
</style>
<style name="main_title_bar_style">
<item name="android:background">@drawable/bg_titlebar_main</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">@dimen/title_bar_height</item>
</style>
</resources>
添加drawable文件夹,保函不少引入
1.bg_category_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="@color/divider" />
</shape>
</item>
<item android:bottom="0.5dip">
<shape>
<solid android:color="@color/top_category_bar_background" />
</shape>
</item>
</layer-list>
2.bg_category_indicator_dark.xml
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/category_tab_highlight_dark_bg" />
<corners android:radius="4.0dip" />
</shape>
3.bg_category_indicator.xml
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/category_tab_highlight_bg" />
<corners android:radius="4.0dip" />
</shape>
4.bg_head_normal.xml
<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="oval"
xmlns:android="http://schemas.android.com/apk/res/android">
<stroke android:width="1.0px" android:color="#ffa50303" />
<solid android:color="#fffafafa" />
</shape>
5.bg_head_pressed.xml
<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="oval"
xmlns:android="http://schemas.android.com/apk/res/android">
<stroke android:width="2.0px" android:color="#ff530000" />
<solid android:color="#fffafafa" />
</shape>
6.bg_head.xml
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@drawable/bg_head_pressed" />
<item android:drawable="@drawable/bg_head_normal" />
</selector>
7.bg_titlebar_main.xml
<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle"
xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#ffcc3131" />
</shape>
8.ic_category_expand.xml
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@drawable/ic_category_expand_pressed" />
<item android:drawable="@drawable/ic_category_expand_normal" />
</selector>
9.ic_category_left_edge.xml
<?xml version="1.0" encoding="utf-8"?>
<rotate android:visible="true" android:drawable="@drawable/ic_category_right_edge" android:fromDegrees="180.0" android:toDegrees="180.0"
xmlns:android="http://schemas.android.com/apk/res/android" />
10.right_drawer.xml
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@drawable/right_drawer_pressed" />
<item android:drawable="@drawable/right_drawer_normal" />
</selector>
图片有点多啊