v416
This commit is contained in:
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,29 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
namespace 'me.majiajie.pagerbottomtabstrip'
|
||||
compileSdkVersion 29
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 29
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.annotation:annotation:1.2.0'
|
||||
implementation 'androidx.viewpager:viewpager:1.0.0'
|
||||
}
|
||||
|
||||
//apply from: 'upload_to_maven_central.gradle'
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in C:\Users\MJJ\Develop\SDK/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
@@ -0,0 +1,6 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="me.majiajie.pagerbottomtabstrip">
|
||||
|
||||
<application android:label="@string/app_name" />
|
||||
|
||||
</manifest>
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package me.majiajie.pagerbottomtabstrip;
|
||||
|
||||
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
interface BottomLayoutController {
|
||||
|
||||
/**
|
||||
* 方便适配ViewPager页面切换<p>
|
||||
* 注意:ViewPager页面数量必须等于导航栏的Item数量
|
||||
*
|
||||
* @param viewPager {@link ViewPager}
|
||||
*/
|
||||
void setupWithViewPager(ViewPager viewPager);
|
||||
|
||||
/**
|
||||
* 向下移动隐藏导航栏
|
||||
*/
|
||||
void hideBottomLayout();
|
||||
|
||||
/**
|
||||
* 向上移动显示导航栏
|
||||
*/
|
||||
void showBottomLayout();
|
||||
}
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
package me.majiajie.pagerbottomtabstrip;
|
||||
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import me.majiajie.pagerbottomtabstrip.item.BaseTabItem;
|
||||
import me.majiajie.pagerbottomtabstrip.listener.OnTabItemSelectedListener;
|
||||
import me.majiajie.pagerbottomtabstrip.listener.SimpleTabItemSelectedListener;
|
||||
|
||||
public interface ItemController {
|
||||
|
||||
/**
|
||||
* 设置选中项
|
||||
*
|
||||
* @param index 顺序索引
|
||||
*/
|
||||
void setSelect(int index);
|
||||
|
||||
/**
|
||||
* 设置选中项,并可以控制是否回调监听事件
|
||||
*
|
||||
* @param index 顺序索引
|
||||
* @param listener true:假如存在监听事件{@link OnTabItemSelectedListener},就会调用相关的回调方法。false:不会触发监听事件
|
||||
*/
|
||||
void setSelect(int index, boolean listener);
|
||||
|
||||
/**
|
||||
* 设置导航按钮上显示的圆形消息数字,通过顺序索引。
|
||||
*
|
||||
* @param index 顺序索引
|
||||
* @param number 消息数字
|
||||
*/
|
||||
void setMessageNumber(int index, int number);
|
||||
|
||||
/**
|
||||
* 设置显示无数字的消息小原点
|
||||
*
|
||||
* @param index 顺序索引
|
||||
* @param hasMessage true显示
|
||||
*/
|
||||
void setHasMessage(int index, boolean hasMessage);
|
||||
|
||||
/**
|
||||
* 导航栏按钮点击监听
|
||||
*
|
||||
* @param listener {@link OnTabItemSelectedListener}
|
||||
*/
|
||||
void addTabItemSelectedListener(OnTabItemSelectedListener listener);
|
||||
|
||||
/**
|
||||
* 导航栏按钮点击监听(只有选中事件)
|
||||
*
|
||||
* @param listener {@link SimpleTabItemSelectedListener}
|
||||
*/
|
||||
void addSimpleTabItemSelectedListener(SimpleTabItemSelectedListener listener);
|
||||
|
||||
/**
|
||||
* 设置标题
|
||||
*
|
||||
* @param index 顺序索引
|
||||
* @param title 标题文字
|
||||
*/
|
||||
void setTitle(int index, String title);
|
||||
|
||||
/**
|
||||
* 设置未选中状态下的图标
|
||||
*
|
||||
* @param index 顺序索引
|
||||
* @param drawable 图标资源
|
||||
*/
|
||||
void setDefaultDrawable(int index, Drawable drawable);
|
||||
|
||||
/**
|
||||
* 设置选中状态下的图标
|
||||
*
|
||||
* @param index 顺序索引
|
||||
* @param drawable 图标资源
|
||||
*/
|
||||
void setSelectedDrawable(int index, Drawable drawable);
|
||||
|
||||
/**
|
||||
* 获取当前选中项索引
|
||||
*
|
||||
* @return 索引
|
||||
*/
|
||||
int getSelected();
|
||||
|
||||
/**
|
||||
* 获取导航按钮总数
|
||||
*
|
||||
* @return 总数
|
||||
*/
|
||||
int getItemCount();
|
||||
|
||||
/**
|
||||
* 获取导航按钮文字
|
||||
*
|
||||
* @param index 顺序索引
|
||||
* @return 文字
|
||||
*/
|
||||
String getItemTitle(int index);
|
||||
|
||||
/**
|
||||
* 移除指定的导航项.需要注意,不能移除当前选中的导航项
|
||||
*
|
||||
* @return 移除是否成功
|
||||
*/
|
||||
boolean removeItem(int index);
|
||||
|
||||
/**
|
||||
* 添加一个材料设计样式的TabItem.注意,只对<code>material()</code>构建的导航栏有效
|
||||
*
|
||||
* @param index 顺序索引
|
||||
* @param defaultDrawable 未选中状态的图标资源
|
||||
* @param selectedDrawable 选中状态的图标资源
|
||||
* @param title 标题
|
||||
* @param selectedColor 选中状态的颜色
|
||||
*/
|
||||
void addMaterialItem(int index, Drawable defaultDrawable, Drawable selectedDrawable, String title, int selectedColor);
|
||||
|
||||
/**
|
||||
* 添加一个自定义样式的TabItem.注意,只对<code>custom()</code>构建的导航栏有效
|
||||
*
|
||||
* @param index 顺序索引
|
||||
* @param item 自定义的Item
|
||||
*/
|
||||
void addCustomItem(int index, BaseTabItem item);
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package me.majiajie.pagerbottomtabstrip;
|
||||
|
||||
|
||||
/**
|
||||
* <p>模式选择。</p>
|
||||
* <p>采用组合的形式,比如要两种效果可以这样做:</p>
|
||||
* MaterialMode.HIDE_TEXT | MaterialMode.CHANGE_BACKGROUND_COLOR
|
||||
*/
|
||||
public final class MaterialMode {
|
||||
/**
|
||||
* 隐藏文字内容,只在选中时显示文字
|
||||
*/
|
||||
public static final int HIDE_TEXT = 0X1;
|
||||
|
||||
/**
|
||||
* 开启导航栏背景变换。点击不同项切换不同背景颜色
|
||||
*/
|
||||
public static final int CHANGE_BACKGROUND_COLOR = 0X2;
|
||||
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
package me.majiajie.pagerbottomtabstrip;
|
||||
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import me.majiajie.pagerbottomtabstrip.internal.Utils;
|
||||
import me.majiajie.pagerbottomtabstrip.item.BaseTabItem;
|
||||
import me.majiajie.pagerbottomtabstrip.listener.OnTabItemSelectedListener;
|
||||
import me.majiajie.pagerbottomtabstrip.listener.SimpleTabItemSelectedListener;
|
||||
|
||||
public class NavigationController implements ItemController, BottomLayoutController {
|
||||
|
||||
private BottomLayoutController mBottomLayoutController;
|
||||
private ItemController mItemController;
|
||||
|
||||
protected NavigationController(BottomLayoutController bottomLayoutController, ItemController itemController) {
|
||||
mBottomLayoutController = bottomLayoutController;
|
||||
mItemController = itemController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelect(int index) {
|
||||
mItemController.setSelect(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelect(int index, boolean listener) {
|
||||
mItemController.setSelect(index, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMessageNumber(int index, int number) {
|
||||
mItemController.setMessageNumber(index, number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHasMessage(int index, boolean hasMessage) {
|
||||
mItemController.setHasMessage(index, hasMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTabItemSelectedListener(@NonNull OnTabItemSelectedListener listener) {
|
||||
mItemController.addTabItemSelectedListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSimpleTabItemSelectedListener(@NonNull SimpleTabItemSelectedListener listener) {
|
||||
mItemController.addSimpleTabItemSelectedListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(int index,@NonNull String title) {
|
||||
mItemController.setTitle(index, title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultDrawable(int index,@NonNull Drawable drawable) {
|
||||
mItemController.setDefaultDrawable(index, drawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectedDrawable(int index,@NonNull Drawable drawable) {
|
||||
mItemController.setSelectedDrawable(index, drawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSelected() {
|
||||
return mItemController.getSelected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mItemController.getItemCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemTitle(int index) {
|
||||
return mItemController.getItemTitle(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeItem(int index) {
|
||||
return mItemController.removeItem(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMaterialItem(int index,@NonNull Drawable defaultDrawable,@NonNull Drawable selectedDrawable,@NonNull String title, int selectedColor) {
|
||||
mItemController.addMaterialItem(index, Utils.newDrawable(defaultDrawable), Utils.newDrawable(selectedDrawable), title, selectedColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCustomItem(int index,@NonNull BaseTabItem item) {
|
||||
mItemController.addCustomItem(index, item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupWithViewPager(@NonNull ViewPager viewPager) {
|
||||
mBottomLayoutController.setupWithViewPager(viewPager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideBottomLayout() {
|
||||
mBottomLayoutController.hideBottomLayout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showBottomLayout() {
|
||||
mBottomLayoutController.showBottomLayout();
|
||||
}
|
||||
}
|
||||
+666
@@ -0,0 +1,666 @@
|
||||
package me.majiajie.pagerbottomtabstrip;
|
||||
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import me.majiajie.pagerbottomtabstrip.internal.CustomItemVerticalLayout;
|
||||
import me.majiajie.pagerbottomtabstrip.internal.MaterialItemLayout;
|
||||
import me.majiajie.pagerbottomtabstrip.internal.MaterialItemVerticalLayout;
|
||||
import me.majiajie.pagerbottomtabstrip.internal.OldCustomItemLayout;
|
||||
import me.majiajie.pagerbottomtabstrip.internal.Utils;
|
||||
import me.majiajie.pagerbottomtabstrip.item.BaseTabItem;
|
||||
import me.majiajie.pagerbottomtabstrip.item.MaterialItemView;
|
||||
import me.majiajie.pagerbottomtabstrip.item.OnlyIconMaterialItemView;
|
||||
import me.majiajie.pagerbottomtabstrip.listener.OnTabItemSelectedListener;
|
||||
|
||||
/**
|
||||
* 导航视图
|
||||
*/
|
||||
public class OldPageNavigationView extends ViewGroup {
|
||||
private int mTabPaddingTop;
|
||||
private int mTabPaddingBottom;
|
||||
|
||||
private NavigationController mNavigationController;
|
||||
|
||||
private ViewPagerPageChangeListener mPageChangeListener;
|
||||
private ViewPager mViewPager;
|
||||
|
||||
private boolean mEnableVerticalLayout;
|
||||
|
||||
private OnTabItemSelectedListener mTabItemListener = new OnTabItemSelectedListener() {
|
||||
@Override
|
||||
public void onSelected(int index, int old) {
|
||||
if (mViewPager != null) {
|
||||
mViewPager.setCurrentItem(index, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRepeat(int index) {
|
||||
}
|
||||
};
|
||||
|
||||
public OldPageNavigationView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public OldPageNavigationView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public OldPageNavigationView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
setPadding(0, 0, 0, 0);
|
||||
|
||||
final TypedArray a = context.obtainStyledAttributes(
|
||||
attrs, R.styleable.PageNavigationView);
|
||||
if (a.hasValue(R.styleable.PageNavigationView_NavigationPaddingTop)) {
|
||||
mTabPaddingTop = a.getDimensionPixelSize(R.styleable.PageNavigationView_NavigationPaddingTop, 0);
|
||||
}
|
||||
if (a.hasValue(R.styleable.PageNavigationView_NavigationPaddingBottom)) {
|
||||
mTabPaddingBottom = a.getDimensionPixelSize(R.styleable.PageNavigationView_NavigationPaddingBottom, 0);
|
||||
}
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
|
||||
final int count = getChildCount();
|
||||
|
||||
int maxWidth = MeasureSpec.getSize(widthMeasureSpec);
|
||||
int maxHeight = MeasureSpec.getSize(heightMeasureSpec);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() == GONE) {
|
||||
continue;
|
||||
}
|
||||
measureChild(child, widthMeasureSpec,heightMeasureSpec);
|
||||
|
||||
maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
|
||||
maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
|
||||
}
|
||||
|
||||
setMeasuredDimension(maxWidth, maxHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
final int count = getChildCount();
|
||||
final int width = r - l;
|
||||
final int height = b - t;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() == GONE) {
|
||||
continue;
|
||||
}
|
||||
child.layout(0, 0, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CharSequence getAccessibilityClassName() {
|
||||
return OldPageNavigationView.class.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 Material Desgin 风格的导航栏
|
||||
*/
|
||||
public MaterialBuilder material() {
|
||||
return new MaterialBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建自定义导航栏
|
||||
*/
|
||||
public CustomBuilder custom() {
|
||||
return new CustomBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 自定义 的导航栏
|
||||
*/
|
||||
public class CustomBuilder {
|
||||
|
||||
private List<BaseTabItem> items;
|
||||
|
||||
private boolean enableVerticalLayout = false;
|
||||
private boolean animateLayoutChanges = false;
|
||||
|
||||
CustomBuilder() {
|
||||
items = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 完成构建
|
||||
*
|
||||
* @return {@link NavigationController},通过它进行后续操作
|
||||
* @throws RuntimeException 没有添加导航项时会抛出
|
||||
*/
|
||||
public NavigationController build() {
|
||||
|
||||
mEnableVerticalLayout = enableVerticalLayout;
|
||||
|
||||
//未添加任何按钮
|
||||
if (items.size() == 0) {
|
||||
throw new RuntimeException("must add a navigation item");
|
||||
}
|
||||
|
||||
ItemController itemController;
|
||||
|
||||
if (enableVerticalLayout) {//垂直布局
|
||||
CustomItemVerticalLayout verticalItemLayout = new CustomItemVerticalLayout(getContext());
|
||||
verticalItemLayout.initialize(items, animateLayoutChanges);
|
||||
verticalItemLayout.setPadding(0, mTabPaddingTop, 0, mTabPaddingBottom);
|
||||
|
||||
OldPageNavigationView.this.removeAllViews();
|
||||
OldPageNavigationView.this.addView(verticalItemLayout);
|
||||
itemController = verticalItemLayout;
|
||||
} else {//水平布局
|
||||
OldCustomItemLayout customItemLayout = new OldCustomItemLayout(getContext());
|
||||
customItemLayout.initialize(items, animateLayoutChanges);
|
||||
customItemLayout.setPadding(0, mTabPaddingTop, 0, mTabPaddingBottom);
|
||||
|
||||
OldPageNavigationView.this.removeAllViews();
|
||||
OldPageNavigationView.this.addView(customItemLayout);
|
||||
itemController = customItemLayout;
|
||||
}
|
||||
|
||||
mNavigationController = new NavigationController(new Controller(), itemController);
|
||||
mNavigationController.addTabItemSelectedListener(mTabItemListener);
|
||||
|
||||
return mNavigationController;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个导航按钮
|
||||
*
|
||||
* @param baseTabItem {@link BaseTabItem},所有自定义Item都必须继承它
|
||||
* @return {@link CustomBuilder}
|
||||
*/
|
||||
public CustomBuilder addItem(BaseTabItem baseTabItem) {
|
||||
items.add(baseTabItem);
|
||||
return CustomBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用垂直布局
|
||||
*
|
||||
* @return {@link CustomBuilder}
|
||||
*/
|
||||
public CustomBuilder enableVerticalLayout() {
|
||||
enableVerticalLayout = true;
|
||||
return CustomBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过{@link NavigationController}动态移除/添加导航项时,显示默认的布局动画
|
||||
*
|
||||
* @return {@link CustomBuilder}
|
||||
*/
|
||||
public CustomBuilder enableAnimateLayoutChanges() {
|
||||
animateLayoutChanges = true;
|
||||
return CustomBuilder.this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 Material Desgin 风格的导航栏
|
||||
*/
|
||||
public class MaterialBuilder {
|
||||
|
||||
private final int DEFAULT_COLOR = 0x56000000;
|
||||
|
||||
private List<MaterialItemViewData> itemDatas;
|
||||
private int defaultColor;
|
||||
private int mode;
|
||||
private int messageBackgroundColor;
|
||||
private int messageNumberColor;
|
||||
private boolean enableVerticalLayout = false;
|
||||
private boolean doTintIcon = true;
|
||||
private boolean animateLayoutChanges = false;
|
||||
|
||||
MaterialBuilder() {
|
||||
itemDatas = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 完成构建
|
||||
*
|
||||
* @return {@link NavigationController},通过它进行后续操作
|
||||
* @throws RuntimeException 没有添加导航项时会抛出
|
||||
*/
|
||||
@NonNull
|
||||
public NavigationController build() {
|
||||
mEnableVerticalLayout = enableVerticalLayout;
|
||||
|
||||
// 未添加任何按钮
|
||||
if (itemDatas.isEmpty()) {
|
||||
throw new RuntimeException("must add a navigation item");
|
||||
}
|
||||
|
||||
// 设置默认颜色
|
||||
if (defaultColor == 0) {
|
||||
defaultColor = DEFAULT_COLOR;
|
||||
}
|
||||
|
||||
ItemController itemController;
|
||||
|
||||
if (enableVerticalLayout) {//垂直布局
|
||||
|
||||
List<BaseTabItem> items = new ArrayList<>();
|
||||
|
||||
for (MaterialItemViewData data : itemDatas) {
|
||||
|
||||
OnlyIconMaterialItemView materialItemView = new OnlyIconMaterialItemView(getContext());
|
||||
materialItemView.initialization(data.title, data.drawable, data.checkedDrawable, doTintIcon, defaultColor, data.chekedColor);
|
||||
|
||||
//检查是否设置了消息圆点的颜色
|
||||
if (messageBackgroundColor != 0) {
|
||||
materialItemView.setMessageBackgroundColor(messageBackgroundColor);
|
||||
}
|
||||
|
||||
//检查是否设置了消息数字的颜色
|
||||
if (messageNumberColor != 0) {
|
||||
materialItemView.setMessageNumberColor(messageNumberColor);
|
||||
}
|
||||
|
||||
items.add(materialItemView);
|
||||
}
|
||||
|
||||
MaterialItemVerticalLayout materialItemVerticalLayout = new MaterialItemVerticalLayout(getContext());
|
||||
materialItemVerticalLayout.initialize(items, animateLayoutChanges, doTintIcon, defaultColor);
|
||||
materialItemVerticalLayout.setPadding(0, mTabPaddingTop, 0, mTabPaddingBottom);
|
||||
|
||||
OldPageNavigationView.this.removeAllViews();
|
||||
OldPageNavigationView.this.addView(materialItemVerticalLayout);
|
||||
|
||||
itemController = materialItemVerticalLayout;
|
||||
|
||||
} else {//水平布局
|
||||
|
||||
boolean changeBackground = (mode & MaterialMode.CHANGE_BACKGROUND_COLOR) > 0;
|
||||
|
||||
List<MaterialItemView> items = new ArrayList<>();
|
||||
List<Integer> checkedColors = new ArrayList<>();
|
||||
|
||||
for (MaterialItemViewData data : itemDatas) {
|
||||
// 记录设置的选中颜色
|
||||
checkedColors.add(data.chekedColor);
|
||||
|
||||
MaterialItemView materialItemView = new MaterialItemView(getContext());
|
||||
// 初始化Item,需要切换背景颜色就将选中颜色改成白色
|
||||
materialItemView.initialization(data.title, data.drawable, data.checkedDrawable, doTintIcon, defaultColor, changeBackground ? Color.WHITE : data.chekedColor);
|
||||
|
||||
//检查是否设置了消息圆点的颜色
|
||||
if (messageBackgroundColor != 0) {
|
||||
materialItemView.setMessageBackgroundColor(messageBackgroundColor);
|
||||
}
|
||||
|
||||
//检查是否设置了消息数字的颜色
|
||||
if (messageNumberColor != 0) {
|
||||
materialItemView.setMessageNumberColor(messageNumberColor);
|
||||
}
|
||||
|
||||
items.add(materialItemView);
|
||||
}
|
||||
|
||||
MaterialItemLayout materialItemLayout = new MaterialItemLayout(getContext());
|
||||
materialItemLayout.initialize(items, checkedColors, mode, animateLayoutChanges, doTintIcon, defaultColor);
|
||||
materialItemLayout.setPadding(0, mTabPaddingTop, 0, mTabPaddingBottom);
|
||||
|
||||
OldPageNavigationView.this.removeAllViews();
|
||||
OldPageNavigationView.this.addView(materialItemLayout);
|
||||
|
||||
itemController = materialItemLayout;
|
||||
}
|
||||
|
||||
mNavigationController = new NavigationController(new Controller(), itemController);
|
||||
mNavigationController.addTabItemSelectedListener(mTabItemListener);
|
||||
|
||||
return mNavigationController;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个导航按钮
|
||||
*
|
||||
* @param drawableRes 图标资源
|
||||
* @param title 显示文字内容.尽量简短
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder addItem(@DrawableRes int drawableRes, @NonNull String title) {
|
||||
addItem(drawableRes, drawableRes, title, Utils.getColorPrimary(getContext()));
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个导航按钮
|
||||
*
|
||||
* @param drawableRes 图标资源
|
||||
* @param checkedDrawableRes 选中时的图标资源
|
||||
* @param title 显示文字内容.尽量简短
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder addItem(@DrawableRes int drawableRes, @DrawableRes int checkedDrawableRes, @NonNull String title) {
|
||||
addItem(drawableRes, checkedDrawableRes, title, Utils.getColorPrimary(getContext()));
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个导航按钮
|
||||
*
|
||||
* @param drawableRes 图标资源
|
||||
* @param title 显示文字内容.尽量简短
|
||||
* @param chekedColor 选中的颜色
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder addItem(@DrawableRes int drawableRes, @NonNull String title, @ColorInt int chekedColor) {
|
||||
addItem(drawableRes, drawableRes, title, chekedColor);
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个导航按钮
|
||||
*
|
||||
* @param drawableRes 图标资源
|
||||
* @param checkedDrawableRes 选中时的图标资源
|
||||
* @param title 显示文字内容.尽量简短
|
||||
* @param chekedColor 选中的颜色
|
||||
* @return {@link MaterialBuilder}
|
||||
* @throws Resources.NotFoundException drawable 资源获取异常
|
||||
*/
|
||||
public MaterialBuilder addItem(@DrawableRes int drawableRes, @DrawableRes int checkedDrawableRes, @NonNull String title, @ColorInt int chekedColor) {
|
||||
Drawable defaultDrawable = ContextCompat.getDrawable(getContext(), drawableRes);
|
||||
Drawable checkDrawable = ContextCompat.getDrawable(getContext(), checkedDrawableRes);
|
||||
if (defaultDrawable == null) {
|
||||
throw new Resources.NotFoundException("Resource ID " + Integer.toHexString(drawableRes));
|
||||
}
|
||||
if (checkDrawable == null) {
|
||||
throw new Resources.NotFoundException("Resource ID " + Integer.toHexString(checkedDrawableRes));
|
||||
}
|
||||
addItem(defaultDrawable, checkDrawable, title, chekedColor);
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个导航按钮
|
||||
*
|
||||
* @param drawable 图标资源
|
||||
* @param title 显示文字内容.尽量简短
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder addItem(@NonNull Drawable drawable, @NonNull String title) {
|
||||
addItem(drawable, drawable, title, Utils.getColorPrimary(getContext()));
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个导航按钮
|
||||
*
|
||||
* @param drawable 图标资源
|
||||
* @param checkedDrawable 选中时的图标资源
|
||||
* @param title 显示文字内容.尽量简短
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder addItem(@NonNull Drawable drawable, @NonNull Drawable checkedDrawable, @NonNull String title) {
|
||||
addItem(drawable, checkedDrawable, title, Utils.getColorPrimary(getContext()));
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个导航按钮
|
||||
*
|
||||
* @param drawable 图标资源
|
||||
* @param title 显示文字内容.尽量简短
|
||||
* @param chekedColor 选中的颜色
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder addItem(@NonNull Drawable drawable, @NonNull String title, @ColorInt int chekedColor) {
|
||||
addItem(drawable, drawable, title, chekedColor);
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个导航按钮
|
||||
*
|
||||
* @param drawable 图标资源
|
||||
* @param checkedDrawable 选中时的图标资源
|
||||
* @param title 显示文字内容.尽量简短
|
||||
* @param chekedColor 选中的颜色
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder addItem(@NonNull Drawable drawable, @NonNull Drawable checkedDrawable, @NonNull String title, @ColorInt int chekedColor) {
|
||||
MaterialItemViewData data = new MaterialItemViewData();
|
||||
data.drawable = Utils.newDrawable(drawable);
|
||||
data.checkedDrawable = Utils.newDrawable(checkedDrawable);
|
||||
data.title = title;
|
||||
data.chekedColor = chekedColor;
|
||||
itemDatas.add(data);
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置导航按钮的默认(未选中状态)颜色
|
||||
*
|
||||
* @param color 16进制整形表示的颜色,例如红色:0xFFFF0000
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder setDefaultColor(@ColorInt int color) {
|
||||
defaultColor = color;
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置消息圆点的颜色
|
||||
*
|
||||
* @param color 16进制整形表示的颜色,例如红色:0xFFFF0000
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder setMessageBackgroundColor(@ColorInt int color) {
|
||||
messageBackgroundColor = color;
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置消息数字的颜色
|
||||
*
|
||||
* @param color 16进制整形表示的颜色,例如红色:0xFFFF0000
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder setMessageNumberColor(@ColorInt int color) {
|
||||
messageNumberColor = color;
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置模式(在垂直布局中无效)。默认文字一直显示,且背景色不变。
|
||||
* 可以通过{@link MaterialMode}选择模式。
|
||||
* <p>例如:</p>
|
||||
* {@code MaterialMode.HIDE_TEXT}
|
||||
* <p>或者多选:</p>
|
||||
* {@code MaterialMode.HIDE_TEXT | MaterialMode.CHANGE_BACKGROUND_COLOR}
|
||||
*
|
||||
* @param mode {@link MaterialMode}
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder setMode(int mode) {
|
||||
MaterialBuilder.this.mode = mode;
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用垂直布局
|
||||
*
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder enableVerticalLayout() {
|
||||
enableVerticalLayout = true;
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 不对图标进行染色
|
||||
*
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder dontTintIcon() {
|
||||
doTintIcon = false;
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过{@link NavigationController}动态移除/添加导航项时,显示默认的布局动画
|
||||
*
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder enableAnimateLayoutChanges() {
|
||||
animateLayoutChanges = true;
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 材料设计的单项视图信息
|
||||
*/
|
||||
private static class MaterialItemViewData {
|
||||
Drawable drawable;
|
||||
Drawable checkedDrawable;
|
||||
String title;
|
||||
@ColorInt
|
||||
int chekedColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实现控制接口
|
||||
*/
|
||||
private class Controller implements BottomLayoutController {
|
||||
|
||||
private ObjectAnimator animator;
|
||||
private boolean hide = false;
|
||||
|
||||
@Override
|
||||
public void setupWithViewPager(ViewPager viewPager) {
|
||||
if (viewPager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mViewPager = viewPager;
|
||||
|
||||
if (mPageChangeListener != null) {
|
||||
mViewPager.removeOnPageChangeListener(mPageChangeListener);
|
||||
} else {
|
||||
mPageChangeListener = new ViewPagerPageChangeListener();
|
||||
}
|
||||
|
||||
if (mNavigationController != null) {
|
||||
int n = mViewPager.getCurrentItem();
|
||||
if (mNavigationController.getSelected() != n) {
|
||||
mNavigationController.setSelect(n);
|
||||
}
|
||||
mViewPager.addOnPageChangeListener(mPageChangeListener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideBottomLayout() {
|
||||
if (!hide) {
|
||||
hide = true;
|
||||
getAnimator().start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showBottomLayout() {
|
||||
if (hide) {
|
||||
hide = false;
|
||||
getAnimator().reverse();
|
||||
}
|
||||
}
|
||||
|
||||
private ObjectAnimator getAnimator() {
|
||||
if (animator == null) {
|
||||
if (mEnableVerticalLayout) {// 垂直布局向左隐藏
|
||||
animator = ObjectAnimator.ofFloat(
|
||||
OldPageNavigationView.this, "translationX", 0, -OldPageNavigationView.this.getWidth());
|
||||
} else {// 水平布局向下隐藏
|
||||
animator = ObjectAnimator.ofFloat(
|
||||
OldPageNavigationView.this, "translationY", 0, OldPageNavigationView.this.getHeight());
|
||||
}
|
||||
animator.setDuration(300);
|
||||
animator.setInterpolator(new AccelerateDecelerateInterpolator());
|
||||
}
|
||||
return animator;
|
||||
}
|
||||
}
|
||||
|
||||
private class ViewPagerPageChangeListener implements ViewPager.OnPageChangeListener {
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
if (mNavigationController != null && mNavigationController.getSelected() != position) {
|
||||
mNavigationController.setSelect(position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
}
|
||||
}
|
||||
|
||||
private static final String INSTANCE_STATUS = "INSTANCE_STATUS";
|
||||
private final String STATUS_SELECTED = "STATUS_SELECTED";
|
||||
|
||||
@Override
|
||||
protected Parcelable onSaveInstanceState() {
|
||||
if (mNavigationController == null) {
|
||||
return super.onSaveInstanceState();
|
||||
}
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(INSTANCE_STATUS, super.onSaveInstanceState());
|
||||
bundle.putInt(STATUS_SELECTED, mNavigationController.getSelected());
|
||||
return bundle;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Parcelable state) {
|
||||
if (state instanceof Bundle) {
|
||||
Bundle bundle = (Bundle) state;
|
||||
int selected = bundle.getInt(STATUS_SELECTED, 0);
|
||||
super.onRestoreInstanceState(bundle.getParcelable(INSTANCE_STATUS));
|
||||
|
||||
if (selected != 0 && mNavigationController != null) {
|
||||
mNavigationController.setSelect(selected);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
super.onRestoreInstanceState(state);
|
||||
}
|
||||
}
|
||||
+665
@@ -0,0 +1,665 @@
|
||||
package me.majiajie.pagerbottomtabstrip;
|
||||
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import me.majiajie.pagerbottomtabstrip.internal.CustomItemLayout;
|
||||
import me.majiajie.pagerbottomtabstrip.internal.CustomItemVerticalLayout;
|
||||
import me.majiajie.pagerbottomtabstrip.internal.MaterialItemLayout;
|
||||
import me.majiajie.pagerbottomtabstrip.internal.MaterialItemVerticalLayout;
|
||||
import me.majiajie.pagerbottomtabstrip.internal.Utils;
|
||||
import me.majiajie.pagerbottomtabstrip.item.BaseTabItem;
|
||||
import me.majiajie.pagerbottomtabstrip.item.MaterialItemView;
|
||||
import me.majiajie.pagerbottomtabstrip.item.OnlyIconMaterialItemView;
|
||||
import me.majiajie.pagerbottomtabstrip.listener.OnTabItemSelectedListener;
|
||||
|
||||
/**
|
||||
* 导航视图
|
||||
*/
|
||||
public class PageNavigationView extends ViewGroup {
|
||||
private int mTabPaddingTop;
|
||||
private int mTabPaddingBottom;
|
||||
|
||||
private NavigationController mNavigationController;
|
||||
|
||||
private ViewPagerPageChangeListener mPageChangeListener;
|
||||
private ViewPager mViewPager;
|
||||
|
||||
private boolean mEnableVerticalLayout;
|
||||
|
||||
private OnTabItemSelectedListener mTabItemListener = new OnTabItemSelectedListener() {
|
||||
@Override
|
||||
public void onSelected(int index, int old) {
|
||||
if (mViewPager != null) {
|
||||
mViewPager.setCurrentItem(index, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRepeat(int index) {
|
||||
}
|
||||
};
|
||||
|
||||
public PageNavigationView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public PageNavigationView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public PageNavigationView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
setPadding(0, 0, 0, 0);
|
||||
|
||||
final TypedArray a = context.obtainStyledAttributes(
|
||||
attrs, R.styleable.PageNavigationView);
|
||||
if (a.hasValue(R.styleable.PageNavigationView_NavigationPaddingTop)) {
|
||||
mTabPaddingTop = a.getDimensionPixelSize(R.styleable.PageNavigationView_NavigationPaddingTop, 0);
|
||||
}
|
||||
if (a.hasValue(R.styleable.PageNavigationView_NavigationPaddingBottom)) {
|
||||
mTabPaddingBottom = a.getDimensionPixelSize(R.styleable.PageNavigationView_NavigationPaddingBottom, 0);
|
||||
}
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
|
||||
final int count = getChildCount();
|
||||
|
||||
int maxWidth = MeasureSpec.getSize(widthMeasureSpec);
|
||||
int maxHeight = MeasureSpec.getSize(heightMeasureSpec);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() == GONE) {
|
||||
continue;
|
||||
}
|
||||
measureChild(child, widthMeasureSpec,heightMeasureSpec);
|
||||
|
||||
maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
|
||||
maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
|
||||
}
|
||||
|
||||
setMeasuredDimension(maxWidth, maxHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
final int count = getChildCount();
|
||||
final int width = r - l;
|
||||
final int height = b - t;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() == GONE) {
|
||||
continue;
|
||||
}
|
||||
child.layout(0, 0, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CharSequence getAccessibilityClassName() {
|
||||
return PageNavigationView.class.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 Material Desgin 风格的导航栏
|
||||
*/
|
||||
public MaterialBuilder material() {
|
||||
return new MaterialBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建自定义导航栏
|
||||
*/
|
||||
public CustomBuilder custom() {
|
||||
return new CustomBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 自定义 的导航栏
|
||||
*/
|
||||
public class CustomBuilder {
|
||||
|
||||
private List<BaseTabItem> items;
|
||||
|
||||
private boolean enableVerticalLayout = false;
|
||||
private boolean animateLayoutChanges = false;
|
||||
|
||||
CustomBuilder() {
|
||||
items = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 完成构建
|
||||
*
|
||||
* @return {@link NavigationController},通过它进行后续操作
|
||||
* @throws RuntimeException 没有添加导航项时会抛出
|
||||
*/
|
||||
public NavigationController build() {
|
||||
|
||||
mEnableVerticalLayout = enableVerticalLayout;
|
||||
|
||||
//未添加任何按钮
|
||||
if (items.size() == 0) {
|
||||
throw new RuntimeException("must add a navigation item");
|
||||
}
|
||||
|
||||
ItemController itemController;
|
||||
|
||||
if (enableVerticalLayout) {//垂直布局
|
||||
CustomItemVerticalLayout verticalItemLayout = new CustomItemVerticalLayout(getContext());
|
||||
verticalItemLayout.initialize(items, animateLayoutChanges);
|
||||
verticalItemLayout.setPadding(0, mTabPaddingTop, 0, mTabPaddingBottom);
|
||||
|
||||
PageNavigationView.this.removeAllViews();
|
||||
PageNavigationView.this.addView(verticalItemLayout);
|
||||
itemController = verticalItemLayout;
|
||||
} else {//水平布局
|
||||
CustomItemLayout customItemLayout = new CustomItemLayout(getContext());
|
||||
customItemLayout.initialize(items, animateLayoutChanges);
|
||||
customItemLayout.setPadding(0, mTabPaddingTop, 0, mTabPaddingBottom);
|
||||
|
||||
PageNavigationView.this.removeAllViews();
|
||||
PageNavigationView.this.addView(customItemLayout);
|
||||
itemController = customItemLayout;
|
||||
}
|
||||
|
||||
mNavigationController = new NavigationController(new Controller(), itemController);
|
||||
mNavigationController.addTabItemSelectedListener(mTabItemListener);
|
||||
|
||||
return mNavigationController;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个导航按钮
|
||||
*
|
||||
* @param baseTabItem {@link BaseTabItem},所有自定义Item都必须继承它
|
||||
* @return {@link CustomBuilder}
|
||||
*/
|
||||
public CustomBuilder addItem(BaseTabItem baseTabItem) {
|
||||
items.add(baseTabItem);
|
||||
return CustomBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用垂直布局
|
||||
*
|
||||
* @return {@link CustomBuilder}
|
||||
*/
|
||||
public CustomBuilder enableVerticalLayout() {
|
||||
enableVerticalLayout = true;
|
||||
return CustomBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过{@link NavigationController}动态移除/添加导航项时,显示默认的布局动画
|
||||
*
|
||||
* @return {@link CustomBuilder}
|
||||
*/
|
||||
public CustomBuilder enableAnimateLayoutChanges() {
|
||||
animateLayoutChanges = true;
|
||||
return CustomBuilder.this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 Material Desgin 风格的导航栏
|
||||
*/
|
||||
public class MaterialBuilder {
|
||||
|
||||
private final int DEFAULT_COLOR = 0x56000000;
|
||||
|
||||
private List<MaterialItemViewData> itemDatas;
|
||||
private int defaultColor;
|
||||
private int mode;
|
||||
private int messageBackgroundColor;
|
||||
private int messageNumberColor;
|
||||
private boolean enableVerticalLayout = false;
|
||||
private boolean doTintIcon = true;
|
||||
private boolean animateLayoutChanges = false;
|
||||
|
||||
MaterialBuilder() {
|
||||
itemDatas = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 完成构建
|
||||
*
|
||||
* @return {@link NavigationController},通过它进行后续操作
|
||||
* @throws RuntimeException 没有添加导航项时会抛出
|
||||
*/
|
||||
@NonNull
|
||||
public NavigationController build() {
|
||||
mEnableVerticalLayout = enableVerticalLayout;
|
||||
|
||||
// 未添加任何按钮
|
||||
if (itemDatas.isEmpty()) {
|
||||
throw new RuntimeException("must add a navigation item");
|
||||
}
|
||||
|
||||
// 设置默认颜色
|
||||
if (defaultColor == 0) {
|
||||
defaultColor = DEFAULT_COLOR;
|
||||
}
|
||||
|
||||
ItemController itemController;
|
||||
|
||||
if (enableVerticalLayout) {//垂直布局
|
||||
|
||||
List<BaseTabItem> items = new ArrayList<>();
|
||||
|
||||
for (MaterialItemViewData data : itemDatas) {
|
||||
|
||||
OnlyIconMaterialItemView materialItemView = new OnlyIconMaterialItemView(getContext());
|
||||
materialItemView.initialization(data.title, data.drawable, data.checkedDrawable, doTintIcon, defaultColor, data.chekedColor);
|
||||
|
||||
//检查是否设置了消息圆点的颜色
|
||||
if (messageBackgroundColor != 0) {
|
||||
materialItemView.setMessageBackgroundColor(messageBackgroundColor);
|
||||
}
|
||||
|
||||
//检查是否设置了消息数字的颜色
|
||||
if (messageNumberColor != 0) {
|
||||
materialItemView.setMessageNumberColor(messageNumberColor);
|
||||
}
|
||||
|
||||
items.add(materialItemView);
|
||||
}
|
||||
|
||||
MaterialItemVerticalLayout materialItemVerticalLayout = new MaterialItemVerticalLayout(getContext());
|
||||
materialItemVerticalLayout.initialize(items, animateLayoutChanges, doTintIcon, defaultColor);
|
||||
materialItemVerticalLayout.setPadding(0, mTabPaddingTop, 0, mTabPaddingBottom);
|
||||
|
||||
PageNavigationView.this.removeAllViews();
|
||||
PageNavigationView.this.addView(materialItemVerticalLayout);
|
||||
|
||||
itemController = materialItemVerticalLayout;
|
||||
|
||||
} else {//水平布局
|
||||
|
||||
boolean changeBackground = (mode & MaterialMode.CHANGE_BACKGROUND_COLOR) > 0;
|
||||
|
||||
List<MaterialItemView> items = new ArrayList<>();
|
||||
List<Integer> checkedColors = new ArrayList<>();
|
||||
|
||||
for (MaterialItemViewData data : itemDatas) {
|
||||
// 记录设置的选中颜色
|
||||
checkedColors.add(data.chekedColor);
|
||||
|
||||
MaterialItemView materialItemView = new MaterialItemView(getContext());
|
||||
// 初始化Item,需要切换背景颜色就将选中颜色改成白色
|
||||
materialItemView.initialization(data.title, data.drawable, data.checkedDrawable, doTintIcon, defaultColor, changeBackground ? Color.WHITE : data.chekedColor);
|
||||
|
||||
//检查是否设置了消息圆点的颜色
|
||||
if (messageBackgroundColor != 0) {
|
||||
materialItemView.setMessageBackgroundColor(messageBackgroundColor);
|
||||
}
|
||||
|
||||
//检查是否设置了消息数字的颜色
|
||||
if (messageNumberColor != 0) {
|
||||
materialItemView.setMessageNumberColor(messageNumberColor);
|
||||
}
|
||||
|
||||
items.add(materialItemView);
|
||||
}
|
||||
|
||||
MaterialItemLayout materialItemLayout = new MaterialItemLayout(getContext());
|
||||
materialItemLayout.initialize(items, checkedColors, mode, animateLayoutChanges, doTintIcon, defaultColor);
|
||||
materialItemLayout.setPadding(0, mTabPaddingTop, 0, mTabPaddingBottom);
|
||||
|
||||
PageNavigationView.this.removeAllViews();
|
||||
PageNavigationView.this.addView(materialItemLayout);
|
||||
|
||||
itemController = materialItemLayout;
|
||||
}
|
||||
|
||||
mNavigationController = new NavigationController(new Controller(), itemController);
|
||||
mNavigationController.addTabItemSelectedListener(mTabItemListener);
|
||||
|
||||
return mNavigationController;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个导航按钮
|
||||
*
|
||||
* @param drawableRes 图标资源
|
||||
* @param title 显示文字内容.尽量简短
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder addItem(@DrawableRes int drawableRes, @NonNull String title) {
|
||||
addItem(drawableRes, drawableRes, title, Utils.getColorPrimary(getContext()));
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个导航按钮
|
||||
*
|
||||
* @param drawableRes 图标资源
|
||||
* @param checkedDrawableRes 选中时的图标资源
|
||||
* @param title 显示文字内容.尽量简短
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder addItem(@DrawableRes int drawableRes, @DrawableRes int checkedDrawableRes, @NonNull String title) {
|
||||
addItem(drawableRes, checkedDrawableRes, title, Utils.getColorPrimary(getContext()));
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个导航按钮
|
||||
*
|
||||
* @param drawableRes 图标资源
|
||||
* @param title 显示文字内容.尽量简短
|
||||
* @param chekedColor 选中的颜色
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder addItem(@DrawableRes int drawableRes, @NonNull String title, @ColorInt int chekedColor) {
|
||||
addItem(drawableRes, drawableRes, title, chekedColor);
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个导航按钮
|
||||
*
|
||||
* @param drawableRes 图标资源
|
||||
* @param checkedDrawableRes 选中时的图标资源
|
||||
* @param title 显示文字内容.尽量简短
|
||||
* @param chekedColor 选中的颜色
|
||||
* @return {@link MaterialBuilder}
|
||||
* @throws Resources.NotFoundException drawable 资源获取异常
|
||||
*/
|
||||
public MaterialBuilder addItem(@DrawableRes int drawableRes, @DrawableRes int checkedDrawableRes, @NonNull String title, @ColorInt int chekedColor) {
|
||||
Drawable defaultDrawable = ContextCompat.getDrawable(getContext(), drawableRes);
|
||||
Drawable checkDrawable = ContextCompat.getDrawable(getContext(), checkedDrawableRes);
|
||||
if (defaultDrawable == null) {
|
||||
throw new Resources.NotFoundException("Resource ID " + Integer.toHexString(drawableRes));
|
||||
}
|
||||
if (checkDrawable == null) {
|
||||
throw new Resources.NotFoundException("Resource ID " + Integer.toHexString(checkedDrawableRes));
|
||||
}
|
||||
addItem(defaultDrawable, checkDrawable, title, chekedColor);
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个导航按钮
|
||||
*
|
||||
* @param drawable 图标资源
|
||||
* @param title 显示文字内容.尽量简短
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder addItem(@NonNull Drawable drawable, @NonNull String title) {
|
||||
addItem(drawable, drawable, title, Utils.getColorPrimary(getContext()));
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个导航按钮
|
||||
*
|
||||
* @param drawable 图标资源
|
||||
* @param checkedDrawable 选中时的图标资源
|
||||
* @param title 显示文字内容.尽量简短
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder addItem(@NonNull Drawable drawable, @NonNull Drawable checkedDrawable, @NonNull String title) {
|
||||
addItem(drawable, checkedDrawable, title, Utils.getColorPrimary(getContext()));
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个导航按钮
|
||||
*
|
||||
* @param drawable 图标资源
|
||||
* @param title 显示文字内容.尽量简短
|
||||
* @param chekedColor 选中的颜色
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder addItem(@NonNull Drawable drawable, @NonNull String title, @ColorInt int chekedColor) {
|
||||
addItem(drawable, drawable, title, chekedColor);
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个导航按钮
|
||||
*
|
||||
* @param drawable 图标资源
|
||||
* @param checkedDrawable 选中时的图标资源
|
||||
* @param title 显示文字内容.尽量简短
|
||||
* @param chekedColor 选中的颜色
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder addItem(@NonNull Drawable drawable, @NonNull Drawable checkedDrawable, @NonNull String title, @ColorInt int chekedColor) {
|
||||
MaterialItemViewData data = new MaterialItemViewData();
|
||||
data.drawable = Utils.newDrawable(drawable);
|
||||
data.checkedDrawable = Utils.newDrawable(checkedDrawable);
|
||||
data.title = title;
|
||||
data.chekedColor = chekedColor;
|
||||
itemDatas.add(data);
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置导航按钮的默认(未选中状态)颜色
|
||||
*
|
||||
* @param color 16进制整形表示的颜色,例如红色:0xFFFF0000
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder setDefaultColor(@ColorInt int color) {
|
||||
defaultColor = color;
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置消息圆点的颜色
|
||||
*
|
||||
* @param color 16进制整形表示的颜色,例如红色:0xFFFF0000
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder setMessageBackgroundColor(@ColorInt int color) {
|
||||
messageBackgroundColor = color;
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置消息数字的颜色
|
||||
*
|
||||
* @param color 16进制整形表示的颜色,例如红色:0xFFFF0000
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder setMessageNumberColor(@ColorInt int color) {
|
||||
messageNumberColor = color;
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置模式(在垂直布局中无效)。默认文字一直显示,且背景色不变。
|
||||
* 可以通过{@link MaterialMode}选择模式。
|
||||
* <p>例如:</p>
|
||||
* {@code MaterialMode.HIDE_TEXT}
|
||||
* <p>或者多选:</p>
|
||||
* {@code MaterialMode.HIDE_TEXT | MaterialMode.CHANGE_BACKGROUND_COLOR}
|
||||
*
|
||||
* @param mode {@link MaterialMode}
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder setMode(int mode) {
|
||||
MaterialBuilder.this.mode = mode;
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用垂直布局
|
||||
*
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder enableVerticalLayout() {
|
||||
enableVerticalLayout = true;
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 不对图标进行染色
|
||||
*
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder dontTintIcon() {
|
||||
doTintIcon = false;
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过{@link NavigationController}动态移除/添加导航项时,显示默认的布局动画
|
||||
*
|
||||
* @return {@link MaterialBuilder}
|
||||
*/
|
||||
public MaterialBuilder enableAnimateLayoutChanges() {
|
||||
animateLayoutChanges = true;
|
||||
return MaterialBuilder.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 材料设计的单项视图信息
|
||||
*/
|
||||
private static class MaterialItemViewData {
|
||||
Drawable drawable;
|
||||
Drawable checkedDrawable;
|
||||
String title;
|
||||
@ColorInt
|
||||
int chekedColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实现控制接口
|
||||
*/
|
||||
private class Controller implements BottomLayoutController {
|
||||
|
||||
private ObjectAnimator animator;
|
||||
private boolean hide = false;
|
||||
|
||||
@Override
|
||||
public void setupWithViewPager(ViewPager viewPager) {
|
||||
if (viewPager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mViewPager = viewPager;
|
||||
|
||||
if (mPageChangeListener != null) {
|
||||
mViewPager.removeOnPageChangeListener(mPageChangeListener);
|
||||
} else {
|
||||
mPageChangeListener = new ViewPagerPageChangeListener();
|
||||
}
|
||||
|
||||
if (mNavigationController != null) {
|
||||
int n = mViewPager.getCurrentItem();
|
||||
if (mNavigationController.getSelected() != n) {
|
||||
mNavigationController.setSelect(n);
|
||||
}
|
||||
mViewPager.addOnPageChangeListener(mPageChangeListener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideBottomLayout() {
|
||||
if (!hide) {
|
||||
hide = true;
|
||||
getAnimator().start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showBottomLayout() {
|
||||
if (hide) {
|
||||
hide = false;
|
||||
getAnimator().reverse();
|
||||
}
|
||||
}
|
||||
|
||||
private ObjectAnimator getAnimator() {
|
||||
if (animator == null) {
|
||||
if (mEnableVerticalLayout) {// 垂直布局向左隐藏
|
||||
animator = ObjectAnimator.ofFloat(
|
||||
PageNavigationView.this, "translationX", 0, -PageNavigationView.this.getWidth());
|
||||
} else {// 水平布局向下隐藏
|
||||
animator = ObjectAnimator.ofFloat(
|
||||
PageNavigationView.this, "translationY", 0, PageNavigationView.this.getHeight());
|
||||
}
|
||||
animator.setDuration(300);
|
||||
animator.setInterpolator(new AccelerateDecelerateInterpolator());
|
||||
}
|
||||
return animator;
|
||||
}
|
||||
}
|
||||
|
||||
private class ViewPagerPageChangeListener implements ViewPager.OnPageChangeListener {
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
if (mNavigationController != null && mNavigationController.getSelected() != position) {
|
||||
mNavigationController.setSelect(position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
}
|
||||
}
|
||||
|
||||
private static final String INSTANCE_STATUS = "INSTANCE_STATUS";
|
||||
private final String STATUS_SELECTED = "STATUS_SELECTED";
|
||||
|
||||
@Override
|
||||
protected Parcelable onSaveInstanceState() {
|
||||
if (mNavigationController == null) {
|
||||
return super.onSaveInstanceState();
|
||||
}
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(INSTANCE_STATUS, super.onSaveInstanceState());
|
||||
bundle.putInt(STATUS_SELECTED, mNavigationController.getSelected());
|
||||
return bundle;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Parcelable state) {
|
||||
if (state instanceof Bundle) {
|
||||
Bundle bundle = (Bundle) state;
|
||||
int selected = bundle.getInt(STATUS_SELECTED, 0);
|
||||
super.onRestoreInstanceState(bundle.getParcelable(INSTANCE_STATUS));
|
||||
|
||||
if (selected != 0 && mNavigationController != null) {
|
||||
mNavigationController.setSelect(selected);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
super.onRestoreInstanceState(state);
|
||||
}
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
package me.majiajie.pagerbottomtabstrip.internal;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* A simple ViewGroup that aligns all the views inside on a baseline. Note: bottom padding for this
|
||||
* view will be measured starting from the baseline.
|
||||
*/
|
||||
public class BaselineLayout extends ViewGroup {
|
||||
private int mBaseline = -1;
|
||||
|
||||
public BaselineLayout(Context context) {
|
||||
super(context, null, 0);
|
||||
}
|
||||
|
||||
public BaselineLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs, 0);
|
||||
}
|
||||
|
||||
public BaselineLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
final int count = getChildCount();
|
||||
int maxWidth = 0;
|
||||
int maxHeight = 0;
|
||||
int maxChildBaseline = -1;
|
||||
int maxChildDescent = -1;
|
||||
int childState = 0;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() == GONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
measureChild(child, widthMeasureSpec, heightMeasureSpec);
|
||||
final int baseline = child.getBaseline();
|
||||
if (baseline != -1) {
|
||||
maxChildBaseline = Math.max(maxChildBaseline, baseline);
|
||||
maxChildDescent = Math.max(maxChildDescent, child.getMeasuredHeight() - baseline);
|
||||
}
|
||||
maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
|
||||
maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
|
||||
childState = childState | child.getMeasuredState();
|
||||
}
|
||||
if (maxChildBaseline != -1) {
|
||||
maxChildDescent = Math.max(maxChildDescent, getPaddingBottom());
|
||||
maxHeight = Math.max(maxHeight, maxChildBaseline + maxChildDescent);
|
||||
mBaseline = maxChildBaseline;
|
||||
}
|
||||
maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
|
||||
maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
|
||||
setMeasuredDimension(
|
||||
View.resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
|
||||
View.resolveSizeAndState(maxHeight, heightMeasureSpec,
|
||||
childState << MEASURED_HEIGHT_STATE_SHIFT));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
final int count = getChildCount();
|
||||
final int parentLeft = getPaddingLeft();
|
||||
final int parentRight = right - left - getPaddingRight();
|
||||
final int parentContentWidth = parentRight - parentLeft;
|
||||
final int parentTop = getPaddingTop();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() == GONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final int width = child.getMeasuredWidth();
|
||||
final int height = child.getMeasuredHeight();
|
||||
|
||||
final int childLeft = parentLeft + (parentContentWidth - width) / 2;
|
||||
final int childTop;
|
||||
if (mBaseline != -1 && child.getBaseline() != -1) {
|
||||
childTop = parentTop + mBaseline - child.getBaseline();
|
||||
} else {
|
||||
childTop = parentTop;
|
||||
}
|
||||
|
||||
child.layout(childLeft, childTop, childLeft + width, childTop + height);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBaseline() {
|
||||
return mBaseline;
|
||||
}
|
||||
}
|
||||
+277
@@ -0,0 +1,277 @@
|
||||
package me.majiajie.pagerbottomtabstrip.internal;
|
||||
|
||||
|
||||
import android.animation.LayoutTransition;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.core.view.ViewCompat;
|
||||
import me.majiajie.pagerbottomtabstrip.ItemController;
|
||||
import me.majiajie.pagerbottomtabstrip.item.BaseTabItem;
|
||||
import me.majiajie.pagerbottomtabstrip.listener.OnTabItemSelectedListener;
|
||||
import me.majiajie.pagerbottomtabstrip.listener.SimpleTabItemSelectedListener;
|
||||
|
||||
/**
|
||||
* 存放自定义项的布局
|
||||
*/
|
||||
public class CustomItemLayout extends ViewGroup implements ItemController {
|
||||
|
||||
private final List<BaseTabItem> mItems = new ArrayList<>();
|
||||
private final List<OnTabItemSelectedListener> mListeners = new ArrayList<>();
|
||||
private final List<SimpleTabItemSelectedListener> mSimpleListeners = new ArrayList<>();
|
||||
|
||||
private int mSelected = -1;
|
||||
|
||||
public CustomItemLayout(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public CustomItemLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public CustomItemLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
setLayoutTransition(new LayoutTransition());
|
||||
}
|
||||
|
||||
public void initialize(List<BaseTabItem> items, boolean animateLayoutChanges) {
|
||||
mItems.clear();
|
||||
mItems.addAll(items);
|
||||
|
||||
if (animateLayoutChanges) {
|
||||
setLayoutTransition(new LayoutTransition());
|
||||
}
|
||||
|
||||
//添加按钮到布局,并注册点击事件
|
||||
int n = mItems.size();
|
||||
for (int i = 0; i < n; i++) {
|
||||
final BaseTabItem tabItem = mItems.get(i);
|
||||
tabItem.setChecked(false);
|
||||
this.addView(tabItem);
|
||||
|
||||
tabItem.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int index = mItems.indexOf(tabItem);
|
||||
if (index >= 0) {
|
||||
setSelect(index);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//默认选中第一项
|
||||
mSelected = 0;
|
||||
mItems.get(0).setChecked(true);
|
||||
}
|
||||
/**
|
||||
* dip转化像素
|
||||
* @param dipValue
|
||||
* @return
|
||||
*/
|
||||
public static int dip2px(float dipValue){
|
||||
final float scale = Resources.getSystem().getDisplayMetrics().density;
|
||||
return (int)(dipValue * scale + 0.5f);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
|
||||
final int n = getChildCount();
|
||||
int visableChildCount = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (getChildAt(i).getVisibility() != GONE) {
|
||||
visableChildCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (visableChildCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec) / visableChildCount, MeasureSpec.EXACTLY);
|
||||
final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(Math.max(0, MeasureSpec.getSize(heightMeasureSpec) - getPaddingBottom() - getPaddingTop()), MeasureSpec.EXACTLY);
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() == GONE) {
|
||||
continue;
|
||||
}
|
||||
child.measure(widthMeasureSpec, childHeightMeasureSpec);
|
||||
}
|
||||
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
final int count = getChildCount();
|
||||
final int width = right - left;
|
||||
final int height = bottom - top;
|
||||
//只支持top、bottom的padding
|
||||
final int padding_top = getPaddingTop();
|
||||
final int padding_bottom = getPaddingBottom();
|
||||
int used = 0;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() == GONE) {
|
||||
continue;
|
||||
}
|
||||
if (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL) {
|
||||
|
||||
child.layout(width - used - child.getMeasuredWidth(), padding_top, width - used, height - padding_bottom);
|
||||
} else {
|
||||
child.layout(used, padding_top, child.getMeasuredWidth() + used, height - padding_bottom);
|
||||
}
|
||||
used += child.getMeasuredWidth()+dip2px(33);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getAccessibilityClassName() {
|
||||
return CustomItemLayout.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelect(int index) {
|
||||
setSelect(index, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelect(int index, boolean needListener) {
|
||||
|
||||
//重复选择
|
||||
if (index == mSelected) {
|
||||
if (needListener) {
|
||||
for (OnTabItemSelectedListener listener : mListeners) {
|
||||
mItems.get(mSelected).onRepeat();
|
||||
listener.onRepeat(mSelected);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//记录前一个选中项和当前选中项
|
||||
int oldSelected = mSelected;
|
||||
mSelected = index;
|
||||
|
||||
//前一个选中项必须不小于0才有效
|
||||
if (oldSelected >= 0) {
|
||||
mItems.get(oldSelected).setChecked(false);
|
||||
}
|
||||
|
||||
mItems.get(mSelected).setChecked(true);
|
||||
|
||||
if (needListener) {
|
||||
//事件回调
|
||||
for (OnTabItemSelectedListener listener : mListeners) {
|
||||
listener.onSelected(mSelected, oldSelected);
|
||||
}
|
||||
for (SimpleTabItemSelectedListener listener : mSimpleListeners) {
|
||||
listener.onSelected(mSelected, oldSelected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMessageNumber(int index, int number) {
|
||||
mItems.get(index).setMessageNumber(number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHasMessage(int index, boolean hasMessage) {
|
||||
mItems.get(index).setHasMessage(hasMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTabItemSelectedListener(OnTabItemSelectedListener listener) {
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSimpleTabItemSelectedListener(SimpleTabItemSelectedListener listener) {
|
||||
mSimpleListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(int index, String title) {
|
||||
mItems.get(index).setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultDrawable(int index, Drawable drawable) {
|
||||
mItems.get(index).setDefaultDrawable(drawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectedDrawable(int index, Drawable drawable) {
|
||||
mItems.get(index).setSelectedDrawable(drawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSelected() {
|
||||
return mSelected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mItems.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemTitle(int index) {
|
||||
return mItems.get(index).getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeItem(int index) {
|
||||
if (index == mSelected || index >= mItems.size() || index < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mSelected > index) {
|
||||
mSelected--;
|
||||
}
|
||||
|
||||
this.removeViewAt(index);
|
||||
mItems.remove(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMaterialItem(int index, Drawable defaultDrawable, Drawable selectedDrawable, String title, int selectedColor) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCustomItem(int index, final BaseTabItem item) {
|
||||
item.setChecked(false);
|
||||
item.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int index = mItems.indexOf(item);
|
||||
if (index >= 0) {
|
||||
setSelect(index);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (index >= mItems.size()) {
|
||||
mItems.add(index, item);
|
||||
this.addView(item);
|
||||
} else {
|
||||
mItems.add(index, item);
|
||||
this.addView(item, index);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+254
@@ -0,0 +1,254 @@
|
||||
package me.majiajie.pagerbottomtabstrip.internal;
|
||||
|
||||
import android.animation.LayoutTransition;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import me.majiajie.pagerbottomtabstrip.ItemController;
|
||||
import me.majiajie.pagerbottomtabstrip.item.BaseTabItem;
|
||||
import me.majiajie.pagerbottomtabstrip.listener.OnTabItemSelectedListener;
|
||||
import me.majiajie.pagerbottomtabstrip.listener.SimpleTabItemSelectedListener;
|
||||
|
||||
/**
|
||||
* Created by mjj on 2017/9/27
|
||||
*/
|
||||
public class CustomItemVerticalLayout extends ViewGroup implements ItemController {
|
||||
|
||||
private final List<BaseTabItem> mItems = new ArrayList<>();
|
||||
private final List<OnTabItemSelectedListener> mListeners = new ArrayList<>();
|
||||
private final List<SimpleTabItemSelectedListener> mSimpleListeners = new ArrayList<>();
|
||||
|
||||
private int mSelected = -1;
|
||||
|
||||
public CustomItemVerticalLayout(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public CustomItemVerticalLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public CustomItemVerticalLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
setLayoutTransition(new LayoutTransition());
|
||||
}
|
||||
|
||||
public void initialize(List<BaseTabItem> items, boolean animateLayoutChanges) {
|
||||
mItems.clear();
|
||||
mItems.addAll(items);
|
||||
|
||||
if (animateLayoutChanges) {
|
||||
setLayoutTransition(new LayoutTransition());
|
||||
}
|
||||
|
||||
//添加按钮到布局,并注册点击事件
|
||||
int n = mItems.size();
|
||||
for (int i = 0; i < n; i++) {
|
||||
final BaseTabItem tabItem = mItems.get(i);
|
||||
tabItem.setChecked(false);
|
||||
this.addView(tabItem);
|
||||
|
||||
tabItem.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int index = mItems.indexOf(tabItem);
|
||||
if (index >= 0) {
|
||||
setSelect(index);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//默认选中第一项
|
||||
mSelected = 0;
|
||||
mItems.get(0).setChecked(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
final int parentHeightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED);
|
||||
final int childwidthMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY);
|
||||
|
||||
int totalHeight = getPaddingTop() + getPaddingBottom();
|
||||
final int n = getChildCount();
|
||||
for (int i = 0; i < n; i++) {
|
||||
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() == GONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final LayoutParams lp = child.getLayoutParams();
|
||||
final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
|
||||
getPaddingTop() + getPaddingBottom(), lp.height);
|
||||
|
||||
child.measure(childwidthMeasureSpec, childHeightMeasureSpec);
|
||||
|
||||
totalHeight += child.getMeasuredHeight();
|
||||
}
|
||||
|
||||
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), totalHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
|
||||
final int count = getChildCount();
|
||||
//只支持top的padding
|
||||
int used = getPaddingTop();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() == GONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
child.layout(0, used, child.getMeasuredWidth(), used + child.getMeasuredHeight());
|
||||
|
||||
used += child.getMeasuredHeight();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getAccessibilityClassName() {
|
||||
return CustomItemVerticalLayout.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelect(int index) {
|
||||
setSelect(index, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelect(int index, boolean needListener) {
|
||||
|
||||
//重复选择
|
||||
if (index == mSelected) {
|
||||
if (needListener) {
|
||||
for (OnTabItemSelectedListener listener : mListeners) {
|
||||
mItems.get(mSelected).onRepeat();
|
||||
listener.onRepeat(mSelected);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//记录前一个选中项和当前选中项
|
||||
int oldSelected = mSelected;
|
||||
mSelected = index;
|
||||
|
||||
//前一个选中项必须不小于0才有效
|
||||
if (oldSelected >= 0) {
|
||||
mItems.get(oldSelected).setChecked(false);
|
||||
}
|
||||
|
||||
mItems.get(mSelected).setChecked(true);
|
||||
|
||||
if (needListener) {
|
||||
//事件回调
|
||||
for (OnTabItemSelectedListener listener : mListeners) {
|
||||
listener.onSelected(mSelected, oldSelected);
|
||||
}
|
||||
for (SimpleTabItemSelectedListener listener : mSimpleListeners) {
|
||||
listener.onSelected(mSelected, oldSelected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMessageNumber(int index, int number) {
|
||||
mItems.get(index).setMessageNumber(number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHasMessage(int index, boolean hasMessage) {
|
||||
mItems.get(index).setHasMessage(hasMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTabItemSelectedListener(OnTabItemSelectedListener listener) {
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSimpleTabItemSelectedListener(SimpleTabItemSelectedListener listener) {
|
||||
mSimpleListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(int index, String title) {
|
||||
mItems.get(index).setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultDrawable(int index, Drawable drawable) {
|
||||
mItems.get(index).setDefaultDrawable(drawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectedDrawable(int index, Drawable drawable) {
|
||||
mItems.get(index).setSelectedDrawable(drawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSelected() {
|
||||
return mSelected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mItems.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemTitle(int index) {
|
||||
return mItems.get(index).getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeItem(int index) {
|
||||
if (index == mSelected || index >= mItems.size() || index < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mSelected > index) {
|
||||
mSelected--;
|
||||
}
|
||||
|
||||
this.removeViewAt(index);
|
||||
mItems.remove(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMaterialItem(int index, Drawable defaultDrawable, Drawable selectedDrawable, String title, int selectedColor) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCustomItem(int index,final BaseTabItem item) {
|
||||
item.setChecked(false);
|
||||
item.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int index = mItems.indexOf(item);
|
||||
if (index >= 0) {
|
||||
setSelect(index);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (index >= mItems.size()) {
|
||||
mItems.add(index, item);
|
||||
this.addView(item);
|
||||
} else {
|
||||
mItems.add(index, item);
|
||||
this.addView(item, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
+549
@@ -0,0 +1,549 @@
|
||||
package me.majiajie.pagerbottomtabstrip.internal;
|
||||
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.LayoutTransition;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.RippleDrawable;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.core.view.ViewCompat;
|
||||
import me.majiajie.pagerbottomtabstrip.ItemController;
|
||||
import me.majiajie.pagerbottomtabstrip.MaterialMode;
|
||||
import me.majiajie.pagerbottomtabstrip.R;
|
||||
import me.majiajie.pagerbottomtabstrip.item.BaseTabItem;
|
||||
import me.majiajie.pagerbottomtabstrip.item.MaterialItemView;
|
||||
import me.majiajie.pagerbottomtabstrip.listener.OnTabItemSelectedListener;
|
||||
import me.majiajie.pagerbottomtabstrip.listener.SimpleTabItemSelectedListener;
|
||||
|
||||
/**
|
||||
* 存放 Material Design 风格按钮的水平布局
|
||||
*/
|
||||
public class MaterialItemLayout extends ViewGroup implements ItemController {
|
||||
|
||||
private final int DEFAULT_SELECTED = 0;
|
||||
|
||||
private final int MATERIAL_BOTTOM_NAVIGATION_ACTIVE_ITEM_MAX_WIDTH;
|
||||
private final int MATERIAL_BOTTOM_NAVIGATION_ITEM_MAX_WIDTH;
|
||||
private final int MATERIAL_BOTTOM_NAVIGATION_ITEM_MIN_WIDTH;
|
||||
private final int MATERIAL_BOTTOM_NAVIGATION_ITEM_HEIGHT;
|
||||
|
||||
private final List<MaterialItemView> mItems = new ArrayList<>();
|
||||
private final List<OnTabItemSelectedListener> mListeners = new ArrayList<>();
|
||||
private final List<SimpleTabItemSelectedListener> mSimpleListeners = new ArrayList<>();
|
||||
|
||||
private boolean mItemTintIcon;
|
||||
private int mItemDefaultColor;
|
||||
|
||||
private int[] mTempChildWidths;
|
||||
private int mItemTotalWidth;
|
||||
|
||||
private int mSelected = -1;
|
||||
private int mOldSelected = -1;
|
||||
|
||||
private boolean mHideTitle;
|
||||
|
||||
//切换背景颜色时使用
|
||||
private final int ANIM_TIME = 300;
|
||||
private Interpolator mInterpolator;
|
||||
private boolean mChangeBackgroundMode;
|
||||
private List<Integer> mBackgroundColors;
|
||||
private List<Oval> mOvals;
|
||||
private RectF mTempRectF;
|
||||
private Paint mPaint;
|
||||
|
||||
//最后手指抬起的坐标
|
||||
private float mLastUpX;
|
||||
private float mLastUpY;
|
||||
|
||||
public MaterialItemLayout(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public MaterialItemLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public MaterialItemLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
|
||||
final Resources res = getResources();
|
||||
|
||||
MATERIAL_BOTTOM_NAVIGATION_ACTIVE_ITEM_MAX_WIDTH = res.getDimensionPixelSize(R.dimen.material_bottom_navigation_active_item_max_width);
|
||||
MATERIAL_BOTTOM_NAVIGATION_ITEM_MAX_WIDTH = res.getDimensionPixelSize(R.dimen.material_bottom_navigation_item_max_width);
|
||||
MATERIAL_BOTTOM_NAVIGATION_ITEM_MIN_WIDTH = res.getDimensionPixelSize(R.dimen.material_bottom_navigation_item_min_width);
|
||||
MATERIAL_BOTTOM_NAVIGATION_ITEM_HEIGHT = res.getDimensionPixelSize(R.dimen.material_bottom_navigation_height);
|
||||
|
||||
//材料设计规范限制最多只能有5个导航按钮
|
||||
mTempChildWidths = new int[5];
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化方法
|
||||
*
|
||||
* @param items 按钮集合
|
||||
* @param checkedColors 选中颜色的集合
|
||||
* @param mode {@link MaterialMode}
|
||||
* @param animateLayoutChanges 是否应用默认的布局动画
|
||||
* @param doTintIcon item是否需要对图标染色
|
||||
* @param color item的默认状态颜色
|
||||
*/
|
||||
public void initialize(List<MaterialItemView> items, List<Integer> checkedColors, int mode, boolean animateLayoutChanges, boolean doTintIcon, int color) {
|
||||
|
||||
if (animateLayoutChanges) {
|
||||
setLayoutTransition(new LayoutTransition());
|
||||
}
|
||||
|
||||
mItems.clear();
|
||||
mItems.addAll(items);
|
||||
|
||||
mItemTintIcon = doTintIcon;
|
||||
mItemDefaultColor = color;
|
||||
|
||||
//判断是否需要切换背景
|
||||
if ((mode & MaterialMode.CHANGE_BACKGROUND_COLOR) > 0) {
|
||||
//初始化一些成员变量
|
||||
mChangeBackgroundMode = true;
|
||||
mOvals = new ArrayList<>();
|
||||
mBackgroundColors = checkedColors;
|
||||
mInterpolator = new AccelerateDecelerateInterpolator();
|
||||
mTempRectF = new RectF();
|
||||
mPaint = new Paint();
|
||||
|
||||
//设置默认的背景
|
||||
setBackgroundColor(mBackgroundColors.get(DEFAULT_SELECTED));
|
||||
} else {
|
||||
//设置按钮点击效果
|
||||
for (int i = 0; i < mItems.size(); i++) {
|
||||
MaterialItemView v = mItems.get(i);
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
v.setBackground(new RippleDrawable(new ColorStateList(new int[][]{{}}, new int[]{0xFFFFFF & checkedColors.get(i) | 0x56000000}), null, null));
|
||||
} else {
|
||||
v.setBackgroundResource(R.drawable.material_item_background);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//判断是否隐藏文字
|
||||
if ((mode & MaterialMode.HIDE_TEXT) > 0) {
|
||||
mHideTitle = true;
|
||||
for (MaterialItemView v : mItems) {
|
||||
v.setHideTitle(true);
|
||||
}
|
||||
}
|
||||
|
||||
//添加按钮到布局,并注册点击事件
|
||||
int n = mItems.size();
|
||||
for (int i = 0; i < n; i++) {
|
||||
final MaterialItemView tabItem = mItems.get(i);
|
||||
tabItem.setChecked(false);
|
||||
this.addView(tabItem);
|
||||
|
||||
tabItem.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int index = mItems.indexOf(tabItem);
|
||||
if (index >= 0) {
|
||||
setSelect(index, mLastUpX, mLastUpY, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//默认选中第一项
|
||||
mSelected = DEFAULT_SELECTED;
|
||||
mItems.get(DEFAULT_SELECTED).setChecked(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
//排除空状态
|
||||
if (mItems == null || mItems.size() <= 0) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
return;
|
||||
}
|
||||
|
||||
final int width = MeasureSpec.getSize(widthMeasureSpec);
|
||||
final int count = getChildCount();
|
||||
|
||||
final int heightSpec = MeasureSpec.makeMeasureSpec(MATERIAL_BOTTOM_NAVIGATION_ITEM_HEIGHT, MeasureSpec.EXACTLY);
|
||||
|
||||
if (mHideTitle) {
|
||||
final int inactiveCount = count - 1;
|
||||
final int activeMaxAvailable = width - inactiveCount * MATERIAL_BOTTOM_NAVIGATION_ITEM_MIN_WIDTH;
|
||||
final int activeWidth = Math.min(activeMaxAvailable, MATERIAL_BOTTOM_NAVIGATION_ACTIVE_ITEM_MAX_WIDTH);
|
||||
final int inactiveMaxAvailable = inactiveCount == 0 ? 0 : (width - activeWidth) / inactiveCount;
|
||||
final int inactiveWidth = Math.min(inactiveMaxAvailable, MATERIAL_BOTTOM_NAVIGATION_ITEM_MAX_WIDTH);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (i == mSelected) {
|
||||
mTempChildWidths[i] = (int) ((activeWidth - inactiveWidth) * mItems.get(mSelected).getAnimValue() + inactiveWidth);
|
||||
} else if (i == mOldSelected) {
|
||||
mTempChildWidths[i] = (int) (activeWidth - (activeWidth - inactiveWidth) * mItems.get(mSelected).getAnimValue());
|
||||
} else {
|
||||
mTempChildWidths[i] = inactiveWidth;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final int maxAvailable = width / (count == 0 ? 1 : count);
|
||||
final int childWidth = Math.min(maxAvailable, MATERIAL_BOTTOM_NAVIGATION_ACTIVE_ITEM_MAX_WIDTH);
|
||||
for (int i = 0; i < count; i++) {
|
||||
mTempChildWidths[i] = childWidth;
|
||||
}
|
||||
}
|
||||
|
||||
mItemTotalWidth = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() == GONE) {
|
||||
continue;
|
||||
}
|
||||
child.measure(MeasureSpec.makeMeasureSpec(mTempChildWidths[i], MeasureSpec.EXACTLY),
|
||||
heightSpec);
|
||||
ViewGroup.LayoutParams params = child.getLayoutParams();
|
||||
params.width = child.getMeasuredWidth();
|
||||
mItemTotalWidth += child.getMeasuredWidth();
|
||||
}
|
||||
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
final int count = getChildCount();
|
||||
final int width = right - left;
|
||||
final int height = bottom - top;
|
||||
//只支持top、bottom的padding
|
||||
final int padding_top = getPaddingTop();
|
||||
final int padding_bottom = getPaddingBottom();
|
||||
int used = 0;
|
||||
|
||||
if (mItemTotalWidth > 0 && mItemTotalWidth < width) {
|
||||
used = (width - mItemTotalWidth) / 2;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() == GONE) {
|
||||
continue;
|
||||
}
|
||||
if (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL) {
|
||||
child.layout(width - used - child.getMeasuredWidth(), padding_top, width - used, height - padding_bottom);
|
||||
} else {
|
||||
child.layout(used, padding_top, child.getMeasuredWidth() + used, height - padding_bottom);
|
||||
}
|
||||
used += child.getMeasuredWidth();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
if (mChangeBackgroundMode) {
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
|
||||
Iterator<Oval> iterator = mOvals.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Oval oval = iterator.next();
|
||||
mPaint.setColor(oval.color);
|
||||
if (oval.r < oval.maxR) {
|
||||
mTempRectF.set(oval.getLeft(), oval.getTop(), oval.getRight(), oval.getBottom());
|
||||
canvas.drawOval(mTempRectF, mPaint);
|
||||
} else {
|
||||
this.setBackgroundColor(oval.color);
|
||||
canvas.drawRect(0, 0, width, height, mPaint);
|
||||
iterator.remove();
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
|
||||
if (ev.getAction() == MotionEvent.ACTION_UP) {
|
||||
mLastUpX = ev.getX();
|
||||
mLastUpY = ev.getY();
|
||||
}
|
||||
|
||||
return super.onInterceptTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getAccessibilityClassName() {
|
||||
return MaterialItemLayout.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelect(int index) {
|
||||
setSelect(index, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelect(int index, boolean needListener) {
|
||||
// 不正常的选择项
|
||||
if (index >= mItems.size() || index < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
View v = mItems.get(index);
|
||||
setSelect(index, v.getX() + v.getWidth() / 2f, v.getY() + v.getHeight() / 2f, needListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMessageNumber(int index, int number) {
|
||||
mItems.get(index).setMessageNumber(number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHasMessage(int index, boolean hasMessage) {
|
||||
mItems.get(index).setHasMessage(hasMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTabItemSelectedListener(OnTabItemSelectedListener listener) {
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSimpleTabItemSelectedListener(SimpleTabItemSelectedListener listener) {
|
||||
mSimpleListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(int index, String title) {
|
||||
mItems.get(index).setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultDrawable(int index, Drawable drawable) {
|
||||
mItems.get(index).setDefaultDrawable(drawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectedDrawable(int index, Drawable drawable) {
|
||||
mItems.get(index).setSelectedDrawable(drawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSelected() {
|
||||
return mSelected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mItems.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemTitle(int index) {
|
||||
return mItems.get(index).getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeItem(int index) {
|
||||
if (index == mSelected || index >= mItems.size() || index < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mSelected > index) {
|
||||
mSelected--;
|
||||
}
|
||||
|
||||
this.removeViewAt(index);
|
||||
mItems.remove(index);
|
||||
if (mChangeBackgroundMode) {
|
||||
mBackgroundColors.remove(index);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMaterialItem(int index, Drawable defaultDrawable, Drawable selectedDrawable, String title, int selectedColor) {
|
||||
|
||||
final MaterialItemView materialItemView = new MaterialItemView(getContext());
|
||||
materialItemView.initialization(title, defaultDrawable, selectedDrawable, mItemTintIcon, mItemDefaultColor, mChangeBackgroundMode ? Color.WHITE : selectedColor);
|
||||
|
||||
materialItemView.setChecked(false);
|
||||
materialItemView.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int index = mItems.indexOf(materialItemView);
|
||||
if (index >= 0) {
|
||||
setSelect(index);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (mHideTitle) {
|
||||
// 隐藏文字
|
||||
materialItemView.setHideTitle(true);
|
||||
}
|
||||
|
||||
if (mSelected >= index){
|
||||
mSelected++;
|
||||
}
|
||||
|
||||
if (index >= mItems.size()) {
|
||||
if (mChangeBackgroundMode) {
|
||||
mBackgroundColors.add(selectedColor);
|
||||
}
|
||||
mItems.add(materialItemView);
|
||||
this.addView(materialItemView);
|
||||
|
||||
} else {
|
||||
if (mChangeBackgroundMode) {
|
||||
mBackgroundColors.add(index, selectedColor);
|
||||
}
|
||||
mItems.add(index, materialItemView);
|
||||
this.addView(materialItemView, index);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCustomItem(int index, BaseTabItem item) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
private void setSelect(int index, float x, float y, boolean needListener) {
|
||||
|
||||
//重复选择
|
||||
if (index == mSelected) {
|
||||
if (needListener) {
|
||||
for (OnTabItemSelectedListener listener : mListeners) {
|
||||
listener.onRepeat(mSelected);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//记录前一个选中项和当前选中项
|
||||
mOldSelected = mSelected;
|
||||
mSelected = index;
|
||||
|
||||
//切换背景颜色
|
||||
if (mChangeBackgroundMode) {
|
||||
addOvalColor(mBackgroundColors.get(mSelected), x, y);
|
||||
}
|
||||
|
||||
//前一个选中项必须不小于0才有效
|
||||
if (mOldSelected >= 0) {
|
||||
mItems.get(mOldSelected).setChecked(false);
|
||||
}
|
||||
|
||||
mItems.get(mSelected).setChecked(true);
|
||||
|
||||
if (needListener) {
|
||||
//事件回调
|
||||
for (OnTabItemSelectedListener listener : mListeners) {
|
||||
listener.onSelected(mSelected, mOldSelected);
|
||||
}
|
||||
for (SimpleTabItemSelectedListener listener : mSimpleListeners) {
|
||||
listener.onSelected(mSelected, mOldSelected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个圆形波纹动画
|
||||
*
|
||||
* @param color 颜色
|
||||
* @param x X座标
|
||||
* @param y y座标
|
||||
*/
|
||||
private void addOvalColor(int color, float x, float y) {
|
||||
final Oval oval = new Oval(color, 2, x, y);
|
||||
|
||||
oval.maxR = getR(x, y);
|
||||
mOvals.add(oval);
|
||||
|
||||
ValueAnimator valueAnimator = ValueAnimator.ofFloat(oval.r, oval.maxR);
|
||||
valueAnimator.setInterpolator(mInterpolator);
|
||||
valueAnimator.setDuration(ANIM_TIME);
|
||||
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator valueAnimator) {
|
||||
oval.r = (float) valueAnimator.getAnimatedValue();
|
||||
}
|
||||
});
|
||||
valueAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
super.onAnimationStart(animation);
|
||||
invalidate();
|
||||
}
|
||||
});
|
||||
valueAnimator.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* 以矩形内一点为圆心画圆,覆盖矩形,求这个圆的最小半径
|
||||
*
|
||||
* @param x 横坐标
|
||||
* @param y 纵坐标
|
||||
* @return 最小半径
|
||||
*/
|
||||
private float getR(float x, float y) {
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
|
||||
double r1_square = x * x + y * y;
|
||||
double r2_square = (width - x) * (width - x) + y * y;
|
||||
double r3_square = (width - x) * (width - x) + (height - y) * (height - y);
|
||||
double r4_square = x * x + (height - y) * (height - y);
|
||||
|
||||
return (float) Math.sqrt(Math.max(Math.max(r1_square, r2_square), Math.max(r3_square, r4_square)));
|
||||
}
|
||||
|
||||
private class Oval {
|
||||
int color;
|
||||
float r;
|
||||
float x;
|
||||
float y;
|
||||
float maxR;
|
||||
|
||||
Oval(int color, float r, float x, float y) {
|
||||
this.color = color;
|
||||
this.r = r;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
float getLeft() {
|
||||
return x - r;
|
||||
}
|
||||
|
||||
float getTop() {
|
||||
return y - r;
|
||||
}
|
||||
|
||||
float getRight() {
|
||||
return x + r;
|
||||
}
|
||||
|
||||
float getBottom() {
|
||||
return y + r;
|
||||
}
|
||||
}
|
||||
}
|
||||
+261
@@ -0,0 +1,261 @@
|
||||
package me.majiajie.pagerbottomtabstrip.internal;
|
||||
|
||||
import android.animation.LayoutTransition;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import me.majiajie.pagerbottomtabstrip.ItemController;
|
||||
import me.majiajie.pagerbottomtabstrip.R;
|
||||
import me.majiajie.pagerbottomtabstrip.item.BaseTabItem;
|
||||
import me.majiajie.pagerbottomtabstrip.item.OnlyIconMaterialItemView;
|
||||
import me.majiajie.pagerbottomtabstrip.listener.OnTabItemSelectedListener;
|
||||
import me.majiajie.pagerbottomtabstrip.listener.SimpleTabItemSelectedListener;
|
||||
|
||||
/**
|
||||
* 存放 Material Design 风格按钮的垂直布局
|
||||
*/
|
||||
public class MaterialItemVerticalLayout extends ViewGroup implements ItemController {
|
||||
|
||||
private final int NAVIGATION_ITEM_SIZE;
|
||||
|
||||
private final List<BaseTabItem> mItems = new ArrayList<>();
|
||||
private final List<OnTabItemSelectedListener> mListeners = new ArrayList<>();
|
||||
private final List<SimpleTabItemSelectedListener> mSimpleListeners = new ArrayList<>();
|
||||
|
||||
private int mSelected = -1;
|
||||
|
||||
private boolean mItemTintIcon;
|
||||
private int mItemDefaultColor;
|
||||
|
||||
public MaterialItemVerticalLayout(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public MaterialItemVerticalLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public MaterialItemVerticalLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
|
||||
NAVIGATION_ITEM_SIZE = getResources().getDimensionPixelSize(R.dimen.material_bottom_navigation_height);
|
||||
}
|
||||
|
||||
public void initialize(List<BaseTabItem> items, boolean animateLayoutChanges, boolean doTintIcon, int color) {
|
||||
|
||||
mItems.clear();
|
||||
mItems.addAll(items);
|
||||
|
||||
mItemTintIcon = doTintIcon;
|
||||
mItemDefaultColor = color;
|
||||
|
||||
if (animateLayoutChanges) {
|
||||
setLayoutTransition(new LayoutTransition());
|
||||
}
|
||||
|
||||
//添加按钮到布局,并注册点击事件
|
||||
int n = mItems.size();
|
||||
for (int i = 0; i < n; i++) {
|
||||
final BaseTabItem tabItem = mItems.get(i);
|
||||
tabItem.setChecked(false);
|
||||
this.addView(tabItem);
|
||||
|
||||
tabItem.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int index = mItems.indexOf(tabItem);
|
||||
if (index >= 0) {
|
||||
setSelect(index);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//默认选中第一项
|
||||
mSelected = 0;
|
||||
mItems.get(0).setChecked(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
|
||||
final int n = getChildCount();
|
||||
|
||||
final int heightSpec = MeasureSpec.makeMeasureSpec(NAVIGATION_ITEM_SIZE, MeasureSpec.EXACTLY);
|
||||
final int widthSpec = MeasureSpec.makeMeasureSpec(NAVIGATION_ITEM_SIZE, MeasureSpec.EXACTLY);
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() == GONE) {
|
||||
continue;
|
||||
}
|
||||
child.measure(widthSpec, heightSpec);
|
||||
}
|
||||
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
final int count = getChildCount();
|
||||
//只支持top的padding
|
||||
int used = getPaddingTop();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() == GONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
child.layout(0, used, child.getMeasuredWidth(), used + child.getMeasuredHeight());
|
||||
|
||||
used += child.getMeasuredHeight();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getAccessibilityClassName() {
|
||||
return MaterialItemVerticalLayout.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelect(int index) {
|
||||
setSelect(index, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelect(int index, boolean needListener) {
|
||||
//重复选择
|
||||
if (index == mSelected) {
|
||||
if (needListener) {
|
||||
for (OnTabItemSelectedListener listener : mListeners) {
|
||||
listener.onRepeat(mSelected);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//记录前一个选中项和当前选中项
|
||||
int oldSelected = mSelected;
|
||||
mSelected = index;
|
||||
|
||||
//前一个选中项必须不小于0才有效
|
||||
if (oldSelected >= 0) {
|
||||
mItems.get(oldSelected).setChecked(false);
|
||||
}
|
||||
|
||||
mItems.get(mSelected).setChecked(true);
|
||||
|
||||
if (needListener) {
|
||||
//事件回调
|
||||
for (OnTabItemSelectedListener listener : mListeners) {
|
||||
listener.onSelected(mSelected, oldSelected);
|
||||
}
|
||||
for (SimpleTabItemSelectedListener listener : mSimpleListeners) {
|
||||
listener.onSelected(mSelected, oldSelected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMessageNumber(int index, int number) {
|
||||
mItems.get(index).setMessageNumber(number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHasMessage(int index, boolean hasMessage) {
|
||||
mItems.get(index).setHasMessage(hasMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTabItemSelectedListener(OnTabItemSelectedListener listener) {
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSimpleTabItemSelectedListener(SimpleTabItemSelectedListener listener) {
|
||||
mSimpleListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(int index, String title) {
|
||||
mItems.get(index).setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultDrawable(int index, Drawable drawable) {
|
||||
mItems.get(index).setDefaultDrawable(drawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectedDrawable(int index, Drawable drawable) {
|
||||
mItems.get(index).setSelectedDrawable(drawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSelected() {
|
||||
return mSelected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mItems.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemTitle(int index) {
|
||||
return mItems.get(index).getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeItem(int index) {
|
||||
if (index == mSelected || index >= mItems.size() || index < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mSelected > index) {
|
||||
mSelected--;
|
||||
}
|
||||
|
||||
this.removeViewAt(index);
|
||||
mItems.remove(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMaterialItem(int index, Drawable defaultDrawable, Drawable selectedDrawable, String title, int selectedColor) {
|
||||
|
||||
final OnlyIconMaterialItemView materialItemView = new OnlyIconMaterialItemView(getContext());
|
||||
materialItemView.initialization(title, defaultDrawable, selectedDrawable, mItemTintIcon, mItemDefaultColor, selectedColor);
|
||||
|
||||
materialItemView.setChecked(false);
|
||||
materialItemView.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int index = mItems.indexOf(materialItemView);
|
||||
if (index >= 0) {
|
||||
setSelect(index);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (index >= mItems.size()) {
|
||||
this.addView(materialItemView);
|
||||
mItems.add(materialItemView);
|
||||
} else {
|
||||
this.addView(materialItemView, index);
|
||||
mItems.add(index, materialItemView);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCustomItem(int index, BaseTabItem item) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
+266
@@ -0,0 +1,266 @@
|
||||
package me.majiajie.pagerbottomtabstrip.internal;
|
||||
|
||||
|
||||
import android.animation.LayoutTransition;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.core.view.ViewCompat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import me.majiajie.pagerbottomtabstrip.ItemController;
|
||||
import me.majiajie.pagerbottomtabstrip.item.BaseTabItem;
|
||||
import me.majiajie.pagerbottomtabstrip.listener.OnTabItemSelectedListener;
|
||||
import me.majiajie.pagerbottomtabstrip.listener.SimpleTabItemSelectedListener;
|
||||
|
||||
/**
|
||||
* 存放自定义项的布局
|
||||
*/
|
||||
public class OldCustomItemLayout extends ViewGroup implements ItemController {
|
||||
|
||||
private final List<BaseTabItem> mItems = new ArrayList<>();
|
||||
private final List<OnTabItemSelectedListener> mListeners = new ArrayList<>();
|
||||
private final List<SimpleTabItemSelectedListener> mSimpleListeners = new ArrayList<>();
|
||||
|
||||
private int mSelected = -1;
|
||||
|
||||
public OldCustomItemLayout(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public OldCustomItemLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public OldCustomItemLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
setLayoutTransition(new LayoutTransition());
|
||||
}
|
||||
|
||||
public void initialize(List<BaseTabItem> items, boolean animateLayoutChanges) {
|
||||
mItems.clear();
|
||||
mItems.addAll(items);
|
||||
|
||||
if (animateLayoutChanges) {
|
||||
setLayoutTransition(new LayoutTransition());
|
||||
}
|
||||
|
||||
//添加按钮到布局,并注册点击事件
|
||||
int n = mItems.size();
|
||||
for (int i = 0; i < n; i++) {
|
||||
final BaseTabItem tabItem = mItems.get(i);
|
||||
tabItem.setChecked(false);
|
||||
this.addView(tabItem);
|
||||
|
||||
tabItem.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int index = mItems.indexOf(tabItem);
|
||||
if (index >= 0) {
|
||||
setSelect(index);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//默认选中第一项
|
||||
mSelected = 0;
|
||||
mItems.get(0).setChecked(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
|
||||
final int n = getChildCount();
|
||||
int visableChildCount = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (getChildAt(i).getVisibility() != GONE) {
|
||||
visableChildCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (visableChildCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec) / visableChildCount, MeasureSpec.EXACTLY);
|
||||
final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(Math.max(0, MeasureSpec.getSize(heightMeasureSpec) - getPaddingBottom() - getPaddingTop()), MeasureSpec.EXACTLY);
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() == GONE) {
|
||||
continue;
|
||||
}
|
||||
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
|
||||
}
|
||||
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
final int count = getChildCount();
|
||||
final int width = right - left;
|
||||
final int height = bottom - top;
|
||||
//只支持top、bottom的padding
|
||||
final int padding_top = getPaddingTop();
|
||||
final int padding_bottom = getPaddingBottom();
|
||||
int used = 0;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() == GONE) {
|
||||
continue;
|
||||
}
|
||||
if (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL) {
|
||||
child.layout(width - used - child.getMeasuredWidth(), padding_top, width - used, height - padding_bottom);
|
||||
} else {
|
||||
child.layout(used, padding_top, child.getMeasuredWidth() + used, height - padding_bottom);
|
||||
}
|
||||
used += child.getMeasuredWidth();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getAccessibilityClassName() {
|
||||
return CustomItemLayout.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelect(int index) {
|
||||
setSelect(index, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelect(int index, boolean needListener) {
|
||||
|
||||
//重复选择
|
||||
if (index == mSelected) {
|
||||
if (needListener) {
|
||||
for (OnTabItemSelectedListener listener : mListeners) {
|
||||
mItems.get(mSelected).onRepeat();
|
||||
listener.onRepeat(mSelected);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//记录前一个选中项和当前选中项
|
||||
int oldSelected = mSelected;
|
||||
mSelected = index;
|
||||
|
||||
//前一个选中项必须不小于0才有效
|
||||
if (oldSelected >= 0) {
|
||||
mItems.get(oldSelected).setChecked(false);
|
||||
}
|
||||
|
||||
mItems.get(mSelected).setChecked(true);
|
||||
|
||||
if (needListener) {
|
||||
//事件回调
|
||||
for (OnTabItemSelectedListener listener : mListeners) {
|
||||
listener.onSelected(mSelected, oldSelected);
|
||||
}
|
||||
for (SimpleTabItemSelectedListener listener : mSimpleListeners) {
|
||||
listener.onSelected(mSelected, oldSelected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMessageNumber(int index, int number) {
|
||||
mItems.get(index).setMessageNumber(number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHasMessage(int index, boolean hasMessage) {
|
||||
mItems.get(index).setHasMessage(hasMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTabItemSelectedListener(OnTabItemSelectedListener listener) {
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSimpleTabItemSelectedListener(SimpleTabItemSelectedListener listener) {
|
||||
mSimpleListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(int index, String title) {
|
||||
mItems.get(index).setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultDrawable(int index, Drawable drawable) {
|
||||
mItems.get(index).setDefaultDrawable(drawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectedDrawable(int index, Drawable drawable) {
|
||||
mItems.get(index).setSelectedDrawable(drawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSelected() {
|
||||
return mSelected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mItems.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemTitle(int index) {
|
||||
return mItems.get(index).getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeItem(int index) {
|
||||
if (index == mSelected || index >= mItems.size() || index < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mSelected > index) {
|
||||
mSelected--;
|
||||
}
|
||||
|
||||
this.removeViewAt(index);
|
||||
mItems.remove(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMaterialItem(int index, Drawable defaultDrawable, Drawable selectedDrawable, String title, int selectedColor) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCustomItem(int index, final BaseTabItem item) {
|
||||
item.setChecked(false);
|
||||
item.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int index = mItems.indexOf(item);
|
||||
if (index >= 0) {
|
||||
setSelect(index);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (index >= mItems.size()) {
|
||||
mItems.add(index, item);
|
||||
this.addView(item);
|
||||
} else {
|
||||
mItems.add(index, item);
|
||||
this.addView(item, index);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
package me.majiajie.pagerbottomtabstrip.internal;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.view.ViewCompat;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import me.majiajie.pagerbottomtabstrip.R;
|
||||
|
||||
|
||||
public class RoundMessageView extends FrameLayout {
|
||||
private final View mOval;
|
||||
private final TextView mMessages;
|
||||
|
||||
private int mMessageNumber;
|
||||
private boolean mHasMessage;
|
||||
|
||||
public RoundMessageView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public RoundMessageView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public RoundMessageView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
LayoutInflater.from(context).inflate(R.layout.round_message_view, this, true);
|
||||
|
||||
mOval = findViewById(R.id.oval);
|
||||
mMessages = findViewById(R.id.msg);
|
||||
mMessages.setTypeface(Typeface.DEFAULT_BOLD);
|
||||
mMessages.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 10);
|
||||
}
|
||||
|
||||
public void setMessageNumber(int number) {
|
||||
mMessageNumber = number;
|
||||
|
||||
if (mMessageNumber > 0) {
|
||||
mOval.setVisibility(View.INVISIBLE);
|
||||
mMessages.setVisibility(View.VISIBLE);
|
||||
|
||||
if (mMessageNumber < 10) {
|
||||
mMessages.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 10);
|
||||
} else {
|
||||
mMessages.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 8);
|
||||
}
|
||||
|
||||
if (mMessageNumber <= 99) {
|
||||
mMessages.setText(String.format(Locale.ENGLISH, "%d", mMessageNumber));
|
||||
} else {
|
||||
mMessages.setText(String.format(Locale.ENGLISH, "%d+", 99));
|
||||
}
|
||||
} else {
|
||||
mMessages.setVisibility(View.INVISIBLE);
|
||||
if (mHasMessage) {
|
||||
mOval.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setHasMessage(boolean hasMessage) {
|
||||
mHasMessage = hasMessage;
|
||||
|
||||
if (hasMessage) {
|
||||
mOval.setVisibility(mMessageNumber > 0 ? View.INVISIBLE : View.VISIBLE);
|
||||
} else {
|
||||
mOval.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
public void tintMessageBackground(@ColorInt int color) {
|
||||
Drawable drawable = Utils.tinting(ContextCompat.getDrawable(getContext(), R.drawable.round), color);
|
||||
ViewCompat.setBackground(mOval, drawable);
|
||||
ViewCompat.setBackground(mMessages, drawable);
|
||||
}
|
||||
|
||||
public void setMessageNumberColor(@ColorInt int color) {
|
||||
mMessages.setTextColor(color);
|
||||
}
|
||||
|
||||
public int getMessageNumber() {
|
||||
return mMessageNumber;
|
||||
}
|
||||
|
||||
public boolean hasMessage() {
|
||||
return mHasMessage;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package me.majiajie.pagerbottomtabstrip.internal;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.TypedValue;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.graphics.drawable.DrawableCompat;
|
||||
|
||||
|
||||
public class Utils {
|
||||
|
||||
/**
|
||||
* Drawable 染色
|
||||
*
|
||||
* @param drawable 染色对象
|
||||
* @param color 颜色
|
||||
* @return 染色后的资源
|
||||
*/
|
||||
public static Drawable tinting(Drawable drawable, int color) {
|
||||
final Drawable wrappedDrawable = DrawableCompat.wrap(drawable);
|
||||
wrappedDrawable.mutate();
|
||||
DrawableCompat.setTint(wrappedDrawable, color);
|
||||
return wrappedDrawable;
|
||||
}
|
||||
|
||||
public static Drawable newDrawable(Drawable drawable) {
|
||||
Drawable.ConstantState constantState = drawable.getConstantState();
|
||||
return constantState != null ? constantState.newDrawable() : drawable;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取colorPrimary的颜色,需要V7包的支持
|
||||
*
|
||||
* @param context 上下文
|
||||
* @return 0xAARRGGBB
|
||||
*/
|
||||
public static int getColorPrimary(Context context) {
|
||||
Resources res = context.getResources();
|
||||
int attrRes = res.getIdentifier("colorPrimary", "attr", context.getPackageName());
|
||||
if (attrRes == 0) {
|
||||
return 0xFF009688;
|
||||
}
|
||||
return ContextCompat.getColor(context, getResourceId(context, attrRes));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取自定义属性的资源ID
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param attrRes 自定义属性
|
||||
* @return resourceId
|
||||
*/
|
||||
private static int getResourceId(Context context, int attrRes) {
|
||||
TypedValue typedValue = new TypedValue();
|
||||
context.getTheme().resolveAttribute(attrRes, typedValue, true);
|
||||
return typedValue.resourceId;
|
||||
}
|
||||
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
package me.majiajie.pagerbottomtabstrip.item;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.AttrRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* 所有自定义Item都必须继承此类
|
||||
*/
|
||||
public abstract class BaseTabItem extends FrameLayout {
|
||||
|
||||
public BaseTabItem(@NonNull Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public BaseTabItem(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public BaseTabItem(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置选中状态
|
||||
*/
|
||||
abstract public void setChecked(boolean checked);
|
||||
|
||||
/**
|
||||
* 设置消息数字。注意:一般数字需要大于0才会显示
|
||||
*/
|
||||
abstract public void setMessageNumber(int number);
|
||||
|
||||
/**
|
||||
* 设置是否显示无数字的小圆点。注意:如果消息数字不为0,优先显示带数字的圆
|
||||
*/
|
||||
abstract public void setHasMessage(boolean hasMessage);
|
||||
|
||||
/**
|
||||
* 设置标题
|
||||
*/
|
||||
abstract public void setTitle(String title);
|
||||
|
||||
/**
|
||||
* 设置未选中状态下的图标
|
||||
*/
|
||||
abstract public void setDefaultDrawable(Drawable drawable);
|
||||
|
||||
/**
|
||||
* 设置选中状态下的图标
|
||||
*/
|
||||
abstract public void setSelectedDrawable(Drawable drawable);
|
||||
|
||||
/**
|
||||
* 获取标题文字
|
||||
*/
|
||||
abstract public String getTitle();
|
||||
|
||||
/**
|
||||
* 已选中的状态下再次点击时触发
|
||||
*/
|
||||
public void onRepeat() {}
|
||||
|
||||
|
||||
}
|
||||
+253
@@ -0,0 +1,253 @@
|
||||
package me.majiajie.pagerbottomtabstrip.item;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.AttrRes;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import me.majiajie.pagerbottomtabstrip.R;
|
||||
import me.majiajie.pagerbottomtabstrip.internal.RoundMessageView;
|
||||
import me.majiajie.pagerbottomtabstrip.internal.Utils;
|
||||
|
||||
/**
|
||||
* 材料设计风格项
|
||||
*/
|
||||
public class MaterialItemView extends BaseTabItem {
|
||||
|
||||
private final RoundMessageView mMessages;
|
||||
private final TextView mLabel;
|
||||
private final ImageView mIcon;
|
||||
|
||||
private Drawable mDefaultDrawable;
|
||||
private Drawable mCheckedDrawable;
|
||||
|
||||
private int mDefaultColor;
|
||||
private int mCheckedColor;
|
||||
|
||||
private final float mTranslation;
|
||||
private final float mTranslationHideTitle;
|
||||
|
||||
private final int mTopMargin;
|
||||
private final int mTopMarginHideTitle;
|
||||
|
||||
private boolean mHideTitle;
|
||||
private boolean mChecked;
|
||||
|
||||
private ValueAnimator mAnimator;
|
||||
private float mAnimatorValue = 1f;
|
||||
|
||||
private boolean mIsMeasured = false;
|
||||
|
||||
private boolean mTintIcon = true;
|
||||
|
||||
public MaterialItemView(@NonNull Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public MaterialItemView(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public MaterialItemView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
|
||||
final float scale = context.getResources().getDisplayMetrics().density;
|
||||
|
||||
mTranslation = scale * 2;
|
||||
mTranslationHideTitle = scale * 10;
|
||||
mTopMargin = (int) (scale * 8);
|
||||
mTopMarginHideTitle = (int) (scale * 16);
|
||||
|
||||
LayoutInflater.from(context).inflate(R.layout.item_material, this, true);
|
||||
|
||||
mIcon = findViewById(R.id.icon);
|
||||
mLabel = findViewById(R.id.label);
|
||||
mMessages = findViewById(R.id.messages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getAccessibilityClassName() {
|
||||
return MaterialItemView.class.getName();
|
||||
}
|
||||
|
||||
public void initialization(String title, Drawable drawable, Drawable checkedDrawable, boolean tintIcon, int color, int checkedColor) {
|
||||
mTintIcon = tintIcon;
|
||||
|
||||
mDefaultColor = color;
|
||||
mCheckedColor = checkedColor;
|
||||
|
||||
if (mTintIcon) {
|
||||
mDefaultDrawable = Utils.tinting(drawable, mDefaultColor);
|
||||
mCheckedDrawable = Utils.tinting(checkedDrawable, mCheckedColor);
|
||||
} else {
|
||||
mDefaultDrawable = drawable;
|
||||
mCheckedDrawable = checkedDrawable;
|
||||
}
|
||||
|
||||
mLabel.setText(title);
|
||||
mLabel.setTextColor(color);
|
||||
|
||||
mIcon.setImageDrawable(mDefaultDrawable);
|
||||
|
||||
mAnimator = ValueAnimator.ofFloat(1f);
|
||||
mAnimator.setDuration(115L);
|
||||
mAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
|
||||
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
mAnimatorValue = (float) animation.getAnimatedValue();
|
||||
if (mHideTitle) {
|
||||
mIcon.setTranslationY(-mTranslationHideTitle * mAnimatorValue);
|
||||
} else {
|
||||
mIcon.setTranslationY(-mTranslation * mAnimatorValue);
|
||||
}
|
||||
mLabel.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12f + mAnimatorValue * 2f);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
mIsMeasured = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChecked(boolean checked) {
|
||||
if (mChecked == checked) {
|
||||
return;
|
||||
}
|
||||
|
||||
mChecked = checked;
|
||||
|
||||
if (mHideTitle) {
|
||||
mLabel.setVisibility(mChecked ? View.VISIBLE : View.INVISIBLE);
|
||||
}
|
||||
|
||||
if (mIsMeasured) {
|
||||
// 切换动画
|
||||
if (mChecked) {
|
||||
mAnimator.start();
|
||||
} else {
|
||||
mAnimator.reverse();
|
||||
}
|
||||
} else if (mChecked) { // 布局还未测量时选中,直接转换到选中的最终状态
|
||||
if (mHideTitle) {
|
||||
mIcon.setTranslationY(-mTranslationHideTitle);
|
||||
} else {
|
||||
mIcon.setTranslationY(-mTranslation);
|
||||
}
|
||||
mLabel.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14f);
|
||||
} else { // 布局还未测量并且未选中,保持未选中状态
|
||||
mIcon.setTranslationY(0);
|
||||
mLabel.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12f);
|
||||
}
|
||||
|
||||
// 切换颜色
|
||||
if (mChecked) {
|
||||
mIcon.setImageDrawable(mCheckedDrawable);
|
||||
mLabel.setTextColor(mCheckedColor);
|
||||
} else {
|
||||
mIcon.setImageDrawable(mDefaultDrawable);
|
||||
mLabel.setTextColor(mDefaultColor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMessageNumber(int number) {
|
||||
mMessages.setVisibility(View.VISIBLE);
|
||||
mMessages.setMessageNumber(number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHasMessage(boolean hasMessage) {
|
||||
mMessages.setVisibility(View.VISIBLE);
|
||||
mMessages.setHasMessage(hasMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(String title) {
|
||||
mLabel.setText(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultDrawable(Drawable drawable) {
|
||||
if (mTintIcon) {
|
||||
mDefaultDrawable = Utils.tinting(drawable, mDefaultColor);
|
||||
} else {
|
||||
mDefaultDrawable = drawable;
|
||||
}
|
||||
|
||||
if (!mChecked) {
|
||||
mIcon.setImageDrawable(mDefaultDrawable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectedDrawable(Drawable drawable) {
|
||||
if (mTintIcon) {
|
||||
mCheckedDrawable = Utils.tinting(drawable, mCheckedColor);
|
||||
} else {
|
||||
mCheckedDrawable = drawable;
|
||||
}
|
||||
|
||||
if (mChecked) {
|
||||
mIcon.setImageDrawable(mCheckedDrawable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return mLabel.getText().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取动画运行值[0,1]
|
||||
*/
|
||||
public float getAnimValue() {
|
||||
return mAnimatorValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否隐藏文字
|
||||
*/
|
||||
public void setHideTitle(boolean hideTitle) {
|
||||
mHideTitle = hideTitle;
|
||||
|
||||
LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
|
||||
|
||||
if (mHideTitle) {
|
||||
iconParams.topMargin = mTopMarginHideTitle;
|
||||
} else {
|
||||
iconParams.topMargin = mTopMargin;
|
||||
}
|
||||
|
||||
mLabel.setVisibility(mChecked ? View.VISIBLE : View.INVISIBLE);
|
||||
|
||||
mIcon.setLayoutParams(iconParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置消息圆形的颜色
|
||||
*/
|
||||
public void setMessageBackgroundColor(@ColorInt int color) {
|
||||
mMessages.tintMessageBackground(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置消息数据的颜色
|
||||
*/
|
||||
public void setMessageNumberColor(@ColorInt int color) {
|
||||
mMessages.setMessageNumberColor(color);
|
||||
}
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
package me.majiajie.pagerbottomtabstrip.item;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import me.majiajie.pagerbottomtabstrip.R;
|
||||
import me.majiajie.pagerbottomtabstrip.internal.RoundMessageView;
|
||||
|
||||
public class NormalItemView extends BaseTabItem {
|
||||
|
||||
private ImageView mIcon;
|
||||
private final TextView mTitle;
|
||||
private final RoundMessageView mMessages;
|
||||
|
||||
private Drawable mDefaultDrawable;
|
||||
private Drawable mCheckedDrawable;
|
||||
|
||||
private int mDefaultTextColor = 0x56000000;
|
||||
private int mCheckedTextColor = 0x56000000;
|
||||
|
||||
private boolean mChecked;
|
||||
|
||||
public NormalItemView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public NormalItemView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public NormalItemView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
|
||||
// LayoutInflater.from(context).inflate(R.layout.item_normal, this, true);
|
||||
LayoutInflater.from(context).inflate(R.layout.item_normal_new, this, true);
|
||||
mIcon = findViewById(R.id.icon);
|
||||
mTitle = findViewById(R.id.title);
|
||||
mMessages = findViewById(R.id.messages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getAccessibilityClassName() {
|
||||
return NormalItemView.class.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 方便初始化的方法
|
||||
*
|
||||
* @param drawableRes 默认状态的图标
|
||||
* @param checkedDrawableRes 选中状态的图标
|
||||
* @param title 标题
|
||||
*/
|
||||
public void initialize(@DrawableRes int drawableRes, @DrawableRes int checkedDrawableRes, String title) {
|
||||
mDefaultDrawable = ContextCompat.getDrawable(getContext(), drawableRes);
|
||||
mCheckedDrawable = ContextCompat.getDrawable(getContext(), checkedDrawableRes);
|
||||
mTitle.setText(title);
|
||||
}
|
||||
public void initialize(@DrawableRes int drawableRes, @DrawableRes int checkedDrawableRes, String title,int textsize) {
|
||||
mDefaultDrawable = ContextCompat.getDrawable(getContext(), drawableRes);
|
||||
mCheckedDrawable = ContextCompat.getDrawable(getContext(), checkedDrawableRes);
|
||||
mTitle.setText(title);
|
||||
mTitle.setTextSize(textsize);
|
||||
}
|
||||
public void initialize(String title,int textsize) {
|
||||
mIcon.setVisibility(GONE);
|
||||
mTitle.setText(title);
|
||||
mTitle.setTextSize(textsize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChecked(boolean checked) {
|
||||
if (checked) {
|
||||
mIcon.setImageDrawable(mCheckedDrawable);
|
||||
mTitle.setTextColor(mCheckedTextColor);
|
||||
} else {
|
||||
mIcon.setImageDrawable(mDefaultDrawable);
|
||||
mTitle.setTextColor(mDefaultTextColor);
|
||||
}
|
||||
mChecked = checked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMessageNumber(int number) {
|
||||
mMessages.setMessageNumber(number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHasMessage(boolean hasMessage) {
|
||||
mMessages.setHasMessage(hasMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(String title) {
|
||||
mTitle.setText(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultDrawable(Drawable drawable) {
|
||||
mDefaultDrawable = drawable;
|
||||
if (!mChecked) {
|
||||
mIcon.setImageDrawable(drawable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectedDrawable(Drawable drawable) {
|
||||
mCheckedDrawable = drawable;
|
||||
if (mChecked) {
|
||||
mIcon.setImageDrawable(drawable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return mTitle.getText().toString();
|
||||
}
|
||||
|
||||
public void setTextDefaultColor(@ColorInt int color) {
|
||||
mDefaultTextColor = color;
|
||||
}
|
||||
|
||||
public void setTextCheckedColor(@ColorInt int color) {
|
||||
mCheckedTextColor = color;
|
||||
}
|
||||
}
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
package me.majiajie.pagerbottomtabstrip.item;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.RippleDrawable;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.AttrRes;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import me.majiajie.pagerbottomtabstrip.R;
|
||||
import me.majiajie.pagerbottomtabstrip.internal.RoundMessageView;
|
||||
import me.majiajie.pagerbottomtabstrip.internal.Utils;
|
||||
|
||||
/**
|
||||
* 只有图标的材料设计项(用于垂直布局)
|
||||
*/
|
||||
public class OnlyIconMaterialItemView extends BaseTabItem {
|
||||
|
||||
private final RoundMessageView mMessages;
|
||||
private final ImageView mIcon;
|
||||
|
||||
private Drawable mDefaultDrawable;
|
||||
private Drawable mCheckedDrawable;
|
||||
|
||||
private int mDefaultColor;
|
||||
private int mCheckedColor;
|
||||
|
||||
private String mTitle;
|
||||
|
||||
private boolean mChecked;
|
||||
|
||||
private boolean mTintIcon = true;
|
||||
|
||||
public OnlyIconMaterialItemView(@NonNull Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public OnlyIconMaterialItemView(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public OnlyIconMaterialItemView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
|
||||
LayoutInflater.from(context).inflate(R.layout.item_material_only_icon, this, true);
|
||||
|
||||
mIcon = findViewById(R.id.icon);
|
||||
mMessages = findViewById(R.id.messages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getAccessibilityClassName() {
|
||||
return OnlyIconMaterialItemView.class.getName();
|
||||
}
|
||||
|
||||
public void initialization(String title, Drawable drawable, Drawable checkedDrawable, boolean tintIcon, int color, int checkedColor) {
|
||||
|
||||
mTitle = title;
|
||||
|
||||
mDefaultColor = color;
|
||||
mCheckedColor = checkedColor;
|
||||
|
||||
mTintIcon = tintIcon;
|
||||
|
||||
if (mTintIcon) {
|
||||
mDefaultDrawable = Utils.tinting(drawable, mDefaultColor);
|
||||
mCheckedDrawable = Utils.tinting(checkedDrawable, mCheckedColor);
|
||||
} else {
|
||||
mDefaultDrawable = drawable;
|
||||
mCheckedDrawable = checkedDrawable;
|
||||
}
|
||||
|
||||
mIcon.setImageDrawable(mDefaultDrawable);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
setBackground(new RippleDrawable(new ColorStateList(new int[][]{{}}, new int[]{0xFFFFFF & checkedColor | 0x56000000}), null, null));
|
||||
} else {
|
||||
setBackgroundResource(R.drawable.material_item_background);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChecked(boolean checked) {
|
||||
if (mChecked == checked) {
|
||||
return;
|
||||
}
|
||||
|
||||
mChecked = checked;
|
||||
|
||||
// 切换颜色
|
||||
if (mChecked) {
|
||||
mIcon.setImageDrawable(mCheckedDrawable);
|
||||
} else {
|
||||
mIcon.setImageDrawable(mDefaultDrawable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMessageNumber(int number) {
|
||||
mMessages.setVisibility(View.VISIBLE);
|
||||
mMessages.setMessageNumber(number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHasMessage(boolean hasMessage) {
|
||||
mMessages.setVisibility(View.VISIBLE);
|
||||
mMessages.setHasMessage(hasMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(String title) {
|
||||
// no title
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultDrawable(Drawable drawable) {
|
||||
if (mTintIcon) {
|
||||
mDefaultDrawable = Utils.tinting(drawable, mDefaultColor);
|
||||
} else {
|
||||
mDefaultDrawable = drawable;
|
||||
}
|
||||
|
||||
if (!mChecked) {
|
||||
mIcon.setImageDrawable(mDefaultDrawable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectedDrawable(Drawable drawable) {
|
||||
if (mTintIcon) {
|
||||
mCheckedDrawable = Utils.tinting(drawable, mCheckedColor);
|
||||
} else {
|
||||
mCheckedDrawable = drawable;
|
||||
}
|
||||
|
||||
if (mChecked) {
|
||||
mIcon.setImageDrawable(mCheckedDrawable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置消息圆形的颜色
|
||||
*/
|
||||
public void setMessageBackgroundColor(@ColorInt int color) {
|
||||
mMessages.tintMessageBackground(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置消息数据的颜色
|
||||
*/
|
||||
public void setMessageNumberColor(@ColorInt int color) {
|
||||
mMessages.setMessageNumberColor(color);
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package me.majiajie.pagerbottomtabstrip.listener;
|
||||
|
||||
/**
|
||||
* 导航栏按钮选中事件
|
||||
*/
|
||||
public interface OnTabItemSelectedListener {
|
||||
|
||||
/**
|
||||
* 选中导航栏的某一项
|
||||
*
|
||||
* @param index 索引导航按钮,按添加顺序排序
|
||||
* @param old 前一个选中项,如果没有就等于-1
|
||||
*/
|
||||
void onSelected(int index, int old);
|
||||
|
||||
/**
|
||||
* 重复选中
|
||||
*
|
||||
* @param index 索引导航按钮,按添加顺序排序
|
||||
*/
|
||||
void onRepeat(int index);
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package me.majiajie.pagerbottomtabstrip.listener;
|
||||
|
||||
/**
|
||||
* 导航栏按钮选中事件
|
||||
*/
|
||||
public interface SimpleTabItemSelectedListener {
|
||||
|
||||
/**
|
||||
* 选中导航栏的某一项
|
||||
*
|
||||
* @param index 索引导航按钮,按添加顺序排序
|
||||
* @param old 前一个选中项,如果没有就等于-1
|
||||
*/
|
||||
void onSelected(int index, int old);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="#33333333"/>
|
||||
</shape>
|
||||
</item>
|
||||
<item android:drawable="@android:color/transparent"/>
|
||||
</selector>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<!-- <solid android:color="@android:color/holo_red_light"/>-->
|
||||
<solid android:color="#EB322D"/>
|
||||
</shape>
|
||||
@@ -0,0 +1,39 @@
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginBottom="@dimen/material_bottom_navigation_margin"
|
||||
android:layout_marginTop="@dimen/material_bottom_navigation_margin" />
|
||||
|
||||
<me.majiajie.pagerbottomtabstrip.internal.BaselineLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
android:clipToPadding="false"
|
||||
android:paddingBottom="10dp"
|
||||
>
|
||||
<TextView
|
||||
android:id="@+id/label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:textSize="@dimen/material_bottom_navigation_text_size"
|
||||
tools:text="123" />
|
||||
</me.majiajie.pagerbottomtabstrip.internal.BaselineLayout>
|
||||
|
||||
<me.majiajie.pagerbottomtabstrip.internal.RoundMessageView
|
||||
android:id="@+id/messages"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="3dp"
|
||||
android:translationX="14dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
</merge>
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
<me.majiajie.pagerbottomtabstrip.internal.RoundMessageView
|
||||
android:id="@+id/messages"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="11dp"
|
||||
android:translationX="14dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
</merge>
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="8dp" />
|
||||
|
||||
<me.majiajie.pagerbottomtabstrip.internal.BaselineLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
android:clipToPadding="false"
|
||||
android:paddingBottom="10dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:textSize="12sp"
|
||||
tools:text="123" />
|
||||
|
||||
</me.majiajie.pagerbottomtabstrip.internal.BaselineLayout>
|
||||
|
||||
<me.majiajie.pagerbottomtabstrip.internal.RoundMessageView
|
||||
android:id="@+id/messages"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="3dp"
|
||||
android:translationX="14dp" />
|
||||
|
||||
</merge>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="22dp"
|
||||
/>
|
||||
|
||||
<!-- <me.majiajie.pagerbottomtabstrip.internal.BaselineLayout-->
|
||||
<!-- android:layout_width="wrap_content"-->
|
||||
<!-- android:layout_height="wrap_content"-->
|
||||
<!-- android:layout_gravity="bottom|center_horizontal"-->
|
||||
<!-- android:clipToPadding="false"-->
|
||||
<!-- android:paddingBottom="24dp">-->
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
android:maxLines="1"
|
||||
android:textSize="12sp"
|
||||
android:paddingBottom="14dp"
|
||||
tools:text="123" />
|
||||
|
||||
<!-- </me.majiajie.pagerbottomtabstrip.internal.BaselineLayout>-->
|
||||
|
||||
<me.majiajie.pagerbottomtabstrip.internal.RoundMessageView
|
||||
android:id="@+id/messages"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="14dp"
|
||||
android:translationX="16dp"
|
||||
android:translationY="-1dp"/>
|
||||
|
||||
</merge>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="33dp"
|
||||
android:layout_height="33dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="4dp"
|
||||
/>
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
android:maxLines="1"
|
||||
android:textSize="14sp"
|
||||
android:paddingBottom="4dp"
|
||||
tools:text="123" />
|
||||
|
||||
<!-- </me.majiajie.pagerbottomtabstrip.internal.BaselineLayout>-->
|
||||
|
||||
<me.majiajie.pagerbottomtabstrip.internal.RoundMessageView
|
||||
android:id="@+id/messages"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="14dp"
|
||||
android:translationX="16dp"
|
||||
android:translationY="-1dp"/>
|
||||
|
||||
</merge>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<View
|
||||
android:id="@+id/oval"
|
||||
android:layout_width="10dp"
|
||||
android:layout_height="10dp"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginTop="2dp"
|
||||
android:background="@drawable/round"
|
||||
android:visibility="invisible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/msg"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/round"
|
||||
android:gravity="center"
|
||||
android:minHeight="20dp"
|
||||
android:minWidth="20dp"
|
||||
android:singleLine="true"
|
||||
android:textColor="@android:color/white"
|
||||
android:visibility="invisible" />
|
||||
|
||||
</merge>
|
||||
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">PagerBottomTabStrip</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<dimen name="material_bottom_navigation_active_item_max_width">168dp</dimen>
|
||||
<dimen name="material_bottom_navigation_active_text_size">14sp</dimen>
|
||||
<dimen name="material_bottom_navigation_elevation">8dp</dimen>
|
||||
<dimen name="material_bottom_navigation_height">56dp</dimen>
|
||||
<dimen name="material_bottom_navigation_item_max_width">96dp</dimen>
|
||||
<dimen name="material_bottom_navigation_item_min_width">56dp</dimen>
|
||||
<dimen name="material_bottom_navigation_margin">8dp</dimen>
|
||||
<dimen name="material_bottom_navigation_shadow_height">1dp</dimen>
|
||||
<dimen name="material_bottom_navigation_text_size">12sp</dimen>
|
||||
|
||||
<declare-styleable name="PageNavigationView">
|
||||
<attr name="NavigationPaddingTop" format="dimension"/>
|
||||
<attr name="NavigationPaddingBottom" format="dimension"/>
|
||||
</declare-styleable>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
ext {
|
||||
|
||||
libraryName = 'PagerBottomTabStrip'
|
||||
libraryDescription = 'An navigation bar for Android'
|
||||
|
||||
publishedGroupId = 'me.majiajie'
|
||||
artifact = 'pager-bottom-tab-strip'
|
||||
|
||||
siteUrl = 'https://github.com/tyzlmjj/PagerBottomTabStrip'
|
||||
scmUrl = 'github.com/tyzlmjj/PagerBottomTabStrip.git'
|
||||
|
||||
libraryVersion = rootProject.ext.versionName
|
||||
|
||||
developerId = 'tyzlmjj'
|
||||
developerName = 'Ma JiaJie'
|
||||
developerEmail = 'tyzl931019@gmail.com'
|
||||
|
||||
licenseName = 'The Apache Software License, Version 2.0'
|
||||
licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
|
||||
}
|
||||
|
||||
apply from: 'https://raw.githubusercontent.com/tyzlmjj/Gradle/master/MavenCentral/publish_module.gradle'
|
||||
Reference in New Issue
Block a user