今天给大家带来一个自定义的底部导航,我不会做动图,只能搞一张图片给大家看看,大家见谅
这个就是自定义的tablayout底部搞好的样式了
首先我们需要创建一个类或者是模块都可以
package com.example.map.tab;
import android.content.Context;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentTabHost;
import com.example.map.R;
import java.util.ArrayList;
import java.util.List;
public class XFragmentTabHost extends FragmentTabHost {
private Context mContext;
private List mTabViews;
private List mTabItems;
// 字体激活颜色
private int mTextActiveColor;
private int mTextInactiveColor;
// 字体激活大小
private float mTextActiveSize;
private float mTextInactiveSize;
// 视图激活对顶部的偏移
private int mViewActivePaddingTop;
private int mViewInactivePaddingTop;
// 波纹模式的前景颜色和后景颜色
private int mFrontColor;
private int mBehindColor;
// TabHost模式
private TabMode mTabMode;
public XFragmentTabHost(Context context) {
super(context);
_init(context);
}
public XFragmentTabHost(Context context, AttributeSet attrs) {
super(context, attrs);
_init(context);
}
private void _init(Context context) {
mTabViews = new ArrayList<>();
mTabItems = new ArrayList<>();
mContext = context;
mTextActiveColor = ContextCompat.getColor(mContext, R.color.colorActive);
mTextInactiveColor = ContextCompat.getColor(mContext, R.color.colorInactive);
mFrontColor = ContextCompat.getColor(mContext, R.color.colorFront);
mBehindColor = ContextCompat.getColor(mContext, R.color.colorBehind);
mTextActiveSize = getResources().getDimension(R.dimen.tab_text_size_active);
mTextInactiveSize = getResources().getDimension(R.dimen.tab_text_size_inactive);
mViewActivePaddingTop = (int) getResources().getDimension(R.dimen.tab_padding_top_active);
mViewInactivePaddingTop = (int) getResources().getDimension(R.dimen.tab_padding_top_inactive);
mTabMode = TabMode.MoveToTop;
}
@Override
public void setCurrentTab(int index) {
// 获取之前选中的index
int lastIndex = getCurrentTab();
super.setCurrentTab(index);
// 选中不同的Tab项才做切换处理
if (lastIndex != index) {
_switchTab(lastIndex, index);
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
// 部分机型TabHost带有分割线,同一将分割线设为透明
getTabWidget().setDividerDrawable(android.R.color.transparent);
}
public void addTabItem(TabItem item, Class> fragClass, Bundle bundle) {
mTabItems.add(item);
View view = _getIndicator(item);
mTabViews.add(view);
this.addTab(newTabSpec(item.getTitle()).setIndicator(view), fragClass, bundle);
}
private View _getIndicator(TabItem item) {
View view = LayoutInflater.from(mContext).inflate(R.layout.tab_indicator, null);
ImageView imageView = (ImageView) view.findViewById(R.id.tab_icon);
TextView title = (TextView) view.findViewById(R.id.tab_title);
imageView.setImageResource(item.getImageRes());
title.setText(item.getTitle());
title.setTextColor(mTextInactiveColor);
return view;
}
private void _switchTab(int lastIndex, int nextIndex) {
for (int i = 0; i < mTabViews.size(); i++) {
if (i == lastIndex) {
_switchView(i, false);
} else if (i == nextIndex) {
_switchView(i, true);
}
}
}
private void _switchView(int index, boolean isActivated) {
switch (mTabMode) {
case MoveToTop:
_doMoveToTop(index, isActivated);
break;
case ClipDrawable:
_doClipDrawable(index, isActivated);
break;
case Ripple:
_doRipple(index, isActivated);
break;
}
}
private void _doClipDrawable(int index, boolean isActivated) {
View view = mTabViews.get(index);
View tabView = view.findViewById(R.id.tab_layout);
if (isActivated) {
TabAnimHelper.clipDrawable(tabView, mTabItems.get(index).getDrawable(), true);
} else {
TabAnimHelper.clipDrawable(tabView, mTabItems.get(index).getDrawable(), false);
}
}
private void _doRipple(int index, boolean isActivated) {
View view = mTabViews.get(index);
View tabView = view.findViewById(R.id.tab_layout);
TextView title = (TextView) view.findViewById(R.id.tab_title);
if (index == 0) {
TabAnimHelper.rippleDrawable(tabView, mFrontColor, mBehindColor, RippleDrawable.MODE_LEFT, isActivated);
} else if (index == (mTabViews.size() - 1)){
TabAnimHelper.rippleDrawable(tabView, mFrontColor, mBehindColor, RippleDrawable.MODE_RIGHT, isActivated);
} else {
TabAnimHelper.rippleDrawable(tabView, mFrontColor, mBehindColor, RippleDrawable.MODE_MIDDLE, isActivated);
}
if (isActivated) {
title.setTextColor(mTextActiveColor);
} else {
title.setTextColor(mTextInactiveColor);
}
}
private void _doMoveToTop(int index, boolean isActivated) {
View view = mTabViews.get(index);
TextView title = (TextView) view.findViewById(R.id.tab_title);
ImageView icon = (ImageView) view.findViewById(R.id.tab_icon);
if (isActivated) {
TabAnimHelper.changeTextColor(title, mTextInactiveColor, mTextActiveColor);
TabAnimHelper.changeTextSize(title, mTextInactiveSize, mTextActiveSize);
TabAnimHelper.changeTopPadding(view, mViewInactivePaddingTop, mViewActivePaddingTop);
TabAnimHelper.changeImageSize(icon, 1.0f, 1.1f);
} else {
TabAnimHelper.changeTextColor(title, mTextActiveColor, mTextInactiveColor);
TabAnimHelper.changeTextSize(title, mTextActiveSize, mTextInactiveSize);
TabAnimHelper.changeTopPadding(view, mViewActivePaddingTop, mViewInactivePaddingTop);
TabAnimHelper.changeImageSize(icon, 1.1f, 1.0f);
}
}
public int getTextActiveColor() {
return mTextActiveColor;
}
public void setTextActiveColor(int textActiveColor) {
mTextActiveColor = textActiveColor;
}
public int getTextInactiveColor() {
return mTextInactiveColor;
}
public void setTextInactiveColor(int textInactiveColor) {
mTextInactiveColor = textInactiveColor;
}
public int getFrontColor() {
return mFrontColor;
}
public void setFrontColor(int frontColor) {
mFrontColor = frontColor;
}
public int getBehindColor() {
return mBehindColor;
}
public void setBehindColor(int behindColor) {
mBehindColor = behindColor;
}
public TabMode getTabMode() {
return mTabMode;
}
public void setTabMode(TabMode tabMode) {
mTabMode = tabMode;
}
public enum TabMode {
MoveToTop(1),
Ripple(2),
ClipDrawable(3);
private int tabMode;
TabMode(int tabMode) {
this.tabMode = tabMode;
}
public int getTabMode() {
return tabMode;
}
}
}
然后在res下的value中的color中加入以下颜色
#3F51B5 #303F9F #FF4081 #000000 #FFFFFF #FBD794 #00000000 #70000000 #99ffffff #efefef #333333 #999999 #cccccc #66333333 #111111 #666666 #eeeeee #ff6700 #cccccc #f6f6f6 #a8a8a8 #dc5900 #171717 #cccccc #333333 #338BFF #f94244 #45cdd5 #5e8cef #4980f6 #c1e4ff #eff4f8 #e5e5e5 #f6f6f6 #FF0000 #FF6666 #e6fffe #00e8df #ffefe5 #e6fff2 #01e48c #ffeeee #ff1901 #fff4ea #ffa96e #ff8430 #ff9d5c #ff802c #f2c279 #fcf1ea #fed2c0 #ffece5 #68ffc4 #31c088 #587ed6ff #7ed6ff #75fff7 #2d9ef5 #181819 #00a6b6 #282e35 #60000000 #b0000000 #c0ffff00 #ffffffff #ffc0c0c0 #c000ff00 #fed952 #eb2127 #ff4200 #f03030 #f8f8f8 #daba7f #858585 #b2b2b2 #58ffc8d1 #ff6e6b #97a8bc #143660 #44db09 #757575 #f5f5f5 #767676 #d1d1d1 #d2d2d2 #d3d3d3 #ffba16 #f73954 #ffbd0a #ff6600 #fff6f3 #dddddd #e0e0e0 #f70c38 #47b81b #38c595 #f1f1f1 #f5f5f5 #3c5c8c #094691 #002553 #333333 #cccccc #cccccc #8290AF #abb1b6 #ffd1c0 #fdf0eb #e4e9ec #d3d3d3 #ffae00 #e9eef3 #ECF0F4 #1ac677 #ECF1F7 #3cace6 #35d282 #ff2a00 #f3f3f3 #d9d9d9 #1b1b1b #818181 #919191 #c7c7c7 #404040 #fcfcfc #333333 #f0420c #BEC0C1 #909090 #666666 #ff000000 #ffffffff #ffcccccc #ff404040 #ffffffff #ff808080 #ffffffff #fffff0e0 #ffffffff #ff000000 #ff4b4b4b #ff000000 #ffffffff #50000000 #ffffffff #00000000 #ff000000 #ffff0000 #D4D4D4 #A9A9A9 #999999 #e1e1e1 #d3d3d3 #5191F2 #1AAC19 #19ad19 #4a4a4a #a2a2a2 #d1d1d1 #00c679 #F5F6F8 #656565 #FFF0E5 #F0F1F2 #C7C9D1 #f5f6f8 #fd3341 #dce1e5 #9498a4 #202741 #444861 #e8e8e8 #FF8963 #2a3038 #9398AE #00A7FF #5c6166 #e4e5e6 #ffb452 #ff7252 #8898A6 #ACB0B9 #CACCD0 #f0f1f3 #eda95b40 #3257c5 #9d9da3 #d7d8dc #c4c6cc #cdcfd5 #d2d4d9 #939499 #616366 #dcdcdc #cc0042ff #97a0ab #ebba8f #a86010 #00BCD4 #d2d0d1 #4db6ac #84ffff
然后是我们的布局
布局中呢会有一些图片这个图片的话就自己搞吧然后在res文件下创建一个dimen
8dp 3dp 4dp 104dp 168dp 56dp 1dp 24dp 3dp 6dp 16dp 3dp 12dp 12dp 14sp 12sp
我们的底部导航的样式就搞完了,接下里就是我们的动画效果写一个自定义Drawable
package com.example.map.tab;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
public class RippleDrawable extends Drawable implements Animatable {
public static final int MODE_LEFT = 1;
public static final int MODE_MIDDLE = 2;
public static final int MODE_RIGHT = 3;
private int mMode = MODE_MIDDLE;
// 前景色和后景色画笔
private Paint mPaintFront;
private Paint mPaintBehind;
// 用来绘制扇形的矩形框
private RectF mRect;
// 目标View的宽高的一半
private int mHalfWidth;
private int mHalfHeight;
// 扩散半径
private int mRadius;
// 前景色和背景色的分割距离
private int mDivideSpace;
// 扩散满视图需要的距离,中点到斜角的距离
private int mFullSpace;
// 动画控制
private ValueAnimator mValueAnimator;
public RippleDrawable(int frontColor, int behindColor, int mode) {
mPaintFront = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintFront.setColor(frontColor);
mPaintBehind = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintBehind.setColor(behindColor);
mRect = new RectF();
mMode = mode;
}
@Override
public void draw(Canvas canvas) {
if (mRadius > mHalfWidth) {
int count = canvas.save();
canvas.drawCircle(mHalfWidth, mHalfHeight, mHalfWidth, mPaintBehind);
canvas.restoreToCount(count);
count = canvas.save();
canvas.drawCircle(mHalfWidth, mHalfHeight, mDivideSpace, mPaintFront);
canvas.restoreToCount(count);
} else if (mRadius > mDivideSpace) {
int count = canvas.save();
canvas.drawCircle(mHalfWidth, mHalfHeight, mRadius, mPaintBehind);
canvas.restoreToCount(count);
count = canvas.save();
canvas.drawCircle(mHalfWidth, mHalfHeight, mDivideSpace, mPaintFront);
canvas.restoreToCount(count);
} else {
canvas.drawCircle(mHalfWidth, mHalfHeight, mRadius, mPaintFront);
}
// 左右两边才进行扇形绘制
if (mMode != MODE_MIDDLE) {
mRect.left = mHalfWidth - mRadius;
mRect.right = mHalfWidth + mRadius;
mRect.top = mHalfHeight - mRadius;
mRect.bottom = mHalfHeight + mRadius;
}
if (mMode == MODE_LEFT) {
canvas.drawArc(mRect, 90, 180, true, mPaintFront);
} else if (mMode == MODE_RIGHT) {
canvas.drawArc(mRect, -90, 180, true, mPaintFront);
}
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
}
@Override
public int getOpacity() {
return PixelFormat.RGBA_8888;
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
mHalfHeight = (bounds.bottom - bounds.top) / 2;
mHalfWidth = (bounds.right - bounds.left) / 2;
mDivideSpace = Math.max(mHalfHeight, mHalfWidth) * 3 / 4;
mFullSpace = (int) Math.sqrt(mHalfWidth * mHalfWidth + mHalfHeight * mHalfHeight);
// 属性动画
mValueAnimator = ValueAnimator.ofInt(0, mFullSpace);
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mRadius = (int) animation.getAnimatedValue();
invalidateSelf();
}
});
mValueAnimator.setDuration(200);
start();
}
@Override
public void start() {
mValueAnimator.start();
}
@Override
public void stop() {
mValueAnimator.end();
}
@Override
public boolean isRunning() {
return mValueAnimator != null && mValueAnimator.isRunning();
}
}
然后创建我们的TabFragment
package com.example.map.tab;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.example.map.R;
public class TabFragment extends Fragment {
public static final String FRAG_KEY = "FragKey";
private TextView mFragTabText;
private void assignViews(View view) {
mFragTabText = (TextView) view.findViewById(R.id.frag_tab_text);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_tab, null);
assignViews(view);
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (getArguments() != null) {
String title = getArguments().getString(FRAG_KEY);
mFragTabText.setText(title);
}
}
}
然后创建一个动画的帮助类
package com.example.map.tab;
import android.animation.AnimatorSet;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.graphics.drawable.ClipDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
public class TabAnimHelper {
public static void changeTopPadding(final View view, int fromPadding, int toPadding) {
ValueAnimator animator = ValueAnimator.ofFloat(fromPadding, toPadding);
animator.setDuration(150);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float animatedValue = (float) valueAnimator.getAnimatedValue();
view.setPadding(view.getPaddingLeft(),
(int) animatedValue,
view.getPaddingRight(),
view.getPaddingBottom());
}
});
animator.start();
}
public static void changeTextSize(final TextView textView, float from, float to) {
ValueAnimator textSizeChangeAnimator = ValueAnimator.ofFloat(from, to);
textSizeChangeAnimator.setDuration(150);
textSizeChangeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, (float) valueAnimator.getAnimatedValue());
}
});
textSizeChangeAnimator.start();
}
public static void changeTextColor(final TextView textView, int fromColor, int toColor) {
ValueAnimator changeTextColorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), fromColor, toColor);
changeTextColorAnimation.setDuration(150);
changeTextColorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animator) {
textView.setTextColor((Integer) animator.getAnimatedValue());
}
});
changeTextColorAnimation.start();
}
public static void changeImageSize(ImageView image, float fromScale, float toScale) {
ObjectAnimator scaleX;
ObjectAnimator scaleY;
scaleX = ObjectAnimator.ofFloat(image, "scaleX", fromScale, toScale);
scaleY = ObjectAnimator.ofFloat(image, "scaleY", fromScale, toScale);
AnimatorSet set = new AnimatorSet();
set.setDuration(150);
set.playTogether(scaleX, scaleY);
set.start();
}
@SuppressWarnings("deprecation")
public static void clipDrawable(final View image, Drawable drawable, boolean isActivated) {
if (drawable == null) {
return;
}
if (isActivated) {
final ClipDrawable scaleDrawable = new ClipDrawable(drawable, Gravity.CENTER,
ClipDrawable.HORIZONTAL | ClipDrawable.VERTICAL);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
image.setBackground(scaleDrawable);
} else {
image.setBackgroundDrawable(scaleDrawable);
}
image.setBackgroundDrawable(scaleDrawable);
ValueAnimator animator = ValueAnimator.ofInt(0, 10000);
animator.setDuration(200);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
scaleDrawable.setLevel((Integer) animation.getAnimatedValue());
}
});
animator.start();
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
image.setBackground(null);
} else {
image.setBackgroundDrawable(null);
}
}
}
@SuppressWarnings("deprecation")
public static void rippleDrawable(final View view, int frontColor, int behindColor, int mode, boolean isActivated) {
if (isActivated) {
RippleDrawable rippleDrawable = new RippleDrawable(frontColor, behindColor, mode);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
view.setBackground(rippleDrawable);
} else {
view.setBackgroundDrawable(rippleDrawable);
}
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
view.setBackground(null);
} else {
view.setBackgroundDrawable(null);
}
}
}
}
还有一个item的实体类
package com.example.map.tab;
import android.graphics.drawable.Drawable;
public class TabItem {
private String title;
private Drawable drawable;
private int imageRes;
public TabItem(String title, Drawable drawable, int imageRes) {
this.title = title;
this.drawable = drawable;
this.imageRes = imageRes;
}
public TabItem(String title, int imageRes) {
this.title = title;
this.drawable = null;
this.imageRes = imageRes;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Drawable getDrawable() {
return drawable;
}
public void setDrawable(Drawable drawable) {
this.drawable = drawable;
}
public int getImageRes() {
return imageRes;
}
public void setImageRes(int imageRes) {
this.imageRes = imageRes;
}
}
然后在我们的Activity中进行一个引用,首先在是我们Activity的一个布局
然后在我们的Activity中进行一个应用控件
package com.example.map.ui.activity;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestBuilder;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.RequestOptions;
import com.example.map.api.ApiService;
import com.example.map.base.GlideImageLoader;
import com.example.map.bean.WallPaperResponse;
import com.example.map.ui.fragment.Fragment1;
import com.example.map.ui.fragment.Fragment2;
import com.example.map.ui.fragment.Fragment3;
import com.example.map.ui.fragment.Fragment4;
import com.example.map.ui.fragment.Fragment5;
import com.example.map.R;
import com.example.map.tab.TabFragment;
import com.example.map.tab.TabItem;
import com.example.map.tab.XFragmentTabHost;
import com.llw.network.NetworkApi;
import com.llw.network.observer.BaseObserver;
import com.llw.network.utils.KLog;
import com.youth.banner.Banner;
import com.youth.banner.BannerConfig;
import com.youth.banner.Transformer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class QihooActivity extends AppCompatActivity {
private XFragmentTabHost mTabHost;
//底部导航的名称
String[] mTabTitle = new String[]{"首页", "游戏", "软件", "应用圈", "管理"};
//文字上的图片
int[] mImageResId = new int[]{R.drawable.sel_360_home, R.drawable.sel_360_game, R.drawable.sel_360_software,
R.drawable.sel_360_app, R.drawable.sel_360_mag};
//创建的几个fragment
Class[] mFragClass = new Class[]{Fragment1.class, Fragment2.class,
Fragment3.class, Fragment4.class, Fragment5.class};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_qihoo);
initTabHost();
}
private void initTabHost() {
mTabHost = (XFragmentTabHost) findViewById(android.R.id.tabhost);
mTabHost.setup(this, getSupportFragmentManager(), R.id.relate_tab_content);
mTabHost.setTabMode(XFragmentTabHost.TabMode.Ripple);
mTabHost.setTextActiveColor(Color.WHITE);
mTabHost.setTextInactiveColor(Color.GRAY);
// mTabHost.setFrontColor(Color.RED);
// mTabHost.setBehindColor(Color.GREEN);
for (int i = 0; i < mFragClass.length; i++) {
Bundle bundle = new Bundle();
bundle.putString(TabFragment.FRAG_KEY, mTabTitle[i]);
mTabHost.addTabItem(new TabItem(mTabTitle[i], mImageResId[i]),
mFragClass[i], bundle);
}
}
}
这样我们的一个自定义的水波纹动画的底部导航就完成了



