热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

Android实现仿网易新闻的顶部导航指示器

这篇文章主要介绍了Android实现仿网易新闻的顶部导航指示器的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下

我们知道,页面导航器(Navigator)在几乎所有的项目中都会用到,平时大多数时候为了节省时间,都会直接在github上面拿别人的开源项目来用,最近自己在复习自定义View,就尝试封装了一下,源码参考项目PagerSlidingTabStrip

大家先来看一下效果图

基于文字的页面导航器

基于图片的页面导航器

使用方法

主要步骤分为三步

1)在xml文件里面



2)在代码里面找到相应的控件

mPagerIndicator = (TabPagerIndicator) findViewById(R.id.pagerIndicator);
mViewPager = (ViewPager) findViewById(R.id.viewPager);

3)初始化ViewPager的Adapter和将mViewPager和我们的mPagerIndicator绑定

//必须先给ViewPager设置适配器
mViewPager.setAdapter(mPagerAdapter);
//接着将mViewPage和我们的mPagerIndicator绑定
mPagerIndicator.setViewPager(mViewPager);

注意事项,

如果是文字标题导航的,我们只需重写在适配器里面重写getPageTitle这个方法

public CharSequence getPageTitle(int position) {
return titles[position];
}

如果是图标导航的,我们的适配器需要实现这个借口TabPagerIndicator.IconTabProvider,并重写里面的public int getPageIconResId(int position)这个方法

public class BaseIconAdapter extends FragmentPagerAdapter implements TabPagerIndicator.IconTabProvider {
//省略了若干方法,有兴趣可以去看一下例子
@Override
public int getPageIconResId(int position) {
return resIds[position];
}
}

我们可以通过setIndicatorMode(IndicatorMode indicatorMode)这个方法设置不同的下滑线样式

mPagerIndicator.setIndicatorMode(TabPagerIndicator.IndicatorMode.MODE_WEIGHT_EXPAND_NOSAME,
true);


mPagerIndicator.setIndicatorMode(TabPagerIndicator.IndicatorMode.MODE_WEIGHT_EXPAND_SAME,
true);

关于下划线的 颜色,字体的颜色与大小的设置,请参照源码设置,这里就不列举了

大家先来看一下源码吧

public class TabPagerIndicator extends HorizontalScrollView {
public interface IconTabProvider {
int getPageIconResId(int position);
}
// @formatter:off
private static final int[] ATTRS = new int[]{
android.R.attr.textSize,
android.R.attr.textColor
};
// @formatter:on
private LinearLayout.LayoutParams wrapTabLayoutParams;
private LinearLayout.LayoutParams expandedTabLayoutParams;
private final PageListener pageListener = new PageListener();
public OnPageChangeListener delegatePageListener;
private LinearLayout tabsContainer;
private ViewPager pager;
private int tabCount;
private static final String TAG = "xujun";
private int currentPosition = 0;
private float currentPositiOnOffset= 0f;
private Paint rectPaint;
private Paint dividerPaint;
private int indicatorColor = 0xFF666666;
private int underlineColor = 0x1A000000;
private int dividerColor = 0x1A000000;
//表示是否扩展
private boolean isExpand = false;
//表示下滑线的长度是否与标题字体的长度一样
private boolean isSame = false;
private boolean textAllCaps = true;
private int scrollOffset = 52;
private int indicatorHeight = 8;
private int underlineHeight = 2;
private int dividerPadding = 12;
//表示自己之间的间隔
private int horizOntalPadding= 24;
private int verticalPadding = 10;
private int dividerWidth = 1;
private int tabTextSize = 12;
private int tabTextColor = 0xFF666666;
private Typeface tabTypeface = null;
private int tabTypefaceStyle = Typeface.BOLD;
private int lastScrollX = -1;
private int tabBackgroundResId = R.drawable.background_tab;
//Indicator的样式
private IndicatorMode curMode = IndicatorMode.MODE_WRAP_EXPAND_SAME;
private Locale locale;
public TabPagerIndicator(Context context) {
this(context, null);
}
public TabPagerIndicator(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TabPagerIndicator(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setFillViewport(true);
setWillNotDraw(false);
tabsCOntainer= new LinearLayout(context);
tabsContainer.setOrientation(LinearLayout.HORIZONTAL);
tabsContainer.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT));
addView(tabsContainer);
//根据IndicatorMode初始化各个变量
setIndicatorMode(curMode);
//初始化自定义属性
obtainAttrs(context, attrs);
rectPaint = new Paint();
rectPaint.setAntiAlias(true);
rectPaint.setStyle(Style.FILL);
dividerPaint = new Paint();
dividerPaint.setAntiAlias(true);
dividerPaint.setStrokeWidth(dividerWidth);
wrapTabLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.MATCH_PARENT);
expandedTabLayoutParams = new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f);
if (locale == null) {
locale = getResources().getConfiguration().locale;
}
}
public void setIndicatorMode(IndicatorMode indicatorMode) {
this.setIndicatorMode(indicatorMode, false);
}
public void setIndicatorMode(IndicatorMode indicatorMode, boolean isNotify) {
switch (indicatorMode) {
case MODE_WRAP_EXPAND_SAME:
isExpand = false;
isSame = true;
break;
case MODE_WRAP_EXPAND_NOSAME:
isExpand = false;
isSame = false;
break;
case MODE_WEIGHT_EXPAND_NOSAME:
isExpand = true;
isSame = false;
break;
case MODE_WEIGHT_EXPAND_SAME:
isExpand = true;
isSame = true;
break;
}
this.curMode = indicatorMode;
if (isNotify) {
notifyDataSetChanged();
}
}
private void obtainAttrs(Context context, AttributeSet attrs) {
DisplayMetrics dm = getResources().getDisplayMetrics();
scrollOffset = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, scrollOffset,
dm);
indicatorHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
indicatorHeight, dm);
underlineHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
underlineHeight, dm);
dividerPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dividerPadding, dm);
horizOntalPadding= (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
horizontalPadding, dm);
dividerWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dividerWidth,
dm);
tabTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, tabTextSize, dm);
// get system attrs (android:textSize and android:textColor)
TypedArray a = context.obtainStyledAttributes(attrs, ATTRS);
tabTextSize = a.getDimensionPixelSize(0, tabTextSize);
tabTextColor = a.getColor(1, tabTextColor);
a.recycle();
// get custom attrs
a = context.obtainStyledAttributes(attrs, R.styleable.TabPagerIndicator);
indicatorColor = a.getColor(R.styleable.TabPagerIndicator_pstsIndicatorColor,
indicatorColor);
underlineColor = a.getColor(R.styleable.TabPagerIndicator_pstsUnderlineColor,
underlineColor);
dividerColor = a.getColor(R.styleable.TabPagerIndicator_pstsDividerColor, dividerColor);
indicatorHeight = a.getDimensionPixelSize(R.styleable
.TabPagerIndicator_pstsIndicatorHeight, indicatorHeight);
underlineHeight = a.getDimensionPixelSize(R.styleable
.TabPagerIndicator_pstsUnderlineHeight, underlineHeight);
dividerPadding = a.getDimensionPixelSize(R.styleable
.TabPagerIndicator_pstsDividerPadding, dividerPadding);
horizOntalPadding= a.getDimensionPixelSize(R.styleable
.TabPagerIndicator_pstsTabPaddingLeftRight, horizontalPadding);
tabBackgroundResId = a.getResourceId(R.styleable.TabPagerIndicator_pstsTabBackground,
tabBackgroundResId);
isExpand = a.getBoolean(R.styleable.TabPagerIndicator_pstsShouldExpand,
isExpand);
scrollOffset = a.getDimensionPixelSize(R.styleable.TabPagerIndicator_pstsScrollOffset,
scrollOffset);
textAllCaps = a.getBoolean(R.styleable.TabPagerIndicator_pstsTextAllCaps, textAllCaps);
a.recycle();
}
public void setViewPager(ViewPager pager) {
this.pager = pager;
if (pager.getAdapter() == null) {
throw new IllegalStateException("ViewPager does not have adapter instance.");
}
pager.addOnPageChangeListener(pageListener);
notifyDataSetChanged();
}
public void addOnPageChangeListener(OnPageChangeListener listener) {
this.delegatePageListener = listener;
}
public void notifyDataSetChanged() {
//先移除掉所有的View ,防止重复添加
tabsContainer.removeAllViews();
tabCount = pager.getAdapter().getCount();
for (int i = 0; i = Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
tab.setAllCaps(true);
} else {
tab.setText(tab.getText().toString().toUpperCase(locale));
}
}
}
}
}
// 调用这个方法是HorizontalScrollView滑动到相应的位置
private void scrollToChild(int position, int offset) {
if (tabCount == 0) {
return;
}
int newScrollX;
View child = tabsContainer.getChildAt(position);
int left = child.getLeft();
if (isSame) {
newScrollX = left + offset - horizontalPadding;
} else {
newScrollX = left + offset;
}
if (position > 0 || offset > 0) {
newScrollX -= scrollOffset;
}
Log.i(TAG, "scrollToChild:newScrollX=" + newScrollX);
if (newScrollX != lastScrollX) {
lastScrollX = newScrollX;
scrollTo(newScrollX, 0);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isInEditMode() || tabCount == 0) {
return;
}
final int height = getHeight();
// draw indicator line
rectPaint.setColor(indicatorColor);
// default: line below current tab
View currentTab = tabsContainer.getChildAt(currentPosition);
float lineLeft = currentTab.getLeft();
float lineRight = currentTab.getRight();
// if there is an offset, start interpolating left and right coordinates between current
// and next tab
if (currentPositionOffset > 0f && currentPosition 
public TabPagerIndicator(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
//初始化各种工作
//根据IndicatorMode初始化各个变量
setIndicatorMode(curMode);
//初始化自定义属性
obtainAttrs(context, attrs);
rectPaint = new Paint();
rectPaint.setAntiAlias(true);
rectPaint.setStyle(Style.FILL);
dividerPaint = new Paint();
dividerPaint.setAntiAlias(true);
dividerPaint.setStrokeWidth(dividerWidth);
if (locale == null) {
locale = getResources().getConfiguration().locale;
}
}

2)通过setViewPager()这个方法将控件与ViewPager联系起来

public void setViewPager(ViewPager pager) {
this.pager = pager;
if (pager.getAdapter() == null) {
throw new IllegalStateException("ViewPager does not have adapter instance.");
}
pager.addOnPageChangeListener(pageListener);
notifyDataSetChanged();
}
public void notifyDataSetChanged() {
//先移除掉所有的View ,防止重复添加
tabsContainer.removeAllViews();
tabCount = pager.getAdapter().getCount();
for (int i = 0; i 

3)在 onDraw里面根据不同的 Mode绘制不同的下划线样式

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isInEditMode() || tabCount == 0) {
return;
}
final int height = getHeight();
// draw indicator line
rectPaint.setColor(indicatorColor);
// default: line below current tab
View currentTab = tabsContainer.getChildAt(currentPosition);
float lineLeft = currentTab.getLeft();
float lineRight = currentTab.getRight();
// if there is an offset, start interpolating left and right coordinates between current
// and next tab
if (currentPositionOffset > 0f && currentPosition 

4)在ViewPager滑动的时候,会调用相应的方法来刷新界面,因为前面我们在setViewPager的时候为其添加pageListener监听器

public void setViewPager(ViewPager pager) {
//省略了若干方法 
pager.addOnPageChangeListener(pageListener);
}
private class PageListener implements OnPageChangeListener {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
currentPosition = position;
currentPositiOnOffset= positionOffset;
View child = tabsContainer.getChildAt(position);
int width = child.getWidth();
if (isSame) {
width += horizontalPadding * 2;
}
Log.i(TAG, "onPageScrolled:width=" + width);
// 调用这个方法是HorizontalScrollView滑动到相应的位置
scrollToChild(position, (int) (positionOffset * width));
//调用这个方法重新绘制
invalidate();
if (delegatePageListener != null) {
delegatePageListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
}
@Override
public void onPageScrollStateChanged(int state) {
if (delegatePageListener != null) {
delegatePageListener.onPageScrollStateChanged(state);
}
}
@Override
public void onPageSelected(int position) {
if (delegatePageListener != null) {
delegatePageListener.onPageSelected(position);
}
}
}

以上所述是小编给大家介绍的Android实现仿网易新闻的顶部导航指示器,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!


推荐阅读
author-avatar
董雪高
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有