Android BottomNavigationView 一个选项卡具有不同 unselected/selected 颜色
Android BottomNavigationView One tab with different unselected/selected colors
我正在尝试匹配这样的设计..
请注意 "selected tab color tint" 是蓝色的,但中心选项卡的图标应该始终是绿色圆圈,中间是白色时钟。
我已经尝试了很多东西。首先尝试通过使用具有绿色圆圈和时钟 PNG 资源的层列表 XML 资源以编程方式执行此操作,但这根本不起作用。然后我让设计师给我完整的图标(时钟和绿色圆圈),但现在我 运行 陷入这个问题..
(未选中)
(已选择)
我在 Google 上找不到正确的搜索词来解决这个问题。
最后,我需要选择的选项卡颜色为蓝色,但我需要中心选项卡图标始终是没有额外颜色的实际图标(基本上它需要看起来与 .png 完全一样)。
PS:我正在使用 Xamarin.Forms、FreshMvvm 和 FreshTabbedFONavigationContainer。但是,通过渲染器,我可以直接访问 BottomNavigationView 和所有其他本机 Android 组件。所以解决方案不一定是 Xamarin 解决方案。 java/kotlin 解决方案也可以,我可以将它转换为 Xamarin。
======================
已编辑:
======================
所以我使用下面的 Andres Castro 代码得到了很多进一步的帮助,但我仍然遇到与以前相同的问题。使用下面安德烈斯的代码,我切换回使用 FontAwesome 作为图标(效果很好),但这样做意味着我需要使用 LayerDrawable
来创建 circle/icon 中心选项卡图标。
这就是我目前所拥有的..
未选中中心图标
选中中心图标
如您所见,未选中时中心图标仍为灰色,选中时为蓝色(其他 4 个图标的正确 selected/unselected 颜色)。
这是我目前拥有的与中心图标相关的代码..
UpdateTabbedIcons
private void UpdateTabbedIcons()
{
for (var i = 0; i < Element.Children.Count; i++) {
var tab = _bottomNavigationView.Menu.GetItem(i);
var element = Element.Children[i];
if (element is NavigationPage navigationPage) {
//if the child page is a navigation page get its root page
element = navigationPage.RootPage;
}
UpdateTabIcon(tab, element);
}
}
UpdateTabIcon
public void UpdateTabIcon(IMenuItem menuItem, Page page)
{
var icon = page?.Icon;
if (icon == null) return;
var drawable = new IconDrawable(Context, icon, "fa-regular-pro-400.ttf");
var element = Element.CurrentPage;
if (element is NavigationPage navigationPage) {
//if the child page is a navigation page get its root page
element = navigationPage.RootPage;
}
if (page is DoNowTabPage) { //Page for center icon
drawable.Color(Helpers.Resources.White.ToAndroid());
var finalDrawable = GetCombinedDrawable(drawable);
menuItem.SetIcon(finalDrawable);
return;
} else if (element == page) {
drawable.Color(BarSelectedItemColor.ToAndroid());
} else {
drawable.Color(BarItemColor.ToAndroid());
}
menuItem.SetIcon(drawable);
}
GetCombinedDrawable
private Drawable GetCombinedDrawable(IconDrawable iconDrawable)
{
var displayMetrics = Resources.DisplayMetrics;
GradientDrawable circleDrawable = new GradientDrawable();
circleDrawable.SetColor(Helpers.Resources.Green.ToAndroid());
circleDrawable.SetShape(ShapeType.Oval);
circleDrawable.SetSize((int)TypedValue.ApplyDimension(ComplexUnitType.Dip, 500, displayMetrics), (int)TypedValue.ApplyDimension(ComplexUnitType.Dip, 500, displayMetrics));
circleDrawable.Alpha = 1;
var inset = (int)TypedValue.ApplyDimension(ComplexUnitType.Dip, 140, displayMetrics);
var bottomInset = (int)TypedValue.ApplyDimension(ComplexUnitType.Dip, 40, displayMetrics);
LayerDrawable finalDrawable = new LayerDrawable(new Drawable[] { circleDrawable, iconDrawable });
finalDrawable.SetLayerHeight(1, iconDrawable.IntrinsicHeight);
finalDrawable.SetLayerWidth(1, iconDrawable.IntrinsicWidth);
finalDrawable.SetLayerInset(1, inset, inset, inset, inset + bottomInset);
finalDrawable.SetLayerInsetBottom(0, bottomInset);
finalDrawable.ClearColorFilter();
return finalDrawable;
}
正如您在我为圆圈创建的 GradientDrawable
中看到的那样,我将其颜色设置为我的绿色(我有一个名为 Resources 的自定义 class..那不是Android Resources
class).
这就是我被困的地方。我将可绘制的圆形设置为绿色,但一旦进入 BottomNavigationView,它的颜色始终与其他图标的 unselected/selected 颜色相匹配。
希望通过这最后一期。感谢您的帮助。
我可以帮你解决这个问题:
public class HomeMenuTabLayout extends TabLayout {
public static final int HOME_MENU_TABLAYOUT_COUNT = 5;
public static final int HOME_MENU_LIVE_INDEX = 0;
public static final int HOME_MENU_TEAM_INDEX = 1;
public static final int HOME_MENU_ADS_INDEX = 2;
public static final int HOME_MENU_WALLET_INDEX = 3;
public static final int HOME_MENU_POST_INDEX = 4;
public int selectedIndex = 0;
private TextView unread;
public HomeMenuTabLayout(Context context) {
super(context);
initItems(context);
}
public HomeMenuTabLayout(Context context, AttributeSet attrs) {
super(context, attrs);
initItems(context);
}
public HomeMenuTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initItems(context);
}
public void initItems(Context context) {
for (int i = 0; i < HOME_MENU_TABLAYOUT_COUNT; i++) {
addTab(newTab());
}
for (int i = 0; i < HOME_MENU_TABLAYOUT_COUNT; i++) {
TabLayout.Tab tab = this.getTabAt(i);
tab.setCustomView(getTabView(context, i, false));
}
}
public void setTagIndex(Context context, int index) {
getTabView(context, selectedIndex, false);
selectedIndex = index;
getTabView(context, selectedIndex, true);
}
private View getTabView(Context context, int index, boolean selected) {
View v = null;
TabLayout.Tab tab = this.getTabAt(index);
if (tab != null) {
v = tab.getCustomView();
if (v == null) {
v = LayoutInflater.from(context).inflate(R.layout.activity_main_tab_layout, null);
}
}
if (v == null) {
return null;
}
ImageView img = v.findViewById(R.id.tablayout_image);
int color = 0;
int color2 = 0;
if (selected) {
color = getResources().getColor(R.color.corn_flower_blue);
color2 = getResources().getColor(R.color.dark_sky_blue_three);
TmlyUtils.displayViewWithZoom(img);
} else {
color = getResources().getColor(R.color.battleship_grey_dark);
color2 = getResources().getColor(R.color.battleship_grey_dark);
}
switch (index) {
case HOME_MENU_ADS_INDEX:
Bitmap offers = StyleKit.imageOfTabbarSearchActive(color, color2);
img.setImageBitmap(offers);
break;
case HOME_MENU_LIVE_INDEX:
Bitmap live = StyleKit.imageOfTabbarHomeActive(color, color2);
img.setImageBitmap(live);
unread = v.findViewById(R.id.tablayout_unread);
break;
case HOME_MENU_TEAM_INDEX:
Bitmap team = StyleKit.imageOfTabbarSocialActive(color, color2);
img.setImageBitmap(team);
break;
case HOME_MENU_WALLET_INDEX:
Bitmap wallet = StyleKit.imageOfTabbarCaddyActive(color, color2);
img.setImageBitmap(wallet);
break;
case HOME_MENU_POST_INDEX:
Bitmap chat = StyleKit.imageOfTabbarPlusActive(getResources().getColor(R.color.white), getResources().getColor(R.color.white));
img.setImageBitmap(chat);
View cirle = v.findViewById(R.id.tablayout_circle);
cirle.setVisibility(View.VISIBLE);
break;
default:
break;
}
return v;
}
}
这是一个自定义 TabLayout,您可以看到我正在扩展 TabLayout class,当创建 TabLayout 时,我正在调用 initItems 方法,该方法添加了 Tab 并为其设置了自定义视图。
getTabView return 膨胀视图,如您所见
LayoutInflater.from(context).inflate(R.layout.activity_main_tab_layout, null);
如果你需要它
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="@dimen/tab_bar_height">
<ImageView
android:id="@+id/tablayout_circle"
android:layout_width="@dimen/tab_bar_height"
android:layout_height="@dimen/tab_bar_height"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:background="@drawable/circle_blue_gradient"
android:visibility="gone"
tools:visibility="visible" />
<ImageView
android:id="@+id/tablayout_image"
android:layout_width="@dimen/tab_bar_icon_favorite_height"
android:layout_height="@dimen/tab_bar_icon_favorite_height"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" />
</RelativeLayout>
膨胀视图后,您可以使用
获取视图元素
ImageView img = v.findViewById(R.id.tablayout_image);
您可以检查是否选择了布尔值的视图,对于您的情况,当索引位于中央时,您需要忽略颜色切换。
只有一件事,当您单击 TabLayout 图标时,不要忘记调用
setTagIndex();
如果你不这样做,图像将不会被重绘
由于您可以访问底部导航视图,因此每次切换页面时都可以 "redraw" 底部工具栏。我们做了类似的事情,但没有发现任何性能问题。
您首先要通过在 OnElementChanged
中订阅页面更改来监视页面更改
Element.CurrentPageChanged += ElementOnCurrentPageChanged;
然后在ElementOnCurrentPageChanged
中你可以遍历每个页面并获取该页面的菜单项
private void UpdateTabbedIcons()
{
for (var i = 0; i < Element.Children.Count; i++)
{
var tab = _bottomNavigationView.Menu.GetItem(i);
var element = Element.Children[i];
if (element is NavigationPage navigationPage)
{
//if the child page is a navigation page get its root page
element = navigationPage.RootPage;
}
UpdateTabIcon(tab, element);
}
}
在我们的例子中,我们使用了字体图标,所以我们每次都绘制图标并设置颜色。
public void UpdateTabIcon(IMenuItem menuItem, Page page)
{
var icon = page?.Icon?.File;
if (icon == null) return;
var drawable = new IconDrawable(Context, "FontAwesome.ttf", icon).SizeDp(20);
var element = Element.CurrentPage;
if (element is NavigationPage navigationPage)
{
//if the child page is a navigation page get its root page
element = navigationPage.RootPage;
}
if (element == page)
{
drawable.Color(BarSelectedItemColor.ToAndroid());
}
else
{
drawable.Color(BarItemColor.ToAndroid());
}
menuItem.SetIcon(drawable);
}
我们还必须覆盖 OnAttachedToWindow 以确保从不同状态返回到应用程序时重绘图标。
protected override void OnAttachedToWindow()
{
UpdateTabbedIcons();
base.OnAttachedToWindow();
}
您必须对此进行一些修改以适合您的用例,但我认为此方法应该可以满足您的需求。
解决方案
Gradle:
implementation 'com.github.armcha:SpaceNavigationView:1.6.0'
Layout:
<com.luseen.spacenavigation.SpaceNavigationView
android:id="@+id/space"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
app:active_item_color="@color/color_trans"
app:centre_button_color="@color/black"
app:inactive_item_color="@color/color_trans"
app:space_background_color="@color/white"
app:space_item_icon_only_size="24dp"
app:space_item_icon_size="@dimen/space_item_icon_default_size"
app:space_item_text_size="@dimen/space_item_text_default_size" />
添加 Space 个导航项。
spaceNavigationView = (SpaceNavigationView) findViewById(R.id.space);
spaceNavigationView.initWithSaveInstanceState(savedInstanceState);
/*Space navigation View*/
spaceNavigationView.initWithSaveInstanceState(savedInstanceState);
spaceNavigationView.addSpaceItem(new SpaceItem(0, "Templates", R.drawable.ic_color_template_tab, getResources().getColor(R.color.color_yellow)));
spaceNavigationView.addSpaceItem(new SpaceItem(1, "Explore", R.drawable.ic_category_tab, getResources().getColor(R.color.color_bg)));
spaceNavigationView.addSpaceItem(new SpaceItem(2, "Tools", R.drawable.ic_tools_tab, getResources().getColor(R.color.color_bg)));
spaceNavigationView.addSpaceItem(new SpaceItem(3, "My Work", R.drawable.ic_my_work_tab, getResources().getColor(R.color.color_bg)));
spaceNavigationView.setCentreButtonIconColorFilterEnabled(true);
spaceNavigationView.setCentreButtonIcon(R.drawable.ic_create2_tab);
spaceNavigationView.setInActiveCentreButtonIconColor(ContextCompat.getColor(this, R.color.white));
spaceNavigationView.setActiveCentreButtonBackgroundColor(ContextCompat.getColor(this, R.color.color_yellow));
spaceNavigationView.setCentreButtonColor(ContextCompat.getColor(this, R.color.black));
spaceNavigationView.setCentreButtonRippleColor(ContextCompat.getColor(this, R.color.color_yellow));
spaceNavigationView.setCentreButtonSelectable(true);
spaceNavigationView.setSpaceBackgroundColor(ContextCompat.getColor(this, R.color.obaudiopicker_white));
// spaceNavigationView.setCentreButtonSelected(2, R.drawable.ic_color_template_tab, getResources().getColor(R.color.color_yellow));
spaceNavigationView.setInActiveSpaceItemColor(ContextCompat.getColor(this, R.color.color_bg));
如果您想在设备旋转时保持所选项目的位置和标记,请使用 initWithSaveInstanceState(savedInstanceState)
和 override onSaveInstanceState
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
spaceNavigationView.onSaveInstanceState(outState);
Log.i(TAG, "onSaveInstanceState: ");
}
Set onClick listener
spaceNavigationView.setSpaceOnClickListener(new SpaceOnClickListener() {
@Override
public void onCentreButtonClick() {
setDefaultIcon();
new Handler().post(new Runnable() {
@Override
public void run() {
spaceNavigationView.setActiveCentreButtonIconColor(ContextCompat.getColor(NEWBusinessCardMainActivity.this, R.color.black));
}
});
changeCurrentFragmentTo(Constants.ITEM_CREATE);
}
@Override
public void onItemClick(final int itemIndex, String itemName) {
Log.d("onItemClick ", "" + itemIndex + " " + itemName);
switch (itemIndex) {
case 0:
setDefaultIcon();
new Handler().post(new Runnable() {
@Override
public void run() {
spaceNavigationView.changeItemIconAtPosition(itemIndex, R.drawable.ic_color_template_tab);
spaceNavigationView.changeItemTextColorAtPosition(itemIndex, getResources().getColor(R.color.color_yellow));
}
});
changeCurrentFragmentTo(Constants.ITEM_TEMPLATE);
break;
case 1:
setDefaultIcon();
new Handler().post(new Runnable() {
@Override
public void run() {
spaceNavigationView.changeItemIconAtPosition(itemIndex, R.drawable.ic_color_category_tab);
spaceNavigationView.changeItemTextColorAtPosition(itemIndex, getResources().getColor(R.color.color_category));
}
});
changeCurrentFragmentTo(Constants.ITEM_CATEGORY);
break;
case 2:
setDefaultIcon();
new Handler().post(new Runnable() {
@Override
public void run() {
spaceNavigationView.changeItemIconAtPosition(itemIndex, R.drawable.ic_color_tool_tab);
spaceNavigationView.changeItemTextColorAtPosition(itemIndex, getResources().getColor(R.color.color_tools));
}
});
changeCurrentFragmentTo(Constants.ITEM_TOOLS);
break;
case 3:
setDefaultIcon();
new Handler().post(new Runnable() {
@Override
public void run() {
spaceNavigationView.changeItemIconAtPosition(itemIndex, R.drawable.ic_color_my_work_tab);
spaceNavigationView.changeItemTextColorAtPosition(itemIndex, getResources().getColor(R.color.color_mywork));
}
});
changeCurrentFragmentTo(Constants.ITEM_MY_WORK);
break;
}
}
@Override
public void onItemReselected(int itemIndex, String itemName) {
// Toast.makeText(MainActivity.this, itemIndex + " " + itemName, Toast.LENGTH_SHORT).show();
}
});
setDefaultIcon()
private void setDefaultIcon() {
spaceNavigationView.changeItemIconAtPosition(0, R.drawable.ic_template_tab, getResources().getColor(R.color.color_bg));
spaceNavigationView.changeItemIconAtPosition(1, R.drawable.ic_category_tab, getResources().getColor(R.color.color_bg));
spaceNavigationView.changeItemIconAtPosition(2, R.drawable.ic_tools_tab, getResources().getColor(R.color.color_bg));
spaceNavigationView.changeItemIconAtPosition(3, R.drawable.ic_my_work_tab, getResources().getColor(R.color.color_bg));
}
Example:
您可以使用 SVG 图像并制作自己的颜色属性,并为中心图标和其他底部导航视图图标制作可绘制选择器,如下所示:
在 colors.xml 文件中
<color name="color_bottom_selected">#44C8F5</color>
<color name="color_bottom_unselected">#c0c0c0</color>
在 attrs.xml 文件中
<attr name="color_bottom_unselected" format="color" />
<attr name="color_bottom_selected" format="color" />
在 SVG 图像文件中
用您的属性替换硬编码颜色值
android:fillColor="#fff" to android:fillColor="?attr/color_bottom_unselected"
并且不要忘记使选择器可绘制
BottomNavigationView 比它的 iOS 实现要困难得多。我做了一些研究,看看您的要求是否可行,然后当我在 Android 本地看到它时,我开始考虑实现它的方法。
要实施最后一个挑战,您必须每次都根据底部导航视图的索引以编程方式更改所选 tint/color。
尝试使用色调模式DST,它会忽略色调。
将此行添加到您的方法中GetCombinedDrawable()
circleDrawable.setTintMode(PorterDuff.Mode.DST);
如果这不起作用,试试这个:
finalDrawable.ClearColorFilter();
finalDrawable.setTintMode(PorterDuff.Mode.DST);
我正在尝试匹配这样的设计..
请注意 "selected tab color tint" 是蓝色的,但中心选项卡的图标应该始终是绿色圆圈,中间是白色时钟。
我已经尝试了很多东西。首先尝试通过使用具有绿色圆圈和时钟 PNG 资源的层列表 XML 资源以编程方式执行此操作,但这根本不起作用。然后我让设计师给我完整的图标(时钟和绿色圆圈),但现在我 运行 陷入这个问题..
(未选中)
(已选择)
我在 Google 上找不到正确的搜索词来解决这个问题。
最后,我需要选择的选项卡颜色为蓝色,但我需要中心选项卡图标始终是没有额外颜色的实际图标(基本上它需要看起来与 .png 完全一样)。
PS:我正在使用 Xamarin.Forms、FreshMvvm 和 FreshTabbedFONavigationContainer。但是,通过渲染器,我可以直接访问 BottomNavigationView 和所有其他本机 Android 组件。所以解决方案不一定是 Xamarin 解决方案。 java/kotlin 解决方案也可以,我可以将它转换为 Xamarin。
======================
已编辑:
======================
所以我使用下面的 Andres Castro 代码得到了很多进一步的帮助,但我仍然遇到与以前相同的问题。使用下面安德烈斯的代码,我切换回使用 FontAwesome 作为图标(效果很好),但这样做意味着我需要使用 LayerDrawable
来创建 circle/icon 中心选项卡图标。
这就是我目前所拥有的..
未选中中心图标
选中中心图标
如您所见,未选中时中心图标仍为灰色,选中时为蓝色(其他 4 个图标的正确 selected/unselected 颜色)。
这是我目前拥有的与中心图标相关的代码..
UpdateTabbedIcons
private void UpdateTabbedIcons()
{
for (var i = 0; i < Element.Children.Count; i++) {
var tab = _bottomNavigationView.Menu.GetItem(i);
var element = Element.Children[i];
if (element is NavigationPage navigationPage) {
//if the child page is a navigation page get its root page
element = navigationPage.RootPage;
}
UpdateTabIcon(tab, element);
}
}
UpdateTabIcon
public void UpdateTabIcon(IMenuItem menuItem, Page page)
{
var icon = page?.Icon;
if (icon == null) return;
var drawable = new IconDrawable(Context, icon, "fa-regular-pro-400.ttf");
var element = Element.CurrentPage;
if (element is NavigationPage navigationPage) {
//if the child page is a navigation page get its root page
element = navigationPage.RootPage;
}
if (page is DoNowTabPage) { //Page for center icon
drawable.Color(Helpers.Resources.White.ToAndroid());
var finalDrawable = GetCombinedDrawable(drawable);
menuItem.SetIcon(finalDrawable);
return;
} else if (element == page) {
drawable.Color(BarSelectedItemColor.ToAndroid());
} else {
drawable.Color(BarItemColor.ToAndroid());
}
menuItem.SetIcon(drawable);
}
GetCombinedDrawable
private Drawable GetCombinedDrawable(IconDrawable iconDrawable)
{
var displayMetrics = Resources.DisplayMetrics;
GradientDrawable circleDrawable = new GradientDrawable();
circleDrawable.SetColor(Helpers.Resources.Green.ToAndroid());
circleDrawable.SetShape(ShapeType.Oval);
circleDrawable.SetSize((int)TypedValue.ApplyDimension(ComplexUnitType.Dip, 500, displayMetrics), (int)TypedValue.ApplyDimension(ComplexUnitType.Dip, 500, displayMetrics));
circleDrawable.Alpha = 1;
var inset = (int)TypedValue.ApplyDimension(ComplexUnitType.Dip, 140, displayMetrics);
var bottomInset = (int)TypedValue.ApplyDimension(ComplexUnitType.Dip, 40, displayMetrics);
LayerDrawable finalDrawable = new LayerDrawable(new Drawable[] { circleDrawable, iconDrawable });
finalDrawable.SetLayerHeight(1, iconDrawable.IntrinsicHeight);
finalDrawable.SetLayerWidth(1, iconDrawable.IntrinsicWidth);
finalDrawable.SetLayerInset(1, inset, inset, inset, inset + bottomInset);
finalDrawable.SetLayerInsetBottom(0, bottomInset);
finalDrawable.ClearColorFilter();
return finalDrawable;
}
正如您在我为圆圈创建的 GradientDrawable
中看到的那样,我将其颜色设置为我的绿色(我有一个名为 Resources 的自定义 class..那不是Android Resources
class).
这就是我被困的地方。我将可绘制的圆形设置为绿色,但一旦进入 BottomNavigationView,它的颜色始终与其他图标的 unselected/selected 颜色相匹配。
希望通过这最后一期。感谢您的帮助。
我可以帮你解决这个问题:
public class HomeMenuTabLayout extends TabLayout {
public static final int HOME_MENU_TABLAYOUT_COUNT = 5;
public static final int HOME_MENU_LIVE_INDEX = 0;
public static final int HOME_MENU_TEAM_INDEX = 1;
public static final int HOME_MENU_ADS_INDEX = 2;
public static final int HOME_MENU_WALLET_INDEX = 3;
public static final int HOME_MENU_POST_INDEX = 4;
public int selectedIndex = 0;
private TextView unread;
public HomeMenuTabLayout(Context context) {
super(context);
initItems(context);
}
public HomeMenuTabLayout(Context context, AttributeSet attrs) {
super(context, attrs);
initItems(context);
}
public HomeMenuTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initItems(context);
}
public void initItems(Context context) {
for (int i = 0; i < HOME_MENU_TABLAYOUT_COUNT; i++) {
addTab(newTab());
}
for (int i = 0; i < HOME_MENU_TABLAYOUT_COUNT; i++) {
TabLayout.Tab tab = this.getTabAt(i);
tab.setCustomView(getTabView(context, i, false));
}
}
public void setTagIndex(Context context, int index) {
getTabView(context, selectedIndex, false);
selectedIndex = index;
getTabView(context, selectedIndex, true);
}
private View getTabView(Context context, int index, boolean selected) {
View v = null;
TabLayout.Tab tab = this.getTabAt(index);
if (tab != null) {
v = tab.getCustomView();
if (v == null) {
v = LayoutInflater.from(context).inflate(R.layout.activity_main_tab_layout, null);
}
}
if (v == null) {
return null;
}
ImageView img = v.findViewById(R.id.tablayout_image);
int color = 0;
int color2 = 0;
if (selected) {
color = getResources().getColor(R.color.corn_flower_blue);
color2 = getResources().getColor(R.color.dark_sky_blue_three);
TmlyUtils.displayViewWithZoom(img);
} else {
color = getResources().getColor(R.color.battleship_grey_dark);
color2 = getResources().getColor(R.color.battleship_grey_dark);
}
switch (index) {
case HOME_MENU_ADS_INDEX:
Bitmap offers = StyleKit.imageOfTabbarSearchActive(color, color2);
img.setImageBitmap(offers);
break;
case HOME_MENU_LIVE_INDEX:
Bitmap live = StyleKit.imageOfTabbarHomeActive(color, color2);
img.setImageBitmap(live);
unread = v.findViewById(R.id.tablayout_unread);
break;
case HOME_MENU_TEAM_INDEX:
Bitmap team = StyleKit.imageOfTabbarSocialActive(color, color2);
img.setImageBitmap(team);
break;
case HOME_MENU_WALLET_INDEX:
Bitmap wallet = StyleKit.imageOfTabbarCaddyActive(color, color2);
img.setImageBitmap(wallet);
break;
case HOME_MENU_POST_INDEX:
Bitmap chat = StyleKit.imageOfTabbarPlusActive(getResources().getColor(R.color.white), getResources().getColor(R.color.white));
img.setImageBitmap(chat);
View cirle = v.findViewById(R.id.tablayout_circle);
cirle.setVisibility(View.VISIBLE);
break;
default:
break;
}
return v;
}
}
这是一个自定义 TabLayout,您可以看到我正在扩展 TabLayout class,当创建 TabLayout 时,我正在调用 initItems 方法,该方法添加了 Tab 并为其设置了自定义视图。
getTabView return 膨胀视图,如您所见
LayoutInflater.from(context).inflate(R.layout.activity_main_tab_layout, null);
如果你需要它
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="@dimen/tab_bar_height">
<ImageView
android:id="@+id/tablayout_circle"
android:layout_width="@dimen/tab_bar_height"
android:layout_height="@dimen/tab_bar_height"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:background="@drawable/circle_blue_gradient"
android:visibility="gone"
tools:visibility="visible" />
<ImageView
android:id="@+id/tablayout_image"
android:layout_width="@dimen/tab_bar_icon_favorite_height"
android:layout_height="@dimen/tab_bar_icon_favorite_height"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" />
</RelativeLayout>
膨胀视图后,您可以使用
获取视图元素 ImageView img = v.findViewById(R.id.tablayout_image);
您可以检查是否选择了布尔值的视图,对于您的情况,当索引位于中央时,您需要忽略颜色切换。
只有一件事,当您单击 TabLayout 图标时,不要忘记调用
setTagIndex();
如果你不这样做,图像将不会被重绘
由于您可以访问底部导航视图,因此每次切换页面时都可以 "redraw" 底部工具栏。我们做了类似的事情,但没有发现任何性能问题。
您首先要通过在 OnElementChanged
Element.CurrentPageChanged += ElementOnCurrentPageChanged;
然后在ElementOnCurrentPageChanged
中你可以遍历每个页面并获取该页面的菜单项
private void UpdateTabbedIcons()
{
for (var i = 0; i < Element.Children.Count; i++)
{
var tab = _bottomNavigationView.Menu.GetItem(i);
var element = Element.Children[i];
if (element is NavigationPage navigationPage)
{
//if the child page is a navigation page get its root page
element = navigationPage.RootPage;
}
UpdateTabIcon(tab, element);
}
}
在我们的例子中,我们使用了字体图标,所以我们每次都绘制图标并设置颜色。
public void UpdateTabIcon(IMenuItem menuItem, Page page)
{
var icon = page?.Icon?.File;
if (icon == null) return;
var drawable = new IconDrawable(Context, "FontAwesome.ttf", icon).SizeDp(20);
var element = Element.CurrentPage;
if (element is NavigationPage navigationPage)
{
//if the child page is a navigation page get its root page
element = navigationPage.RootPage;
}
if (element == page)
{
drawable.Color(BarSelectedItemColor.ToAndroid());
}
else
{
drawable.Color(BarItemColor.ToAndroid());
}
menuItem.SetIcon(drawable);
}
我们还必须覆盖 OnAttachedToWindow 以确保从不同状态返回到应用程序时重绘图标。
protected override void OnAttachedToWindow()
{
UpdateTabbedIcons();
base.OnAttachedToWindow();
}
您必须对此进行一些修改以适合您的用例,但我认为此方法应该可以满足您的需求。
解决方案
Gradle:
implementation 'com.github.armcha:SpaceNavigationView:1.6.0'
Layout:
<com.luseen.spacenavigation.SpaceNavigationView
android:id="@+id/space"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
app:active_item_color="@color/color_trans"
app:centre_button_color="@color/black"
app:inactive_item_color="@color/color_trans"
app:space_background_color="@color/white"
app:space_item_icon_only_size="24dp"
app:space_item_icon_size="@dimen/space_item_icon_default_size"
app:space_item_text_size="@dimen/space_item_text_default_size" />
添加 Space 个导航项。
spaceNavigationView = (SpaceNavigationView) findViewById(R.id.space);
spaceNavigationView.initWithSaveInstanceState(savedInstanceState);
/*Space navigation View*/
spaceNavigationView.initWithSaveInstanceState(savedInstanceState);
spaceNavigationView.addSpaceItem(new SpaceItem(0, "Templates", R.drawable.ic_color_template_tab, getResources().getColor(R.color.color_yellow)));
spaceNavigationView.addSpaceItem(new SpaceItem(1, "Explore", R.drawable.ic_category_tab, getResources().getColor(R.color.color_bg)));
spaceNavigationView.addSpaceItem(new SpaceItem(2, "Tools", R.drawable.ic_tools_tab, getResources().getColor(R.color.color_bg)));
spaceNavigationView.addSpaceItem(new SpaceItem(3, "My Work", R.drawable.ic_my_work_tab, getResources().getColor(R.color.color_bg)));
spaceNavigationView.setCentreButtonIconColorFilterEnabled(true);
spaceNavigationView.setCentreButtonIcon(R.drawable.ic_create2_tab);
spaceNavigationView.setInActiveCentreButtonIconColor(ContextCompat.getColor(this, R.color.white));
spaceNavigationView.setActiveCentreButtonBackgroundColor(ContextCompat.getColor(this, R.color.color_yellow));
spaceNavigationView.setCentreButtonColor(ContextCompat.getColor(this, R.color.black));
spaceNavigationView.setCentreButtonRippleColor(ContextCompat.getColor(this, R.color.color_yellow));
spaceNavigationView.setCentreButtonSelectable(true);
spaceNavigationView.setSpaceBackgroundColor(ContextCompat.getColor(this, R.color.obaudiopicker_white));
// spaceNavigationView.setCentreButtonSelected(2, R.drawable.ic_color_template_tab, getResources().getColor(R.color.color_yellow));
spaceNavigationView.setInActiveSpaceItemColor(ContextCompat.getColor(this, R.color.color_bg));
如果您想在设备旋转时保持所选项目的位置和标记,请使用 initWithSaveInstanceState(savedInstanceState)
和 override onSaveInstanceState
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
spaceNavigationView.onSaveInstanceState(outState);
Log.i(TAG, "onSaveInstanceState: ");
}
Set onClick listener
spaceNavigationView.setSpaceOnClickListener(new SpaceOnClickListener() {
@Override
public void onCentreButtonClick() {
setDefaultIcon();
new Handler().post(new Runnable() {
@Override
public void run() {
spaceNavigationView.setActiveCentreButtonIconColor(ContextCompat.getColor(NEWBusinessCardMainActivity.this, R.color.black));
}
});
changeCurrentFragmentTo(Constants.ITEM_CREATE);
}
@Override
public void onItemClick(final int itemIndex, String itemName) {
Log.d("onItemClick ", "" + itemIndex + " " + itemName);
switch (itemIndex) {
case 0:
setDefaultIcon();
new Handler().post(new Runnable() {
@Override
public void run() {
spaceNavigationView.changeItemIconAtPosition(itemIndex, R.drawable.ic_color_template_tab);
spaceNavigationView.changeItemTextColorAtPosition(itemIndex, getResources().getColor(R.color.color_yellow));
}
});
changeCurrentFragmentTo(Constants.ITEM_TEMPLATE);
break;
case 1:
setDefaultIcon();
new Handler().post(new Runnable() {
@Override
public void run() {
spaceNavigationView.changeItemIconAtPosition(itemIndex, R.drawable.ic_color_category_tab);
spaceNavigationView.changeItemTextColorAtPosition(itemIndex, getResources().getColor(R.color.color_category));
}
});
changeCurrentFragmentTo(Constants.ITEM_CATEGORY);
break;
case 2:
setDefaultIcon();
new Handler().post(new Runnable() {
@Override
public void run() {
spaceNavigationView.changeItemIconAtPosition(itemIndex, R.drawable.ic_color_tool_tab);
spaceNavigationView.changeItemTextColorAtPosition(itemIndex, getResources().getColor(R.color.color_tools));
}
});
changeCurrentFragmentTo(Constants.ITEM_TOOLS);
break;
case 3:
setDefaultIcon();
new Handler().post(new Runnable() {
@Override
public void run() {
spaceNavigationView.changeItemIconAtPosition(itemIndex, R.drawable.ic_color_my_work_tab);
spaceNavigationView.changeItemTextColorAtPosition(itemIndex, getResources().getColor(R.color.color_mywork));
}
});
changeCurrentFragmentTo(Constants.ITEM_MY_WORK);
break;
}
}
@Override
public void onItemReselected(int itemIndex, String itemName) {
// Toast.makeText(MainActivity.this, itemIndex + " " + itemName, Toast.LENGTH_SHORT).show();
}
});
setDefaultIcon()
private void setDefaultIcon() {
spaceNavigationView.changeItemIconAtPosition(0, R.drawable.ic_template_tab, getResources().getColor(R.color.color_bg));
spaceNavigationView.changeItemIconAtPosition(1, R.drawable.ic_category_tab, getResources().getColor(R.color.color_bg));
spaceNavigationView.changeItemIconAtPosition(2, R.drawable.ic_tools_tab, getResources().getColor(R.color.color_bg));
spaceNavigationView.changeItemIconAtPosition(3, R.drawable.ic_my_work_tab, getResources().getColor(R.color.color_bg));
}
Example:
您可以使用 SVG 图像并制作自己的颜色属性,并为中心图标和其他底部导航视图图标制作可绘制选择器,如下所示:
在 colors.xml 文件中
<color name="color_bottom_selected">#44C8F5</color>
<color name="color_bottom_unselected">#c0c0c0</color>
在 attrs.xml 文件中
<attr name="color_bottom_unselected" format="color" />
<attr name="color_bottom_selected" format="color" />
在 SVG 图像文件中
用您的属性替换硬编码颜色值
android:fillColor="#fff" to android:fillColor="?attr/color_bottom_unselected"
并且不要忘记使选择器可绘制
BottomNavigationView 比它的 iOS 实现要困难得多。我做了一些研究,看看您的要求是否可行,然后当我在 Android 本地看到它时,我开始考虑实现它的方法。
要实施最后一个挑战,您必须每次都根据底部导航视图的索引以编程方式更改所选 tint/color。
尝试使用色调模式DST,它会忽略色调。
将此行添加到您的方法中GetCombinedDrawable()
circleDrawable.setTintMode(PorterDuff.Mode.DST);
如果这不起作用,试试这个:
finalDrawable.ClearColorFilter();
finalDrawable.setTintMode(PorterDuff.Mode.DST);