
源码下载:Android Navigation TabBar控件实现多彩标签栏
代码:
MainActivity.java
package com.bzu.gxs.meunguide;import android.app.Activity;import android.graphics.Color;import android.support.v4.view.PagerAdapter;import android.support.v4.view.ViewPager;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;import java.util.ArrayList;public class MainActivity extends Activity{@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initUI();}private void initUI() {final ViewPager viewPager = (ViewPager) findViewById(R.id.vp_horizontal_ntb);viewPager.setAdapter(new PagerAdapter() {@Overridepublic int getCount() {return 5;}@Overridepublic boolean isViewFromObject(View view, Object object) {return view.equals(object);}@Overridepublic void destroyItem(final View container,final int position,final Object object) {((ViewPager)container).removeView((View)object);}@Overridepublic Object instantiateItem(final ViewGroup container,final int position) {final View view = LayoutInflater.from(getBaseContext()).inflate(R.layout.activity_item,null,false);final TextView textView = (TextView) view.findViewById(R.id.txt_vp_item_page);textView.setText(String.format("界面 %d",position));container.addView(view);return view;}});//final String[] colors = getResources().getStringArray(R.array.default_preview);final NavigationTabBar navigationTabBar = (NavigationTabBar) findViewById(R.id.ntb_horizontal);final ArrayList<NavigationTabBar.Model> models = new ArrayList<>();models.add(new NavigationTabBar.Model(getResources().getDrawable(R.drawable.ic_first), Color.parseColor(colors[0]),"One"));models.add(new NavigationTabBar.Model(getResources().getDrawable(R.drawable.ic_second),Color.parseColor(colors[1]),"Two"));models.add(new NavigationTabBar.Model(getResources().getDrawable(R.drawable.ic_third),Color.parseColor(colors[2]),"Thirt"));models.add(new NavigationTabBar.Model(getResources().getDrawable(R.drawable.ic_fourth),Color.parseColor(colors[3]),"Fourth"));models.add(new NavigationTabBar.Model(getResources().getDrawable(R.drawable.ic_fifth),Color.parseColor(colors[4]),"Fifth"));navigationTabBar.setModels(models);navigationTabBar.setViewPager(viewPager,2);navigationTabBar.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {@Overridepublic void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {}@Overridepublic void onPageSelected(final int position) {navigationTabBar.getModels().get(position).hideBadge();}@Overridepublic void onPageScrollStateChanged(final int state) {}});navigationTabBar.post(new Runnable() {@Overridepublic void run() {final View bgNavigationTaBar = findViewById(R.id.bg_ntb_horizontal);bgNavigationTaBar.getLayoutParams().height = (int) navigationTabBar.getHeight();}});navigationTabBar.postDelayed(new Runnable() {@Overridepublic void run() {for (int i=0; i<navigationTabBar.getModels().size() ; i++){final NavigationTabBar.Model model = navigationTabBar.getModels().get(i);switch (i){case 0:model.setBadgeTitle("Gxs1");break;case 1:model.setBadgeTitle("Gxs2");break;case 2:model.setBadgeTitle("Gxs3");break;case 3:model.setBadgeTitle("Gxs4");break;case 4:model.setBadgeTitle("Gxs5");break;default:break;}navigationTabBar.postDelayed(new Runnable() {@Overridepublic void run() {model.showBadge();}},i * 100);}}},500);}}NavigationTabBar.javapackage com.bzu.gxs.meunguide;import android.animation.Animator;import android.animation.ValueAnimator;import android.content.Context;import android.content.res.Configuration;import android.content.res.TypedArray;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.PorterDuff;import android.graphics.PorterDuffColorFilter;import android.graphics.PorterDuffXfermode;import android.graphics.Rect;import android.graphics.RectF;import android.graphics.Typeface;import android.graphics.drawable.BitmapDrawable;import android.graphics.drawable.Drawable;import android.os.Parcel;import android.os.Parcelable;import android.support.v4.view.ViewPager;import android.text.TextPaint;import android.text.TextUtils;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.animation.AccelerateDecelerateInterpolator;import android.view.animation.AccelerateInterpolator;import android.view.animation.DecelerateInterpolator;import android.view.animation.Interpolator;import android.view.animation.LinearInterpolator;import android.widget.Scroller;import java.lang.reflect.Field;import java.util.ArrayList;import java.util.List;import java.util.Random;/** * Created by GXS on 2016/5/7. */public class NavigationTabBar extends View implements ViewPager.OnPageChangeListener {// NTP constantsprivate final static String PREVIEW_BADGE = "0";private final static String PREVIEW_TITLE = "Title";private final static int INVALID_INDEX = -1;private final static int DEFAULT_BADGE_ANIMATION_DURATION = 200;private final static int DEFAULT_BADGE_REFRESH_ANIMATION_DURATION = 100;private final static int DEFAULT_ANIMATION_DURATION = 300;private final static int DEFAULT_INACTIVE_COLOR = Color.parseColor("#9f90af");private final static int DEFAULT_ACTIVE_COLOR = Color.WHITE;private final static float MIN_FRACTION = 0.0f;private final static float NON_SCALED_FRACTION = 0.35f;private final static float MAX_FRACTION = 1.0f;private final static int MIN_ALPHA = 0;private final static int MAX_ALPHA = 255;private final static float ACTIVE_ICON_SCALE_BY = 0.3f;private final static float ICON_SIZE_FRACTION = 0.45f;private final static float TITLE_ACTIVE_ICON_SCALE_BY = 0.2f;private final static float TITLE_ICON_SIZE_FRACTION = 0.45f;private final static float TITLE_ACTIVE_SCALE_BY = 0.2f;private final static float TITLE_SIZE_FRACTION = 0.2f;private final static float TITLE_MARGIN_FRACTION = 0.15f;private final static float BADGE_HORIZONTAL_FRACTION = 0.5f;private final static float BADGE_VERTICAL_FRACTION = 0.75f;private final static float BADGE_TITLE_SIZE_FRACTION = 0.85f;private final static int ALL_INDEX = 0;private final static int ACTIVE_INDEX = 1;private final static int LEFT_INDEX = 0;private final static int CENTER_INDEX = 1;private final static int RIGHT_INDEX = 2;private final static int TOP_INDEX = 0;private final static int BOTTOM_INDEX = 1;private final static float LEFT_FRACTION = 0.25f;private final static float CENTER_FRACTION = 0.5f;private final static float RIGHT_FRACTION = 0.75f;private final static Interpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator();private final static Interpolator ACCELERATE_INTERPOLATOR = new AccelerateInterpolator();// NTP and pointer boundsprivate final RectF mBounds = new RectF();private final RectF mPointerBounds = new RectF();// Badge bounds and bg badge boundsprivate final Rect mBadgeBounds = new Rect();private final RectF mBgBadgeBounds = new RectF();// Canvas, where all of other canvas will be mergedprivate Bitmap mBitmap;private Canvas mCanvas;// Canvas with iconsprivate Bitmap mIconsBitmap;private Canvas mIconsCanvas;// Canvas for our rect pointerprivate Bitmap mPointerBitmap;private Canvas mPointerCanvas;// Main paintprivate final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG) {{setDither(true);setStyle(Style.FILL);}};// Pointer paintprivate final Paint mPointerPaint = new Paint(Paint.ANTI_ALIAS_FLAG) {{setDither(true);setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));}};// Icons paintprivate final Paint mIconPaint = new Paint(Paint.ANTI_ALIAS_FLAG) {{setDither(true);}};// Paint for icon mask pointerprivate final Paint mIconPointerPaint = new Paint(Paint.ANTI_ALIAS_FLAG) {{setStyle(Style.FILL);setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));}};// Paint for model titleprivate final Paint mModelTitlePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG) {{setDither(true);setColor(Color.WHITE);setTextAlign(Align.CENTER);}};// Paint for badgeprivate final Paint mBadgePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG) {{setDither(true);setTextAlign(Align.CENTER);setFakeBoldText(true);}};// Variables for animatorprivate final ValueAnimator mAnimator = new ValueAnimator();private final ResizeInterpolator mResizeInterpolator = new ResizeInterpolator();private int mAnimationDuration;// NTP modelsprivate List<Model> mModels = new ArrayList<>();// Variables for ViewPagerprivate ViewPager mViewPager;private ViewPager.OnPageChangeListener mOnPageChangeListener;private int mScrollState;// Tab listenerprivate OnTabBarSelectedIndexListener mOnTabBarSelectedIndexListener;private ValueAnimator.AnimatorListener mAnimatorListener;// Variables for sizesprivate float mModelSize;private int mIconSize;// Corners radius for rect modeprivate float mCornersRadius;// Model title size and marginprivate float mModelTitleSize;private float mTitleMargin;// Model badge title size and marginprivate float mBadgeMargin;private float mBadgeTitleSize;// Model title mode: active ar allprivate TitleMode mTitleMode;// Model badge position: left, center or rightprivate BadgePosition mBadgePosition;// Model badge gravity: top or bottomprivate BadgeGravity mBadgeGravity;// Indexesprivate int mLastIndex = INVALID_INDEX;private int mIndex = INVALID_INDEX;// General fraction valueprivate float mFraction;// Coordinates of pointerprivate float mStartPointerX;private float mEndPointerX;private float mPointerLeftTop;private float mPointerRightBottom;// Detect if model has titleprivate boolean mIsTitled;// Detect if model has badgeprivate boolean mIsBadged;// Detect if model icon scaledprivate boolean mIsScaled;// Detect if model badge have custom typefaceprivate boolean mIsBadgeUseTypeface;// Detect if is bar mode or indicator pager modeprivate boolean mIsViewPagerMode;// Detect whether the horizontal orientationprivate boolean mIsHorizontalOrientation;// Detect if we move from left to rightprivate boolean mIsResizeIn;// Detect if we get action down eventprivate boolean mIsActionDown;// Detect if we get action down event on pointerprivate boolean mIsPointerActionDown;// Detect when we set index from tab bar nor from ViewPagerprivate boolean mIsSetIndexFromTabBar;// Color variablesprivate int mInactiveColor;private int mActiveColor;// Custom typefaceprivate Typeface mTypeface;public NavigationTabBar(final Context context) {this(context, null);}public NavigationTabBar(final Context context, final AttributeSet attrs) {this(context, attrs, 0);}public NavigationTabBar(final Context context, final AttributeSet attrs, final int defStyleAttr) {super(context, attrs, defStyleAttr);//Init NTB// Always drawsetWillNotDraw(false);// More speed!setLayerType(LAYER_TYPE_HARDWARE, null);final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.NavigationTabBar);try {setIsTitled(typedArray.getBoolean(R.styleable.NavigationTabBar_ntb_titled, false));setIsBadged(typedArray.getBoolean(R.styleable.NavigationTabBar_ntb_badged, false));setIsScaled(typedArray.getBoolean(R.styleable.NavigationTabBar_ntb_scaled, true));setIsBadgeUseTypeface(typedArray.getBoolean(R.styleable.NavigationTabBar_ntb_badge_use_typeface, false));setTitleMode(typedArray.getInt(R.styleable.NavigationTabBar_ntb_title_mode, ALL_INDEX));setBadgePosition(typedArray.getInt(R.styleable.NavigationTabBar_ntb_badge_position, RIGHT_INDEX));setBadgeGravity(typedArray.getInt(R.styleable.NavigationTabBar_ntb_badge_gravity, TOP_INDEX));setTypeface(typedArray.getString(R.styleable.NavigationTabBar_ntb_typeface));setInactiveColor(typedArray.getColor(R.styleable.NavigationTabBar_ntb_inactive_color, DEFAULT_INACTIVE_COLOR));setActiveColor(typedArray.getColor(R.styleable.NavigationTabBar_ntb_active_color, DEFAULT_ACTIVE_COLOR));setAnimationDuration(typedArray.getInteger(R.styleable.NavigationTabBar_ntb_animation_duration, DEFAULT_ANIMATION_DURATION));setCornersRadius(typedArray.getDimension(R.styleable.NavigationTabBar_ntb_corners_radius, 0.0f));// Init animatormAnimator.setFloatValues(MIN_FRACTION, MAX_FRACTION);mAnimator.setInterpolator(new LinearInterpolator());mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(final ValueAnimator animation) {updateIndicatorPosition((Float) animation.getAnimatedValue());}});// Set preview modelsif (isInEditMode()) {// Get preview colorsString[] previewColors = null;try {final int previewColorsId = typedArray.getResourceId(R.styleable.NavigationTabBar_ntb_preview_colors, 0);previewColors = previewColorsId == 0 ? null :typedArray.getResources().getStringArray(previewColorsId);} catch (Exception exception) {previewColors = null;exception.printStackTrace();} finally {if (previewColors == null)previewColors = typedArray.getResources().getStringArray(R.array.default_preview);for (String previewColor : previewColors)mModels.add(new Model(null, Color.parseColor(previewColor)));requestLayout();}}} finally {typedArray.recycle();}}public int getAnimationDuration() {return mAnimationDuration;}public void setAnimationDuration(final int animationDuration) {mAnimationDuration = animationDuration;mAnimator.setDuration(mAnimationDuration);resetScroller();}public List<Model> getModels() {return mModels;}public void setModels(final List<Model> models) {//Set update listeners to badge model animationfor (final Model model : models) {model.mBadgeAnimator.removeAllUpdateListeners();model.mBadgeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(final ValueAnimator animation) {model.mBadgeFraction = (float) animation.getAnimatedValue();postInvalidate();}});}mModels.clear();mModels = models;requestLayout();}public boolean isTitled() {return mIsTitled;}public void setIsTitled(final boolean isTitled) {mIsTitled = isTitled;requestLayout();}public boolean isBadged() {return mIsBadged;}public void setIsBadged(final boolean isBadged) {mIsBadged = isBadged;requestLayout();}public boolean isScaled() {return mIsScaled;}public void setIsScaled(final boolean isScaled) {mIsScaled = isScaled;requestLayout();}public boolean isBadgeUseTypeface() {return mIsBadgeUseTypeface;}public void setIsBadgeUseTypeface(final boolean isBadgeUseTypeface) {mIsBadgeUseTypeface = isBadgeUseTypeface;setBadgeTypeface();postInvalidate();}public TitleMode getTitleMode() {return mTitleMode;}private void setTitleMode(final int index) {switch (index) {case ACTIVE_INDEX:setTitleMode(TitleMode.ACTIVE);break;case ALL_INDEX:default:setTitleMode(TitleMode.ALL);}}public void setTitleMode(final TitleMode titleMode) {mTitleMode = titleMode;postInvalidate();}public BadgePosition getBadgePosition() {return mBadgePosition;}private void setBadgePosition(final int index) {switch (index) {case LEFT_INDEX:setBadgePosition(BadgePosition.LEFT);break;case CENTER_INDEX:setBadgePosition(BadgePosition.CENTER);break;case RIGHT_INDEX:default:setBadgePosition(BadgePosition.RIGHT);}}public void setBadgePosition(final BadgePosition badgePosition) {mBadgePosition = badgePosition;postInvalidate();}public BadgeGravity getBadgeGravity() {return mBadgeGravity;}private void setBadgeGravity(final int index) {switch (index) {case BOTTOM_INDEX:setBadgeGravity(BadgeGravity.BOTTOM);break;case TOP_INDEX:default:setBadgeGravity(BadgeGravity.TOP);}}public void setBadgeGravity(final BadgeGravity badgeGravity) {mBadgeGravity = badgeGravity;requestLayout();}public Typeface getTypeface() {return mTypeface;}public void setTypeface(final String typeface) {Typeface tempTypeface;try {tempTypeface = Typeface.createFromAsset(getContext().getAssets(), typeface);} catch (Exception e) {tempTypeface = Typeface.create(Typeface.DEFAULT, Typeface.NORMAL);e.printStackTrace();}setTypeface(tempTypeface);}public void setTypeface(final Typeface typeface) {mTypeface = typeface;mModelTitlePaint.setTypeface(typeface);setBadgeTypeface();postInvalidate();}private void setBadgeTypeface() {mBadgePaint.setTypeface(mIsBadgeUseTypeface ? mTypeface : Typeface.create(Typeface.DEFAULT, Typeface.NORMAL));}public int getActiveColor() {return mActiveColor;}public void setActiveColor(final int activeColor) {mActiveColor = activeColor;mIconPointerPaint.setColor(activeColor);postInvalidate();}public int getInactiveColor() {return mInactiveColor;}public void setInactiveColor(final int inactiveColor) {mInactiveColor = inactiveColor;// Set color filter to wrap icons with inactive colormIconPaint.setColorFilter(new PorterDuffColorFilter(inactiveColor, PorterDuff.Mode.SRC_IN));mModelTitlePaint.setColor(mInactiveColor);postInvalidate();}public float getCornersRadius() {return mCornersRadius;}public void setCornersRadius(final float cornersRadius) {mCornersRadius = cornersRadius;postInvalidate();}public float getBadgeMargin() {return mBadgeMargin;}public float getBarHeight() {return mBounds.height();}public OnTabBarSelectedIndexListener getOnTabBarSelectedIndexListener() {return mOnTabBarSelectedIndexListener;}// Set on tab bar selected index listener where you can trigger action onStart or onEndpublic void setOnTabBarSelectedIndexListener(final OnTabBarSelectedIndexListener onTabBarSelectedIndexListener) {mOnTabBarSelectedIndexListener = onTabBarSelectedIndexListener;if (mAnimatorListener == null)mAnimatorListener = new Animator.AnimatorListener() {@Overridepublic void onAnimationStart(final Animator animation) {if (mOnTabBarSelectedIndexListener != null)mOnTabBarSelectedIndexListener.onStartTabSelected(mModels.get(mIndex), mIndex);}@Overridepublic void onAnimationEnd(final Animator animation) {if (mOnTabBarSelectedIndexListener != null)mOnTabBarSelectedIndexListener.onEndTabSelected(mModels.get(mIndex), mIndex);}@Overridepublic void onAnimationCancel(final Animator animation) {}@Overridepublic void onAnimationRepeat(final Animator animation) {}};mAnimator.removeListener(mAnimatorListener);mAnimator.addListener(mAnimatorListener);}public void setViewPager(final ViewPager viewPager) {// Detect whether ViewPager modeif (viewPager == null) {mIsViewPagerMode = false;return;}if (mViewPager == viewPager) return;if (mViewPager != null) mViewPager.setOnPageChangeListener(null);if (viewPager.getAdapter() == null)throw new IllegalStateException("ViewPager does not provide adapter instance.");mIsViewPagerMode = true;mViewPager = viewPager;mViewPager.addOnPageChangeListener(this);resetScroller();postInvalidate();}public void setViewPager(final ViewPager viewPager, int index) {setViewPager(viewPager);mIndex = index;if (mIsViewPagerMode) mViewPager.setCurrentItem(index, true);postInvalidate();}// Reset scroller and reset scroll duration equals to animation durationprivate void resetScroller() {if (mViewPager == null) return;try {final Field scrollerField = ViewPager.class.getDeclaredField("mScroller");scrollerField.setAccessible(true);final ResizeViewPagerScroller scroller = new ResizeViewPagerScroller(getContext());scrollerField.set(mViewPager, scroller);} catch (Exception e) {e.printStackTrace();}}public void setOnPageChangeListener(final ViewPager.OnPageChangeListener listener) {mOnPageChangeListener = listener;}public int getModelIndex() {return mIndex;}public void setModelIndex(int index) {setModelIndex(index, false);}// Set model index from touch or programmaticallypublic void setModelIndex(int index, boolean force) {if (mAnimator.isRunning()) return;if (mModels.isEmpty()) return;// This check gives us opportunity to have an non selected modelif (mIndex == INVALID_INDEX) force = true;// Detect if last is the sameif (index == mIndex) return;// Snap index to models sizeindex = Math.max(0, Math.min(index, mModels.size() - 1));mIsResizeIn = index < mIndex;mLastIndex = mIndex;mIndex = index;mIsSetIndexFromTabBar = true;if (mIsViewPagerMode) {if (mViewPager == null) throw new IllegalStateException("ViewPager is null.");mViewPager.setCurrentItem(index, true);}// Set startX and endX for animation, where we animate two sides of rect with different interpolationmStartPointerX = mPointerLeftTop;mEndPointerX = mIndex * mModelSize;// If it force, so update immediately, else animate// This happens if we set index onCreate or something like this// You can use force param or call this method in some post()if (force) updateIndicatorPosition(MAX_FRACTION);else mAnimator.start();}private void updateIndicatorPosition(final float fraction) {// Update general fractionmFraction = fraction;// Set the pointer left top side coordinatemPointerLeftTop =mStartPointerX + (mResizeInterpolator.getResizeInterpolation(fraction, mIsResizeIn) *(mEndPointerX - mStartPointerX));// Set the pointer right bottom side coordinatemPointerRightBottom =(mStartPointerX + mModelSize) +(mResizeInterpolator.getResizeInterpolation(fraction, !mIsResizeIn) *(mEndPointerX - mStartPointerX));// Update pointerpostInvalidate();}// Update NTPprivate void notifyDataSetChanged() {postInvalidate();}@Overridepublic boolean onTouchEvent(final MotionEvent event) {// Return if animation is runningif (mAnimator.isRunning()) return true;// If is not idle state, returnif (mScrollState != ViewPager.SCROLL_STATE_IDLE) return true;switch (event.getAction()) {case MotionEvent.ACTION_DOWN:// Action down touchmIsActionDown = true;if (!mIsViewPagerMode) break;// Detect if we touch down on pointer, later to moveif (mIsHorizontalOrientation)mIsPointerActionDown = (int) (event.getX() / mModelSize) == mIndex;elsemIsPointerActionDown = (int) (event.getY() / mModelSize) == mIndex;break;case MotionEvent.ACTION_MOVE:// If pointer touched, so moveif (mIsPointerActionDown) {if (mIsHorizontalOrientation)mViewPager.setCurrentItem((int) (event.getX() / mModelSize), true);elsemViewPager.setCurrentItem((int) (event.getY() / mModelSize), true);break;}if (mIsActionDown) break;case MotionEvent.ACTION_UP:// Press up and set model index relative to current coordinateif (mIsActionDown) {if (mIsHorizontalOrientation) setModelIndex((int) (event.getX() / mModelSize));else setModelIndex((int) (event.getY() / mModelSize));}case MotionEvent.ACTION_CANCEL:case MotionEvent.ACTION_OUTSIDE:default:// Reset action touch variablesmIsPointerActionDown = false;mIsActionDown = false;break;}return true;}@Overrideprotected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);// Get measure sizefinal int width = MeasureSpec.getSize(widthMeasureSpec);final int height = MeasureSpec.getSize(heightMeasureSpec);if (mModels.isEmpty() || width == 0 || height == 0) return;// Detect orientation and calculate icon sizeif (width > height) {mIsHorizontalOrientation = true;// Get smaller sidefloat side = mModelSize > height ? height : mModelSize;if (mIsBadged) side -= side * TITLE_SIZE_FRACTION;mModelSize = (float) width / (float) mModels.size();mIconSize = (int) (side * (mIsTitled ? TITLE_ICON_SIZE_FRACTION : ICON_SIZE_FRACTION));mModelTitleSize = side * TITLE_SIZE_FRACTION;mTitleMargin = side * TITLE_MARGIN_FRACTION;// If is badged mode, so get vars and set paint with default boundsif (mIsBadged) {mBadgeTitleSize = mModelTitleSize * BADGE_TITLE_SIZE_FRACTION;final Rect badgeBounds = new Rect();mBadgePaint.setTextSize(mBadgeTitleSize);mBadgePaint.getTextBounds(PREVIEW_BADGE, 0, 1, badgeBounds);mBadgeMargin = (badgeBounds.height() * 0.5f) +(mBadgeTitleSize * BADGE_HORIZONTAL_FRACTION * BADGE_VERTICAL_FRACTION);}} else {mIsHorizontalOrientation = false;mIsTitled = false;mIsBadged = false;mModelSize = (float) height / (float) mModels.size();mIconSize = (int) ((mModelSize > width ? width : mModelSize) * ICON_SIZE_FRACTION);}// Set bounds for NTBmBounds.set(0.0f, 0.0f, width, height - mBadgeMargin);// Set main bitmapmBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);mCanvas = new Canvas(mBitmap);// Set pointer canvasmPointerBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);mPointerCanvas = new Canvas(mPointerBitmap);// Set icons canvasmIconsBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);mIconsCanvas = new Canvas(mIconsBitmap);// Set scale fraction for iconsfor (Model model : mModels) {final float originalIconSize = model.mIcon.getWidth() > model.mIcon.getHeight() ?model.mIcon.getWidth() : model.mIcon.getHeight();model.mInactiveIconScale = (float) mIconSize / originalIconSize;model.mActiveIconScaleBy = model.mInactiveIconScale *(mIsTitled ? TITLE_ACTIVE_ICON_SCALE_BY : ACTIVE_ICON_SCALE_BY);}// Set start position of pointer for preview or on startif (isInEditMode() || !mIsViewPagerMode) {mIsSetIndexFromTabBar = true;// Set random in preview modeif (isInEditMode()) {mIndex = new Random().nextInt(mModels.size());if (mIsBadged)for (int i = 0; i < mModels.size(); i++) {final Model model = mModels.get(i);if (i == mIndex) {model.mBadgeFraction = MAX_FRACTION;model.showBadge();} else {model.mBadgeFraction = MIN_FRACTION;model.hideBadge();}}}mStartPointerX = mIndex * mModelSize;mEndPointerX = mStartPointerX;updateIndicatorPosition(MAX_FRACTION);}}@Overrideprotected void onDraw(final Canvas canvas) {if (mCanvas == null || mPointerCanvas == null || mIconsCanvas == null) return;// Reset and clear canvasesmCanvas.drawColor(0, PorterDuff.Mode.CLEAR);mPointerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);mIconsCanvas.drawColor(0, PorterDuff.Mode.CLEAR);// Get pointer badge margin for gravityfinal float pointerBadgeMargin = mBadgeGravity == BadgeGravity.TOP ? mBadgeMargin : 0.0f;// Draw our model colorsfor (int i = 0; i < mModels.size(); i++) {mPaint.setColor(mModels.get(i).getColor());if (mIsHorizontalOrientation) {final float left = mModelSize * i;final float right = left + mModelSize;mCanvas.drawRect(left, pointerBadgeMargin, right, mBounds.height() + pointerBadgeMargin, mPaint);} else {final float top = mModelSize * i;final float bottom = top + mModelSize;mCanvas.drawRect(0.0f, top, mBounds.width(), bottom, mPaint);}}// Set bound of pointerif (mIsHorizontalOrientation)mPointerBounds.set(mPointerLeftTop, pointerBadgeMargin,mPointerRightBottom, mBounds.height() + pointerBadgeMargin);else mPointerBounds.set(0.0f, mPointerLeftTop, mBounds.width(), mPointerRightBottom);// Draw pointer for model colorsif (mCornersRadius == 0) mPointerCanvas.drawRect(mPointerBounds, mPaint);else mPointerCanvas.drawRoundRect(mPointerBounds, mCornersRadius, mCornersRadius, mPaint);// Draw pointer into main canvasmCanvas.drawBitmap(mPointerBitmap, 0.0f, 0.0f, mPointerPaint);// Draw model iconsfor (int i = 0; i < mModels.size(); i++) {final Model model = mModels.get(i);// Variables to center our iconsfinal float leftOffset;final float topOffset;final float matrixCenterX;final float matrixCenterY;// Set vars for icon when model with title or withoutfinal float iconMarginTitleHeight = mIconSize + mTitleMargin + mModelTitleSize;final float leftTitleOffset = (mModelSize * i) + (mModelSize * 0.5f);final float topTitleOffset =mBounds.height() - (mBounds.height() - iconMarginTitleHeight) * 0.5f;if (mIsHorizontalOrientation) {leftOffset = (mModelSize * i) + (mModelSize - model.mIcon.getWidth()) * 0.5f;topOffset = (mBounds.height() - model.mIcon.getHeight()) * 0.5f;matrixCenterX = leftOffset + model.mIcon.getWidth() * 0.5f;matrixCenterY = topOffset + model.mIcon.getHeight() * 0.5f +(mIsTitled && mTitleMode == TitleMode.ALL ? mTitleMargin * 0.5f : 0.0f);} else {leftOffset = (mBounds.width() - model.mIcon.getWidth()) * 0.5f;topOffset = (mModelSize * i) + (mModelSize - model.mIcon.getHeight()) * 0.5f;matrixCenterX = leftOffset + model.mIcon.getWidth() * 0.5f;matrixCenterY = topOffset + model.mIcon.getHeight() * 0.5f;}// Title translate positionfinal float titleTranslate = -model.mIcon.getHeight() + topTitleOffset - mTitleMargin * 0.5f;// Translate icon to model centermodel.mIconMatrix.setTranslate(leftOffset,(mIsTitled && mTitleMode == TitleMode.ALL) ? titleTranslate : topOffset);// Get interpolated fraction for left last and current modelsfinal float interpolation = mResizeInterpolator.getResizeInterpolation(mFraction, true);final float lastInterpolation = mResizeInterpolator.getResizeInterpolation(mFraction, false);//final float interpolation =//mIsScaled ? mResizeInterpolator.getResizeInterpolation(mFraction, true);//final float lastInterpolation =//mIsScaled ? mResizeInterpolator.getResizeInterpolation(mFraction, false) ://(MAX_FRACTION - NON_SCALED_FRACTION);// Scale value relative to interpolationfinal float matrixScale = model.mActiveIconScaleBy *(mIsScaled ? interpolation : NON_SCALED_FRACTION);final float matrixLastScale = model.mActiveIconScaleBy *(mIsScaled ? lastInterpolation : (MAX_FRACTION - NON_SCALED_FRACTION));// Get title alpha relative to interpolationfinal int titleAlpha = (int) (MAX_ALPHA * interpolation);final int titleLastAlpha = MAX_ALPHA - (int) (MAX_ALPHA * lastInterpolation);// Get title scale relative to interpolationfinal float titleScale = MAX_FRACTION +((mIsScaled ? interpolation : NON_SCALED_FRACTION) * TITLE_ACTIVE_SCALE_BY);final float titleLastScale = mIsScaled ? (MAX_FRACTION + TITLE_ACTIVE_SCALE_BY) -(lastInterpolation * TITLE_ACTIVE_SCALE_BY) : titleScale;// Check if we handle models from touch on NTP or from ViewPager// There is a strange logic of ViewPager onPageScrolled method, so it isif (mIsSetIndexFromTabBar) {if (mIndex == i)updateCurrentModel(model, leftOffset, topOffset, titleTranslate, interpolation,matrixCenterX, matrixCenterY, matrixScale, titleScale, titleAlpha);else if (mLastIndex == i)updateLastModel(model, leftOffset, topOffset, titleTranslate, lastInterpolation,matrixCenterX, matrixCenterY, matrixLastScale, titleLastScale, titleLastAlpha);elseupdateInactiveModel(model, leftOffset, topOffset, titleScale,matrixScale, matrixCenterX, matrixCenterY);} else {if (i != mIndex && i != mIndex + 1)updateInactiveModel(model, leftOffset, topOffset, titleScale,matrixScale, matrixCenterX, matrixCenterY);else if (i == mIndex + 1)updateCurrentModel(model, leftOffset, topOffset, titleTranslate, interpolation,matrixCenterX, matrixCenterY, matrixScale, titleScale, titleAlpha);else if (i == mIndex)updateLastModel(model, leftOffset, topOffset, titleTranslate, lastInterpolation,matrixCenterX, matrixCenterY, matrixLastScale, titleLastScale, titleLastAlpha);}// Draw model iconmIconsCanvas.drawBitmap(model.mIcon, model.mIconMatrix, mIconPaint);if (mIsTitled)mIconsCanvas.drawText(isInEditMode() ? PREVIEW_TITLE : model.getTitle(),leftTitleOffset, topTitleOffset, mModelTitlePaint);}// Draw pointer with active color to wrap out active iconif (mCornersRadius == 0) mIconsCanvas.drawRect(mPointerBounds, mIconPointerPaint);elsemIconsCanvas.drawRoundRect(mPointerBounds, mCornersRadius, mCornersRadius, mIconPointerPaint);// Draw general bitmapcanvas.drawBitmap(mBitmap, 0.0f, 0.0f, null);// Draw icons bitmap on topcanvas.drawBitmap(mIconsBitmap, 0.0f, pointerBadgeMargin, null);// If is not badged, exitif (!mIsBadged) return;// Model badge margin and offset relative to gravity modefinal float modelBadgeMargin =mBadgeGravity == BadgeGravity.TOP ? mBadgeMargin : mBounds.height();final float modelBadgeOffset =mBadgeGravity == BadgeGravity.TOP ? 0.0f : mBounds.height() - mBadgeMargin;for (int i = 0; i < mModels.size(); i++) {final Model model = mModels.get(i);// Set preview badge titleif (isInEditMode() || TextUtils.isEmpty(model.getBadgeTitle()))model.setBadgeTitle(PREVIEW_BADGE);// Set badge title boundsmBadgePaint.setTextSize(mBadgeTitleSize * model.mBadgeFraction);mBadgePaint.getTextBounds(model.getBadgeTitle(), 0, model.getBadgeTitle().length(), mBadgeBounds);// Get horizontal and vertical padding for bgfinal float horizontalPadding = mBadgeTitleSize * BADGE_HORIZONTAL_FRACTION;final float verticalPadding = horizontalPadding * BADGE_VERTICAL_FRACTION;// Set horizontal badge offsetfinal float badgeBoundsHorizontalOffset =(mModelSize * i) + (mModelSize * mBadgePosition.mPositionFraction);// If is badge title only one char, so create circle else round rectif (model.getBadgeTitle().length() == 1) {final float badgeMargin = mBadgeMargin * model.mBadgeFraction;mBgBadgeBounds.set(badgeBoundsHorizontalOffset - badgeMargin, modelBadgeMargin - badgeMargin,badgeBoundsHorizontalOffset + badgeMargin, modelBadgeMargin + badgeMargin);} elsemBgBadgeBounds.set(badgeBoundsHorizontalOffset - mBadgeBounds.centerX() - horizontalPadding,modelBadgeMargin - (mBadgeMargin * model.mBadgeFraction),badgeBoundsHorizontalOffset + mBadgeBounds.centerX() + horizontalPadding,modelBadgeOffset + (verticalPadding * 2.0f) + mBadgeBounds.height());// Set color and alpha for badge bgif (model.mBadgeFraction == MIN_FRACTION) mBadgePaint.setColor(Color.TRANSPARENT);else mBadgePaint.setColor(mActiveColor);mBadgePaint.setAlpha((int) (MAX_ALPHA * model.mBadgeFraction));// Set corners to round rect for badge bg and drawfinal float cornerRadius = mBgBadgeBounds.height() * 0.5f;canvas.drawRoundRect(mBgBadgeBounds, cornerRadius, cornerRadius, mBadgePaint);// Set color and alpha for badge titleif (model.mBadgeFraction == MIN_FRACTION) mBadgePaint.setColor(Color.TRANSPARENT);else mBadgePaint.setColor(model.getColor());mBadgePaint.setAlpha((int) (MAX_ALPHA * model.mBadgeFraction));// Set badge title center position and draw titlefinal float badgeHalfHeight = mBadgeBounds.height() * 0.5f;float badgeVerticalOffset = (mBgBadgeBounds.height() * 0.5f) + badgeHalfHeight -mBadgeBounds.bottom + modelBadgeOffset;canvas.drawText(model.getBadgeTitle(), badgeBoundsHorizontalOffset, badgeVerticalOffset +mBadgeBounds.height() - (mBadgeBounds.height() * model.mBadgeFraction),mBadgePaint);}}// Method to transform current fraction of NTB and positionprivate void updateCurrentModel(final Model model,final float leftOffset,final float topOffset,final float titleTranslate,final float interpolation,final float matrixCenterX,final float matrixCenterY,final float matrixScale,final float textScale,final int textAlpha) {if (mIsTitled && mTitleMode == TitleMode.ACTIVE)model.mIconMatrix.setTranslate(leftOffset, topOffset - (interpolation * (topOffset - titleTranslate)));model.mIconMatrix.postScale(model.mInactiveIconScale + matrixScale, model.mInactiveIconScale + matrixScale,matrixCenterX, matrixCenterY + (mIsTitled && mTitleMode == TitleMode.ACTIVE ?mTitleMargin * 0.5f * interpolation : 0.0f));mModelTitlePaint.setTextSize(mModelTitleSize * textScale);if (mTitleMode == TitleMode.ACTIVE) mModelTitlePaint.setAlpha(textAlpha);}// Method to transform last fraction of NTB and positionprivate void updateLastModel(final Model model,final float leftOffset,final float topOffset,final float titleTranslate,final float lastInterpolation,final float matrixCenterX,final float matrixCenterY,final float matrixLastScale,final float textLastScale,final int textLastAlpha) {if (mIsTitled && mTitleMode == TitleMode.ACTIVE)model.mIconMatrix.setTranslate(leftOffset, titleTranslate + (lastInterpolation * (topOffset - titleTranslate)));model.mIconMatrix.postScale(model.mInactiveIconScale + model.mActiveIconScaleBy - matrixLastScale,model.mInactiveIconScale + model.mActiveIconScaleBy - matrixLastScale,matrixCenterX, matrixCenterY + (mIsTitled && mTitleMode == TitleMode.ACTIVE ?mTitleMargin * 0.5f - (mTitleMargin * 0.5f * lastInterpolation) : 0.0f));mModelTitlePaint.setTextSize(mModelTitleSize * textLastScale);if (mTitleMode == TitleMode.ACTIVE) mModelTitlePaint.setAlpha(textLastAlpha);}// Method to transform others fraction of NTB and positionprivate void updateInactiveModel(final Model model,final float leftOffset,final float topOffset,final float textScale,final float matrixScale,final float matrixCenterX,final float matrixCenterY) {if (mIsTitled && mTitleMode == TitleMode.ACTIVE)model.mIconMatrix.setTranslate(leftOffset, topOffset);if (mIsScaled)model.mIconMatrix.postScale(model.mInactiveIconScale, model.mInactiveIconScale, matrixCenterX, matrixCenterY);elsemodel.mIconMatrix.postScale(model.mInactiveIconScale + matrixScale, model.mInactiveIconScale + matrixScale,matrixCenterX, matrixCenterY);mModelTitlePaint.setTextSize(mModelTitleSize * (mIsScaled ? 1.0f : textScale));if (mTitleMode == TitleMode.ACTIVE) mModelTitlePaint.setAlpha(MIN_ALPHA);}@Overridepublic void onPageScrolled(int position, float positionOffset, final int positionOffsetPixels) {// If we animate, don`t call thisif (!mIsSetIndexFromTabBar) {mIsResizeIn = position < mIndex;mLastIndex = mIndex;mIndex = position;mStartPointerX = position * mModelSize;mEndPointerX = mStartPointerX + mModelSize;updateIndicatorPosition(positionOffset);}if (mOnPageChangeListener != null)mOnPageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels);}@Overridepublic void onPageSelected(final int position) {// If VP idle, so updateif (mScrollState == ViewPager.SCROLL_STATE_IDLE) {mIsResizeIn = position < mIndex;mLastIndex = mIndex;mIndex = position;postInvalidate();}}@Overridepublic void onPageScrollStateChanged(final int state) {// If VP idle, reset to MIN_FRACTIONif (state == ViewPager.SCROLL_STATE_IDLE) {mFraction = MIN_FRACTION;mIsSetIndexFromTabBar = false;if (mOnPageChangeListener != null) mOnPageChangeListener.onPageSelected(mIndex);else {if (mOnTabBarSelectedIndexListener != null)mOnTabBarSelectedIndexListener.onEndTabSelected(mModels.get(mIndex), mIndex);}}mScrollState = state;if (mOnPageChangeListener != null) mOnPageChangeListener.onPageScrollStateChanged(state);}@Overridepublic void onRestoreInstanceState(Parcelable state) {final SavedState savedState = (SavedState) state;super.onRestoreInstanceState(savedState.getSuperState());mIndex = savedState.index;requestLayout();}@Overridepublic Parcelable onSaveInstanceState() {final Parcelable superState = super.onSaveInstanceState();final SavedState savedState = new SavedState(superState);savedState.index = mIndex;return savedState;}private static class SavedState extends BaseSavedState {int index;public SavedState(Parcelable superState) {super(superState);}private SavedState(Parcel in) {super(in);index = in.readInt();}@Overridepublic void writeToParcel(Parcel dest, int flags) {super.writeToParcel(dest, flags);dest.writeInt(index);}@SuppressWarnings("UnusedDeclaration")public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {@Overridepublic SavedState createFromParcel(Parcel in) {return new SavedState(in);}@Overridepublic SavedState[] newArray(int size) {return new SavedState[size];}};}@Overrideprotected void onConfigurationChanged(final Configuration newConfig) {// Config view on rotate etc.super.onConfigurationChanged(newConfig);requestLayout();// Refresh pointer and state after config changed to currentfinal int tempIndex = mIndex;setModelIndex(INVALID_INDEX, true);post(new Runnable() {@Overridepublic void run() {setModelIndex(tempIndex, true);}});}// Model classpublic static class Model {private String mTitle = "";private int mColor;private Bitmap mIcon;private final Matrix mIconMatrix = new Matrix();private String mBadgeTitle = "";private String mTempBadgeTitle = "";private float mBadgeFraction;private boolean mIsBadgeShowed;private boolean mIsBadgeUpdated;private final ValueAnimator mBadgeAnimator = new ValueAnimator();private float mInactiveIconScale;private float mActiveIconScaleBy;public Model(final Drawable icon, final int color) {mColor = color;if (icon != null) {if (icon instanceof BitmapDrawable) mIcon = ((BitmapDrawable) icon).getBitmap();else {mIcon = Bitmap.createBitmap(icon.getIntrinsicWidth(),icon.getIntrinsicHeight(),Bitmap.Config.ARGB_8888);final Canvas canvas = new Canvas(mIcon);icon.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());icon.draw(canvas);}} else {mIcon = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565);}mBadgeAnimator.addListener(new Animator.AnimatorListener() {@Overridepublic void onAnimationStart(final Animator animation) {}@Overridepublic void onAnimationEnd(final Animator animation) {// Detect whether we just update text and don`t reset show stateif (!mIsBadgeUpdated) mIsBadgeShowed = !mIsBadgeShowed;else mIsBadgeUpdated = false;}@Overridepublic void onAnimationCancel(final Animator animation) {}@Overridepublic void onAnimationRepeat(final Animator animation) {// Change title when we update and don`t see the titleif (mIsBadgeUpdated) mBadgeTitle = mTempBadgeTitle;}});}public Model(final Drawable icon, final int color, final String title) {this(icon, color);mTitle = title;}public Model(final Drawable icon, final int color, final String title, final String badgeTitle) {this(icon, color, title);mBadgeTitle = badgeTitle;}public String getTitle() {return mTitle;}public void setTitle(final String title) {mTitle = title;}public int getColor() {return mColor;}public void setColor(final int color) {mColor = color;}public boolean isBadgeShowed() {return mIsBadgeShowed;}public String getBadgeTitle() {return mBadgeTitle;}public void setBadgeTitle(final String badgeTitle) {mBadgeTitle = badgeTitle;}// If your badge is visible on screen, so you can update title with animationpublic void updateBadgeTitle(final String badgeTitle) {if (!mIsBadgeShowed) return;if (mBadgeAnimator.isRunning()) mBadgeAnimator.end();mTempBadgeTitle = badgeTitle;mIsBadgeUpdated = true;mBadgeAnimator.setFloatValues(MAX_FRACTION, MIN_FRACTION);mBadgeAnimator.setDuration(DEFAULT_BADGE_REFRESH_ANIMATION_DURATION);mBadgeAnimator.setRepeatMode(ValueAnimator.REVERSE);mBadgeAnimator.setRepeatCount(1);mBadgeAnimator.start();}public void toggleBadge() {if (mBadgeAnimator.isRunning()) mBadgeAnimator.end();if (mIsBadgeShowed) hideBadge();else showBadge();}public void showBadge() {mIsBadgeUpdated = false;if (mBadgeAnimator.isRunning()) mBadgeAnimator.end();if (mIsBadgeShowed) return;mBadgeAnimator.setFloatValues(MIN_FRACTION, MAX_FRACTION);mBadgeAnimator.setInterpolator(DECELERATE_INTERPOLATOR);mBadgeAnimator.setDuration(DEFAULT_BADGE_ANIMATION_DURATION);mBadgeAnimator.setRepeatMode(ValueAnimator.RESTART);mBadgeAnimator.setRepeatCount(0);mBadgeAnimator.start();}public void hideBadge() {mIsBadgeUpdated = false;if (mBadgeAnimator.isRunning()) mBadgeAnimator.end();if (!mIsBadgeShowed) return;mBadgeAnimator.setFloatValues(MAX_FRACTION, MIN_FRACTION);mBadgeAnimator.setInterpolator(ACCELERATE_INTERPOLATOR);mBadgeAnimator.setDuration(DEFAULT_BADGE_ANIMATION_DURATION);mBadgeAnimator.setRepeatMode(ValueAnimator.RESTART);mBadgeAnimator.setRepeatCount(0);mBadgeAnimator.start();}}// Custom scroller with custom scroll durationprivate class ResizeViewPagerScroller extends Scroller {public ResizeViewPagerScroller(Context context) {super(context, new AccelerateDecelerateInterpolator());}@Overridepublic void startScroll(int startX, int startY, int dx, int dy, int duration) {super.startScroll(startX, startY, dx, dy, mAnimationDuration);}@Overridepublic void startScroll(int startX, int startY, int dx, int dy) {super.startScroll(startX, startY, dx, dy, mAnimationDuration);}}// Resize interpolator to create smooth effect on pointer according to inspiration design// This is like improved accelerated and decelerated interpolatorprivate class ResizeInterpolator implements Interpolator {// Spring factorprivate final float mFactor = 1.0f;// Check whether side we moveprivate boolean mResizeIn;@Overridepublic float getInterpolation(final float input) {if (mResizeIn) return (float) (1.0f - Math.pow((1.0f - input), 2.0f * mFactor));else return (float) (Math.pow(input, 2.0f * mFactor));}public float getResizeInterpolation(final float input, final boolean resizeIn) {mResizeIn = resizeIn;return getInterpolation(input);}}// Model title modepublic enum TitleMode {ALL, ACTIVE}// Model badge positionpublic enum BadgePosition {LEFT(LEFT_FRACTION), CENTER(CENTER_FRACTION), RIGHT(RIGHT_FRACTION);private float mPositionFraction;BadgePosition() {mPositionFraction = RIGHT_FRACTION;}BadgePosition(final float positionFraction) {mPositionFraction = positionFraction;}}// Model badge gravitypublic enum BadgeGravity {TOP, BOTTOM}// Out listener for selected indexpublic interface OnTabBarSelectedIndexListener {void onStartTabSelected(final Model model, final int index);void onEndTabSelected(final Model model, final int index);}}布局:<?xml version="1.0" encoding="utf-8"?><RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><android.support.v4.view.ViewPagerandroid:id="@+id/vp_horizontal_ntb"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_above="@+id/wrapper_ntb_horizontal"/><FrameLayoutandroid:id="@+id/wrapper_ntb_horizontal"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"><Viewandroid:id="@+id/bg_ntb_horizontal"android:layout_width="match_parent"android:layout_height="52dp"android:layout_gravity="bottom"android:background="#605271"/><com.bzu.gxs.meunguide.NavigationTabBarandroid:id="@+id/ntb_horizontal"android:layout_width="match_parent"android:layout_height="60dp"android:layout_gravity="center"android:background="@drawable/bg_round_circle"app:ntb_animation_duration="400"app:ntb_preview_colors="@array/red_wine"app:ntb_corners_radius="50dp"app:ntb_scaled="false"app:ntb_active_color="#8d88e4"app:ntb_inactive_color="#dddfec"/></FrameLayout></RelativeLayout>activity_item.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:weightSum="4"><TextViewandroid:id="@+id/txt_vp_item_page"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_margin="10dp"android:background="@drawable/bg_round_rect"android:gravity="center"android:text="Page"android:textColor="#9b92b3"android:textStyle="bold"/></LinearLayout>以上就是本文的全部内容,希望能给大家一个参考,也希望大家多多支持脚本之家。