Android实现仿网易新闻的顶部导航指示器
我们知道,页面导航器(Navigator)在几乎所有的项目中都会用到,平时大多数时候为了节省时间,都会直接在github上面拿别人的开源项目来用,最近自己在复习自定义View,就尝试封装了一下,源码参考项目PagerSlidingTabStrip
大家先来看一下效果图
基于文字的页面导航器
基于图片的页面导航器
使用方法
主要步骤分为三步
1)在xml文件里面
1 2 3 4 5 6 7 8 9 10 | <com.xujun.viewpagertabindicator.TabPagerIndicator android:id= "@+id/pagerIndicator" android:layout_width= "match_parent" android:layout_height= "50dp" /> <android.support.v4.view.ViewPager android:layout_weight= "1" android:id= "@+id/viewPager" android:layout_width= "match_parent" android:layout_height= "0dp" > </android.support.v4.view.ViewPager> |
2)在代码里面找到相应的控件
1 2 | mPagerIndicator = (TabPagerIndicator) findViewById(R.id.pagerIndicator); mViewPager = (ViewPager) findViewById(R.id.viewPager); |
3)初始化ViewPager的Adapter和将mViewPager和我们的mPagerIndicator绑定
1 2 3 4 | //必须先给ViewPager设置适配器 mViewPager.setAdapter(mPagerAdapter); //接着将mViewPage和我们的mPagerIndicator绑定 mPagerIndicator.setViewPager(mViewPager); |
注意事项,
如果是文字标题导航的,我们只需重写在适配器里面重写getPageTitle这个方法
1 2 3 | public CharSequence getPageTitle(int position) { return titles[position]; } |
如果是图标导航的,我们的适配器需要实现这个借口TabPagerIndicator.IconTabProvider,并重写里面的public int getPageIconResId(int position)这个方法
1 2 3 4 5 6 7 | public class BaseIconAdapter extends FragmentPagerAdapter implements TabPagerIndicator.IconTabProvider { //省略了若干方法,有兴趣可以去看一下例子 @Override public int getPageIconResId(int position) { return resIds[position]; } } |
我们可以通过setIndicatorMode(IndicatorMode indicatorMode)这个方法设置不同的下滑线样式
1 2 | mPagerIndicator.setIndicatorMode(TabPagerIndicator.IndicatorMode.MODE_WEIGHT_EXPAND_NOSAME, true); |
1 2 | mPagerIndicator.setIndicatorMode(TabPagerIndicator.IndicatorMode.MODE_WEIGHT_EXPAND_SAME, true); |
关于下划线的 颜色,字体的颜色与大小的设置,请参照源码设置,这里就不列举了
大家先来看一下源码吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 | 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 < tabCount; i++) { //区分是文字还是Icon的导航 if (pager.getAdapter() instanceof IconTabProvider) { addIconTab(i, ((IconTabProvider) pager.getAdapter()).getPageIconResId(i)); } else { addTextTab(i, pager.getAdapter().getPageTitle(i).toString()); } } updateTabStyles(); //监听视图树,在绘制完毕后调用相关的方法完成初始化工作 getViewTreeObserver().addOnGlobalLayoutListener( new OnGlobalLayoutListener() { @SuppressWarnings( "deprecation" ) @SuppressLint( "NewApi" ) @Override public void onGlobalLayout() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { getViewTreeObserver().removeGlobalOnLayoutListener(this); } else { getViewTreeObserver().removeOnGlobalLayoutListener(this); } currentPosition = pager.getCurrentItem(); scrollToChild(currentPosition, 0); } }); } private void addTextTab( final int position, String title) { TextView tab = new TextView(getContext()); tab.setText(title); tab.setGravity(Gravity.CENTER); tab.setSingleLine(); addTab(position, tab); } private void addIconTab( final int position, int resId) { ImageButton tab = new ImageButton(getContext()); tab.setImageResource(resId); addTab(position, tab); } //添加孩子 private void addTab( final int position, View tab) { tab.setFocusable(true); // 设置监听 tab.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { pager.setCurrentItem(position); } }); // 这里我们下划线的 高度是否与文字的长度保持一致,是通过给孩子设置padding或者margin实现的 // 注意与onDraw里面的逻辑结合起来 if (!isSame) { tab.setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding); wrapTabLayoutParams.setMargins(0, 0, 0, 0); expandedTabLayoutParams.setMargins(0, 0, 0, 0); } else { wrapTabLayoutParams.setMargins(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding); expandedTabLayoutParams.setMargins(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding); } //根据是否可以扩展来设置不同的layoutParams tabsContainer.addView(tab, position, isExpand ? expandedTabLayoutParams : wrapTabLayoutParams); } private void updateTabStyles() { for (int i = 0; i < tabCount; i++) { View v = tabsContainer.getChildAt(i); v.setBackgroundResource(tabBackgroundResId); if (v instanceof TextView) { TextView tab = (TextView) v; tab.setTextSize(TypedValue.COMPLEX_UNIT_PX, tabTextSize); tab.setTypeface(tabTypeface, tabTypefaceStyle); tab.setTextColor(tabTextColor); // setAllCaps() is only available from API 14, so the upper case is made manually // if we are on a pre-ICS-build if (textAllCaps) { if (Build.VERSION.SDK_INT >= 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 < tabCount - 1) { View nextTab = tabsContainer.getChildAt(currentPosition + 1); final float nextTabLeft = nextTab.getLeft(); final float nextTabRight = nextTab.getRight(); lineLeft = (currentPositionOffset * nextTabLeft + (1f - currentPositionOffset) * lineLeft); lineRight = (currentPositionOffset * nextTabRight + (1f - currentPositionOffset) * lineRight); } canvas.drawRect(lineLeft, height - indicatorHeight, lineRight, height, rectPaint); // draw underline rectPaint.setColor(underlineColor); canvas.drawRect(0, height - underlineHeight, tabsContainer.getWidth(), height, rectPaint); // draw divider dividerPaint.setColor(dividerColor); for (int i = 0; i < tabCount - 1; i++) { View tab = tabsContainer.getChildAt(i); if (!isSame) { canvas.drawLine(tab.getRight(), dividerPadding, tab.getRight(), height - dividerPadding, dividerPaint); } else { canvas.drawLine(tab.getRight() + horizontalPadding, dividerPadding, tab.getRight() + horizontalPadding, height - dividerPadding, dividerPaint); } } } 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); } } } public void setIndicatorColor(int indicatorColor) { this.indicatorColor = indicatorColor; invalidate(); } public void setIndicatorColorResource(int resId) { this.indicatorColor = getResources().getColor(resId); invalidate(); } public int getIndicatorColor() { return this.indicatorColor; } public void setIndicatorHeight(int indicatorLineHeightPx) { this.indicatorHeight = indicatorLineHeightPx; invalidate(); } public int getIndicatorHeight() { return indicatorHeight; } public void setUnderlineColor(int underlineColor) { this.underlineColor = underlineColor; invalidate(); } public void setUnderlineColorResource(int resId) { this.underlineColor = getResources().getColor(resId); invalidate(); } public int getUnderlineColor() { return underlineColor; } public void setDividerColor(int dividerColor) { this.dividerColor = dividerColor; invalidate(); } public void setDividerColorResource(int resId) { this.dividerColor = getResources().getColor(resId); invalidate(); } public int getDividerColor() { return dividerColor; } public void setUnderlineHeight(int underlineHeightPx) { this.underlineHeight = underlineHeightPx; invalidate(); } public int getUnderlineHeight() { return underlineHeight; } public void setDividerPadding(int dividerPaddingPx) { this.dividerPadding = dividerPaddingPx; invalidate(); } public int getDividerPadding() { return dividerPadding; } public void setScrollOffset(int scrollOffsetPx) { this.scrollOffset = scrollOffsetPx; invalidate(); } public int getScrollOffset() { return scrollOffset; } public void setExpand(boolean expand) { this.isExpand = expand; requestLayout(); } public boolean getExpand() { return isExpand; } public boolean isTextAllCaps() { return textAllCaps; } public void setAllCaps(boolean textAllCaps) { this.textAllCaps = textAllCaps; } public void setTextSize(int textSizePx) { this.tabTextSize = textSizePx; updateTabStyles(); } public int getTextSize() { return tabTextSize; } public void setTextColor(int textColor) { this.tabTextColor = textColor; updateTabStyles(); } public void setTextColorResource(int resId) { this.tabTextColor = getResources().getColor(resId); updateTabStyles(); } public int getTextColor() { return tabTextColor; } public void setTypeface(Typeface typeface, int style) { this.tabTypeface = typeface; this.tabTypefaceStyle = style; updateTabStyles(); } public void setTabBackground(int resId) { this.tabBackgroundResId = resId; } public int getTabBackground() { return tabBackgroundResId; } public void setTabPaddingLeftRight(int paddingPx) { this.horizontalPadding = paddingPx; updateTabStyles(); } public int getTabPaddingLeftRight() { return horizontalPadding; } @Override public void onRestoreInstanceState(Parcelable state) { SavedState savedState = (SavedState) state; super.onRestoreInstanceState(savedState.getSuperState()); currentPosition = savedState.currentPosition; requestLayout(); } @Override public Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); SavedState savedState = new SavedState(superState); savedState.currentPosition = currentPosition; return savedState; } //用来保存状态 static class SavedState extends BaseSavedState { int currentPosition; public SavedState(Parcelable superState) { super(superState); } private SavedState(Parcel in) { super(in); currentPosition = in.readInt(); } @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); dest.writeInt(currentPosition); } public static final Creator<SavedState> CREATOR = new Creator<SavedState>() { @Override public SavedState createFromParcel(Parcel in) { return new SavedState(in); } @Override public SavedState[] newArray(int size) { return new SavedState[size]; } }; } /** * 定义4种模式 */ public enum IndicatorMode { // 给枚举传入自定义的int值 MODE_WRAP_EXPAND_SAME(1), // 可扩展,导航线跟标题相等 MODE_WRAP_EXPAND_NOSAME(2), // 可扩展,导标不相等 MODE_WEIGHT_EXPAND_SAME(3), // 可扩展,导航线跟标题相等 MODE_WEIGHT_EXPAND_NOSAME(4); // 可扩展,导标不相等 private int value; IndicatorMode(int value) { this.value = value; } public int getValue() { return value; } } } |
思路主要 可以分为以下几个步骤
1)在构造方法里面初始化各种工作,包括一些自定义属性,画笔等等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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联系起来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 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 < tabCount; i++) { //区分是文字还是Icon的导航 if (pager.getAdapter() instanceof IconTabProvider) { addIconTab(i, ((IconTabProvider) pager.getAdapter()).getPageIconResId(i)); } else { addTextTab(i, pager.getAdapter().getPageTitle(i).toString()); } } updateTabStyles(); //监听视图树,在绘制完毕后调用相关的方法完成初始化工作 getViewTreeObserver().addOnGlobalLayoutListener( new OnGlobalLayoutListener() { @SuppressWarnings( "deprecation" ) @SuppressLint( "NewApi" ) @Override public void onGlobalLayout() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { getViewTreeObserver().removeGlobalOnLayoutListener(this); } else { getViewTreeObserver().removeOnGlobalLayoutListener(this); } currentPosition = pager.getCurrentItem(); scrollToChild(currentPosition, 0); } }); } |
3)在 onDraw里面根据不同的 Mode绘制不同的下划线样式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | @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 < tabCount - 1) { View nextTab = tabsContainer.getChildAt(currentPosition + 1); final float nextTabLeft = nextTab.getLeft(); final float nextTabRight = nextTab.getRight(); lineLeft = (currentPositionOffset * nextTabLeft + (1f - currentPositionOffset) * lineLeft); lineRight = (currentPositionOffset * nextTabRight + (1f - currentPositionOffset) * lineRight); } canvas.drawRect(lineLeft, height - indicatorHeight, lineRight, height, rectPaint); // draw underline rectPaint.setColor(underlineColor); canvas.drawRect(0, height - underlineHeight, tabsContainer.getWidth(), height, rectPaint); // draw divider dividerPaint.setColor(dividerColor); for (int i = 0; i < tabCount - 1; i++) { View tab = tabsContainer.getChildAt(i); if (!isSame) { canvas.drawLine(tab.getRight(), dividerPadding, tab.getRight(), height - dividerPadding, dividerPaint); } else { canvas.drawLine(tab.getRight() + horizontalPadding, dividerPadding, tab.getRight() + horizontalPadding, height - dividerPadding, dividerPaint); } } } |
4)在ViewPager滑动的时候,会调用相应的方法来刷新界面,因为前面我们在setViewPager的时候为其添加pageListener监听器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 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实现仿网易新闻的顶部导航指示器,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对phpstudy网站的支持!