目前市面上主流的app 都会采用多页面管理,以承载更多的内容,这里会简单叙述 通过底部按钮 是血页面的切换。
android 篇:
android 通过fragment 有三种实现方式:
整体大同小异,菜鸟教程有详细讲述: https://www.runoob.com/w3cnote/android-tutorial-fragment-demo1.html
或者可以使用第三方库:
/**Bottom Navigation**/
implementation 'com.ashokvarma.android:bottom-navigation-bar:2.2.0'
<com.ashokvarma.bottomnavigation.BottomNavigationBar
android:id="@+id/bottom_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
app:bnbActiveColor="@color/color_ffffff"
app:bnbInactiveColor="@color/color_929292"
app:bnbBackgroundColor="@color/colorPrimaryDark"/>
Java:
BottomNavigationBar bottomBar;
@Override
protected void initialize() {
setTopTitle(getResources().getString(R.string.t_home), true);
setLeftBtn(false, 0, null);
bottomBar.setTabSelectedListener(this);
bottomBar.setMode(BottomNavigationBar.MODE_FIXED);
bottomBar.setBackgroundStyle(BottomNavigationBar.BACKGROUND_STYLE_RIPPLE);
bottomBar.addItem(new BottomNavigationItem(ContextCompat.getDrawable(this, R.mipmap.icon_home_press),
getString(R.string.t_home)).setInactiveIcon(ContextCompat.getDrawable(this, R.mipmap.icon_home)))
.addItem(new BottomNavigationItem(ContextCompat.getDrawable(this, R.mipmap.icon_discover_press),
getString(R.string.t_serive)).setInactiveIcon(ContextCompat.getDrawable(this, R.mipmap.icon_discover)))
.addItem(new BottomNavigationItem(ContextCompat.getDrawable(this, R.mipmap.icon_hot_press),
getString(R.string.t_learn)).setInactiveIcon(ContextCompat.getDrawable(this, R.mipmap.icon_hot)))
.addItem(new BottomNavigationItem(ContextCompat.getDrawable(this, R.mipmap.icon_user_press),
getString(R.string.t_person)).setInactiveIcon(ContextCompat.getDrawable(this, R.mipmap.icon_user)))
.setFirstSelectedPosition(0)
.initialise();
setDefaultFragment();
}
//点击事件处理
@Override
public void onTabSelected(int position) {}
fragment 处理逻辑一致,选择一种自己喜欢的方式。
第三方控件相对于 可以让开发者少些布局,将底部按钮进行封装 ,点击具有动画效果,整体对比,减少开发工作量 。
旧版仅供参考 :布局如下:
<FrameLayout
android:id="@+id/ly_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_above="@+id/rg_tab_bar"></FrameLayout>
<RadioGroup
android:id="@+id/rg_tab_bar"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_alignParentBottom="true"
android:background="@color/white"
android:orientation="horizontal">
<RadioButton
android:id="@+id/rb_Home"
style="@style/tab_menu_item"
android:drawableTop="@drawable/tab_menu_infromation"
android:text="首页"/>
<RadioButton
android:id="@+id/rb_Service"
style="@style/tab_menu_item"
android:drawableTop="@drawable/tab_menu_health"
android:text="服务"/>
<RadioButton
android:id="@+id/rb_Preson"
style="@style/tab_menu_item"
android:drawableTop="@drawable/tab_menu_home"
android:text="我"/>
</RadioGroup>
创建3个fragment 和RadioButton 相对应 ly_content 内容匹配 这里有个易错点 就是
import android.app.Fragment; 与
import android.support.v7.app.Fragment; 这个传递参数 继承 Fragment 两个内容要匹配
这里一定要注意 一不小心就容易出错。 实际上 同样 不同情况 也容易出错
private void init() {
rg_tab_bar = (RadioGroup) findViewById(R.id.rg_tab_bar);
fManager = getFragmentManager();
rg_tab_bar.setOnCheckedChangeListener(this);
rb_home=(RadioButton)findViewById(R.id.rb_Home);
rb_home.setChecked(true);
}
@Override
public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) {
FragmentTransaction fragmentTransaction=fManager.beginTransaction();
hideAllFragment(fragmentTransaction);
switch (checkedId){
case R.id.rb_Home:
if (fg1==null){
fg1=new HomeFragment();
fragmentTransaction.add(R.id.ly_content,fg1);
}else {
fragmentTransaction.show(fg1);
}
break;
case R.id.rb_Service:
if (fg2==null){
fg2=new ServiceFragment();
fragmentTransaction.add(R.id.ly_content,fg2);
}else {
fragmentTransaction.show(fg2);
}
break;
case R.id.rb_Preson:
if (fg3==null){
fg3=new PresonFragment();
fragmentTransaction.add(R.id.ly_content,fg3);
}else {
fragmentTransaction.show(fg3);
}
break;
}
fragmentTransaction.commit();
}
//隐藏所有Fragment
private void hideAllFragment(FragmentTransaction fragmentTransaction) {
if (fg1 != null) fragmentTransaction.hide(fg1);
if (fg2 != null) fragmentTransaction.hide(fg2);
if (fg3 != null) fragmentTransaction.hide(fg3);
}
IOS篇:
相对于 android 使用碎片化的fragment 实现 底部菜单栏 而 IOS端 主要是通过 结合视图和控制器构建tabbar 样式页面。
UITabBarController
UITabBarController 功能就是管理理多个 UIViewController 切换 通过点击底部对应按钮,选中对应需要展示的 UIViewController
UITabBar
- 按照加⼊入 UITabbarController 的顺序展示
- 展示的内容有对应 UIViewController 设置
- 系统负责点击的响应和切换
相对于 Android 和 iOS 之间的切换,都是面向对象的语言。主要语法上的差异,对比刚开始学习fragment 的同学,可能对碎片这个使用的理解不太清楚,而iOS这里就是比较好理解了,简单明了,代码如下:
iOS13里生命周期有所调整需要将代码移动到SceneDelegate.m中
iOS13中appdelegate的职责发现了改变:
iOS13之前,Appdelegate的职责全权处理App生命周期和UI生命周期;
iOS13之后,Appdelegate的职责是:
1、处理 App 生命周期
2、新的 Scene Session 生命周期
那UI的生命周期交给新增的Scene Delegate处理
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
self.window = [[UIWindow alloc] initWithWindowScene:(UIWindowScene *)scene];
UITabBarController *tabbarController = [[UITabBarController alloc] init];
HomeViewController *homeViewController = [[HomeViewController alloc] init];
homeViewController.view.backgroundColor = [UIColor whiteColor];
FindViewController *findViewController = [[FindViewController alloc] init];
ChatViewController *chatViewController = [[ChatViewController alloc] init];
PersonalViewController *personalViewController = [[PersonalViewController alloc] init];
[tabbarController setViewControllers:@[homeViewController, findViewController, chatViewController, personalViewController]];
self.window.rootViewController = tabbarController;
[self.window makeKeyAndVisible];
[self.window makeKeyWindow];
}
@implementation HomeViewController
- (instancetype)init
{
self = [super init];
if (self) {
self.tabBarItem.title = @"首页";
self.tabBarItem.image = [UIImage imageNamed:@"icon.bundle/icon_home@2x.png"];
self.tabBarItem.selectedImage = [UIImage imageNamed:@"icon_home_press@2x.png"];
}
return self;
}
其他viewController 同理,也可以在外部直接调用设置,最好改viewController的设置写在内部。