【移动开发】Android中的底部菜单框架(Fragment)

简介:

今天,我将总结一下Android应用中大家经常见到的底部导航栏的几种实现!


一。TabHost + RadioGroup实现方式

在我们平时开发过程中使用的TabHost是在上方,这里我们简单修改了一下<TabHost>的布局,让叶片放到了底部。

main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<?xml version= "1.0"  encoding= "utf-8" ?>
<TabHost xmlns:android= "http://schemas.android.com/apk/res/android"
     android:id= "@android:id/tabhost"
     android:layout_width= "fill_parent"
     android:layout_height= "fill_parent"
     android:orientation= "horizontal"  >
     <LinearLayout
         android:layout_width= "fill_parent"
         android:layout_height= "fill_parent"
         android:orientation= "vertical"  >
         <TabWidget
             android:id= "@android:id/tabs"
             android:layout_width= "fill_parent"
             android:layout_height= "wrap_content"
             android:visibility= "gone"  />
         <FrameLayout
             android:id= "@android:id/tabcontent"
             android:layout_width= "fill_parent"
             android:layout_height= "fill_parent"
             android:layout_weight= "1.0"  />
         <RadioGroup
             android:id= "@+id/radioGroup"
             android:layout_width= "fill_parent"
             android:layout_height= "wrap_content"
             android:layout_gravity= "bottom"
             android:background= "@drawable/bar"
             android:gravity= "center_vertical"
             android:orientation= "horizontal"  >
             <RadioButton
                 android:id= "@+id/rd_home"
                 style= "@style/main_btn_style"
                 android:layout_width= "wrap_content"
                 android:layout_height= "wrap_content"
                 android:drawableTop= "@drawable/home_icon"
                 android:text= "主页"  />
             <RadioButton
                 android:id= "@+id/rd_wt"
                 style= "@style/main_btn_style"
                 android:layout_width= "wrap_content"
                 android:layout_height= "wrap_content"
                 android:drawableTop= "@drawable/wb_icon_write_n"
                 android:text= "发表"  />
             <RadioButton
                 android:id= "@+id/rd_msg"
                 style= "@style/main_btn_style"
                 android:layout_width= "wrap_content"
                 android:layout_height= "wrap_content"
                 android:drawableTop= "@drawable/msg_icon"
                 android:text= "信息"  />
             <RadioButton
                 android:id= "@+id/rd_more"
                 style= "@style/main_btn_style"
                 android:layout_width= "wrap_content"
                 android:layout_height= "wrap_content"
                 android:drawableTop= "@drawable/more_icon"
                 android:text= "更多"  />
         </RadioGroup>
     </LinearLayout>
</TabHost>

styles.xml

1
2
3
4
5
6
7
8
9
<style name= "main_btn_style" >
        <item name= "android:button" >@ null </item>
        <item name= "android:textSize" >10dp</item>
        <item name= "android:textColor" >#ffffff</item>
        <item name= "android:gravity" >center_horizontal</item>
        <item name= "android:drawablePadding" >4dp</item>
        <item name= "android:layout_weight" > 1.0 </item>
        <item name= "android:background" >@drawable/main_btn_bg_d</item>
    </style>

main_btn_bg_d.xml

1
2
3
4
5
<?xml version= "1.0"  encoding= "utf-8" ?>
<selector xmlns:android= "http://schemas.android.com/apk/res/android" >
     <item android:drawable= "@drawable/main_btn_bg"  android:state_enabled= "true"  android:state_pressed= "true" ></item>
     <item android:drawable= "@drawable/main_btn_bg"  android:state_checked= "true"  android:state_enabled= "true" ></item>
</selector>

这里需要注意的是:

1.main.xml中:TabWidget的id必须是@android:id/tabs,FrameLayout的id必须是 @android:id/tabcontent。

2.把TabWidget的Visibility设置成了gone!也就是默认难看的风格不见了2011-3-1_2.jpg取而代之的是5个带风格的单选按钮.


MainActivity类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package  com.zhf.android_tabhost;
import  android.app.TabActivity;
import  android.content.Intent;
import  android.os.Bundle;
import  android.widget.RadioGroup;
import  android.widget.RadioGroup.OnCheckedChangeListener;
import  android.widget.TabHost;
import  android.widget.TabHost.TabSpec;
public  class  MainActivity  extends  TabActivity {
     private  TabHost tabHost;
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
     @Override
     public  void  onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.main);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
         tabHost =  this .getTabHost();
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
         TabSpec homeSpec = tabHost.newTabSpec( "home" ).setIndicator( "home" ).setContent( new  Intent( this ,HomeActivity. class ));
         TabSpec writeSpec = tabHost.newTabSpec( "write" ).setIndicator( "write" ).setContent( new  Intent( this ,WriteActivity. class ));
         TabSpec msgSpec = tabHost.newTabSpec( "msg" ).setIndicator( "msg" ).setContent( new  Intent( this ,MsgActivity. class ));
         TabSpec moreSpec = tabHost.newTabSpec( "more" ).setIndicator( "more" ).setContent( new  Intent( this ,MoreActivity. class ));
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
         tabHost.addTab(homeSpec);
         tabHost.addTab(writeSpec);
         tabHost.addTab(msgSpec);
         tabHost.addTab(moreSpec);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
         RadioGroup rg = (RadioGroup)  this .findViewById(R.id.radioGroup);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
         rg.setOnCheckedChangeListener( new  OnCheckedChangeListener() {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
             @Override
             public  void  onCheckedChanged(RadioGroup group,  int  checkedId) {
                 switch  (checkedId) {
                 case  R.id.rd_home:
                     tabHost.setCurrentTabByTag( "home" );
                     break ;
                 case  R.id.rd_wt:
                     tabHost.setCurrentTabByTag( "write" );
                     break ;
                 case  R.id.rd_msg:
                     tabHost.setCurrentTabByTag( "msg" );
                     break ;
                 case  R.id.rd_more:
                     tabHost.setCurrentTabByTag( "more" );
                     break ;
                 default :
                     break ;
                 }
             }
         });
     }
}

注:

1.由于TabWidget被隐藏,所以相关的事件也会无效,这里取巧用RadioGroup与RadioButton的特性来处理切换,然后监听事件调用setCurrentTabByTag来切换Activity。

2.注意即使TabWidget被隐藏,也要为其设置indicator,否则会保持。

效果图:

174435324.png

点击底部就可以实现切换不同的Activity的操作了,这里需要注意的一点是,切换底部菜单时不会重新调用onCreate()方法的!!)



二.底部回调接口实现(使用Fragment)--- 重要!


这种方式使用了最新的Fragment,采用了底部导航栏回调接口的方法,来切换底部菜单,并且每次切换回重新调用onCreate()方法!!


main.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?xml version= "1.0"  encoding= "utf-8" ?>
<LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android"
     xmlns:tools= "http://schemas.android.com/tools"
     android:layout_width= "fill_parent"
     android:layout_height= "fill_parent"
     android:orientation= "vertical"
     tools:context= ".MainActivity"  >
     <LinearLayout
         android:layout_width= "fill_parent"
         android:layout_height= "0dp"
         android:layout_weight= "10"
         android:orientation= "vertical"  >
         <RelativeLayout
             android:id= "@+id/main_title_RelativeLayout"
             android:layout_width= "fill_parent"
             android:layout_height= "50dp"
             android:background= "@drawable/fragment_bottom_normal"
             android:orientation= "horizontal"  >
             <TextView
                 android:id= "@+id/main_title_TextView"
                 android:layout_width= "wrap_content"
                 android:layout_height= "wrap_content"
                 android:layout_centerInParent= "true"
                 android:text= "主页"
                 android:textColor= "@android:color/white"
                 android:textSize= "24sp"  />
         </RelativeLayout>
         <FrameLayout
             android:id= "@+id/main_detail_FrameLayout"
             android:layout_width= "fill_parent"
             android:layout_height= "fill_parent"
             android:background= "#ffffff"  >
         </FrameLayout>
     </LinearLayout>
     <fragment
         android:id= "@+id/bottom_fragment"
         android:name= "com.zhf.frameworkdemo02.fragments.BottomFragment"
         android:layout_width= "fill_parent"
         android:layout_height= "0dp"
         android:layout_weight= "1"  />
</LinearLayout>


这里由于我们底部菜单我们采用了fragment,所以布局里面要留出位置!


BottomFragment类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package  com.zhf.frameworkdemo02.fragments;
import  com.zhf.frameworkdemo02.R;
import  android.app.Activity;
import  android.os.Bundle;
import  android.support.v4.app.Fragment;
import  android.view.LayoutInflater;
import  android.view.View;
import  android.view.ViewGroup;
import  android.widget.RadioGroup;
import  android.widget.RadioGroup.OnCheckedChangeListener;
/**
  * 页面底部导航栏
  *
  * @author ZHF
  *
  */
public  class  BottomFragment  extends  Fragment {
     //默认回调接口实现类的对象
     private  Callbacks callbacks = defaultCallbacks;
     /** Fragment和Activity建立关联的时候调用 **/
     @Override
     public  void  onAttach(Activity activity) {
         super .onAttach(activity);
         //当前类是否实现了底部导航栏点击事件回调接口
         if (!(activity  instanceof  Callbacks)) {
             throw  new  IllegalStateException( "Activity must implements fragment's callbacks !" );
         }
         callbacks = (Callbacks) activity;
     }
     /** 为Fragment加载布局时调用 **/
     @Override
     public  View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
         RadioGroup radioGroup = (RadioGroup) inflater.inflate(R.layout.fragment_bottom, container,  false );
         //绑定监听器
         radioGroup.setOnCheckedChangeListener(changeListener);
         return  radioGroup;
     }
                                                                                                                                                                                                                                                                                                                   
     /**RadioGroup监听器**/
     private  OnCheckedChangeListener changeListener =  new  OnCheckedChangeListener() {
         @Override
         public  void  onCheckedChanged(RadioGroup group,  int  checkedId) {
             System.out.println(checkedId);
             callbacks.onItemSelected(checkedId);  //调用接口中方法
         }
     };
     public  interface  Callbacks{
         /**导航栏回调接口**/
         public  void  onItemSelected( int  item);
     }
     /**默认回调实现类的对象**/
     private  static  Callbacks defaultCallbacks =  new  Callbacks() {
         @Override
         public  void  onItemSelected( int  item) {
         //什么都不干
         }
     };
                                                                                                                                                                                                                                                                                                                   
     /**Fragment和Activity解除关联的时候调用**/
     @Override
     public  void  onDetach() {
         super .onDetach();
        callbacks = defaultCallbacks;
     }
}

底部菜单布局fragment_bottom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<?xml version= "1.0"  encoding= "utf-8" ?>
<RadioGroup xmlns:android= "http://schemas.android.com/apk/res/android"
     android:layout_width= "fill_parent"
     android:layout_height= "fill_parent"
     android:orientation= "horizontal"  >
     <RadioButton
         android:id= "@+id/fragment_bottom_home"
         android:layout_width= "fill_parent"
         android:layout_height= "fill_parent"
         android:layout_weight= "1"
         android:background= "@drawable/fragment_bottom_selector"
         android:button= "@null"
         android:drawableTop= "@drawable/main_readiobutton_home"
         android:gravity= "center"
         android:text= "@string/home"
         android:textColor= "@color/white"
         android:textSize= "12sp"  />
     <View
         android:layout_width= "1dp"
         android:layout_height= "fill_parent"
         android:background= "@color/white"  />
     <RadioButton
         android:id= "@+id/fragment_bottom_order"
         android:layout_width= "fill_parent"
         android:layout_height= "fill_parent"
         android:layout_weight= "1"
         android:background= "@drawable/fragment_bottom_selector"
         android:button= "@null"
         android:drawableTop= "@drawable/main_readiobutton_order"
         android:gravity= "center"
         android:text= "@string/order"
         android:textColor= "@color/white"
         android:textSize= "12sp"  />
     <View
         android:layout_width= "1dp"
         android:layout_height= "fill_parent"
         android:background= "@color/white"
         />
     <RadioButton
         android:id= "@+id/fragment_bottom_notice"
         android:layout_width= "fill_parent"
         android:layout_height= "fill_parent"
         android:layout_weight= "1"
         android:background= "@drawable/fragment_bottom_selector"
         android:button= "@null"
         android:drawableTop= "@drawable/main_readiobutton_notice"
         android:gravity= "center"
         android:text= "@string/notice"
         android:textColor= "@color/white"
         android:textSize= "12sp"  />
     <View
         android:layout_width= "1dp"
         android:layout_height= "fill_parent"
         android:background= "@color/white"  />
     <RadioButton
         android:id= "@+id/fragment_bottom_more"
         android:layout_width= "fill_parent"
         android:layout_height= "fill_parent"
         android:layout_weight= "1"
         android:background= "@drawable/fragment_bottom_selector"
         android:button= "@null"
         android:drawablePadding= "3dip"
         android:drawableTop= "@drawable/main_readiobutton_more"
         android:gravity= "center"
         android:text= "@string/more"
         android:textColor= "@color/white"
         android:textSize= "12sp"  />
</RadioGroup>


这里我们定义了一个框架类:GeneralFragment(所有的fragment界面都需继承它)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package  com.zhf.frameworkdemo02.fragments;
import  java.io.Serializable;
import  com.zhf.frameworkdemo02.R;
import  com.zhf.frameworkdemo02.view.OrderView;
import  com.zhf.frameworkdemo02.view.HomeView;
import  com.zhf.frameworkdemo02.view.MoreView;
import  com.zhf.frameworkdemo02.view.NoticeView;
import  android.os.Bundle;
import  android.support.v4.app.Fragment;
import  android.view.LayoutInflater;
import  android.view.View;
import  android.view.ViewGroup;
import  android.widget.TextView;
/**
  * 框架类,抽象公共方法
  * @author ZHF
  *
  */
public  class  GeneralFragment  extends  Fragment  implements  Serializable{
     /**
      *
      */
     private  static  final  long  serialVersionUID = 1L;
                                                                                                                                                                                                                                                               
     private  int  item;  //用于区分底部菜单项
     protected  static  View main_title_RelativeLayout;  //标题栏
     protected  final  static  String key =  "Bundle" ;    //跳转值传递key的名称
                                                                                                                                                                                                                                                               
     @Override
     public  void  onCreate(Bundle savedInstanceState) {
         // TODO Auto-generated method stub
         super .onCreate(savedInstanceState);
         if (getArguments() !=  null ) {   //根据接收子类传来的arguments判断item的哪一项
             if (getArguments().containsKey(MainFragment.Item)) {
                 item = getArguments().getInt(MainFragment.Item);
             }
         }
     }
                                                                                                                                                                                                                                                               
     /**为Fragment加载布局时调用 **/
     @Override
     public  View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
         View view = inflater.inflate(R.layout.fragment_general, container,  false );
         GeneralFragment fragment =  null ;
         switch (item) {
         case  R.id.fragment_bottom_home:   //初始化主页
             fragment =  new  HomeView();
             break ;
         case  R.id.fragment_bottom_order:
             fragment =  new  OrderView();   //初始化订单
              break ;
         case  R.id.fragment_bottom_notice:
             fragment =  new  NoticeView();    //初始化公告
             break ;
         case  R.id.fragment_bottom_more:
             fragment =  new  MoreView();   //初始化更多
             break ;
         default :
             break ;
         }
         if (fragment !=  null ) {
             //更换mainView中间的内容(home,msg,at,more)
             getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.general_fragment, fragment).commit();
         }
         main_title_RelativeLayout =  ((View) container.getParent()).findViewById(R.id.main_title_RelativeLayout);
         //将生成的view返回
         return  view;
     }
                                                                                                                                                                                                                                                               
     /**设置标题**/
     protected  void  setTitle(Object title) {
         if (main_title_RelativeLayout !=  null ) {
             //标题栏中的文字
             TextView mTvTitle = (TextView) main_title_RelativeLayout.findViewById(R.id.main_title_TextView);
             if (mTvTitle !=  null ) {
                 if (title  instanceof  Integer) {   //整型
                     mTvTitle.setText((Integer)title);
                 else  //字符类型
                     mTvTitle.setText((CharSequence)title);
                 }
             }
         }
     }
                                                                                                                                                                                                                                                               
     /**页面跳转值传递**/
     protected  void  setBundle(Object... objects) {
         Bundle arguments =  new  Bundle();
         arguments.putSerializable(key, objects);
         GeneralFragment generalFragment =  new  GeneralFragment();
         generalFragment.setArguments(arguments);
     }
                                                                                                                                                                                                                                                               
     /**获取所传递的值**/
     protected  Object[] getBundle() {
         if (getArguments() !=  null ) {
             System.out.println( "getBundle" );
             if (getArguments().containsKey(key)) {
                 Object[] object = (Object[]) getArguments().getSerializable(key);
                 return  object;
             }
         }
         return  null ;
     }
                                                                                                                                                                                                                                                               
     /**无参页面跳转**/
     protected  void  toIntent(GeneralFragment generalFragment) {
         if (generalFragment !=  null ) {
             getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.general_fragment, generalFragment).commit();
         }
     }
}


程序入口MainFragment:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package  com.zhf.frameworkdemo02.fragments;
import  com.zhf.frameworkdemo02.R;
import  android.os.Bundle;
import  android.support.v4.app.FragmentActivity;
import  android.support.v4.app.FragmentManager;
/**
  *MainView
  * @author ZHF
  *
  */
public  class  MainFragment  extends  FragmentActivity  implements  BottomFragment.Callbacks {
                                                                                                                                                                                                                                  
     public  final  static  String  Item =  "item" ;
                                                                                                                                                                                                                                  
     @Override
     protected  void  onCreate(Bundle savedInstanceState) {
         // TODO Auto-generated method stub
         super .onCreate(savedInstanceState);
         setContentView(R.layout.main);
         //初始化默认调用接口中item选中方法
         onItemSelected(R.id.fragment_bottom_home);
     }
     @Override
     public  void  onItemSelected( int  item) {
         Bundle arguments =  new  Bundle();
         arguments.putInt(Item, item);  //将选中的底部radio的Id放进去
         GeneralFragment generalFragment =  new  GeneralFragment();
         generalFragment.setArguments(arguments);  //设置参数值
         //这里根据item的ID进行界面跳转
         FragmentManager fm = getSupportFragmentManager();
         fm.beginTransaction().replace(R.id.main_detail_FrameLayout, generalFragment).commit();
     }
}


说明:这里我们的每个界面都将采用Fragment,故每个界面需重写onCreateView()


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package  com.zhf.frameworkdemo02.view;
import  android.os.Bundle;
import  android.view.LayoutInflater;
import  android.view.View;
import  android.view.ViewGroup;
import  com.zhf.frameworkdemo02.R;
import  com.zhf.frameworkdemo02.fragments.GeneralFragment;
/**
  * 主页面
  * @author ZHF
  *
  */
public  class  HomeView  extends  GeneralFragment{
     @Override
     public  void  onCreate(Bundle savedInstanceState) {
         // TODO Auto-generated method stub
         super .onCreate(savedInstanceState);
         super .setTitle( "主页" );
     }
                                                                                                                                               
     @Override
     public  View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
         return  inflater.inflate(R.layout.home, container,  false );
     }
}

(其他三个略)

最终效果图:

225533378.png


ok!大功告成!相当实用的!有兴趣的可以学习一下!


源码下载:http://down.51cto.com/data/1009354





今天,我将总结一下Android应用中大家经常见到的底部导航栏的几种实现!


一。TabHost + RadioGroup实现方式

在我们平时开发过程中使用的TabHost是在上方,这里我们简单修改了一下<TabHost>的布局,让叶片放到了底部。

main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<?xml version= "1.0"  encoding= "utf-8" ?>
<TabHost xmlns:android= "http://schemas.android.com/apk/res/android"
     android:id= "@android:id/tabhost"
     android:layout_width= "fill_parent"
     android:layout_height= "fill_parent"
     android:orientation= "horizontal"  >
     <LinearLayout
         android:layout_width= "fill_parent"
         android:layout_height= "fill_parent"
         android:orientation= "vertical"  >
         <TabWidget
             android:id= "@android:id/tabs"
             android:layout_width= "fill_parent"
             android:layout_height= "wrap_content"
             android:visibility= "gone"  />
         <FrameLayout
             android:id= "@android:id/tabcontent"
             android:layout_width= "fill_parent"
             android:layout_height= "fill_parent"
             android:layout_weight= "1.0"  />
         <RadioGroup
             android:id= "@+id/radioGroup"
             android:layout_width= "fill_parent"
             android:layout_height= "wrap_content"
             android:layout_gravity= "bottom"
             android:background= "@drawable/bar"
             android:gravity= "center_vertical"
             android:orientation= "horizontal"  >
             <RadioButton
                 android:id= "@+id/rd_home"
                 style= "@style/main_btn_style"
                 android:layout_width= "wrap_content"
                 android:layout_height= "wrap_content"
                 android:drawableTop= "@drawable/home_icon"
                 android:text= "主页"  />
             <RadioButton
                 android:id= "@+id/rd_wt"
                 style= "@style/main_btn_style"
                 android:layout_width= "wrap_content"
                 android:layout_height= "wrap_content"
                 android:drawableTop= "@drawable/wb_icon_write_n"
                 android:text= "发表"  />
             <RadioButton
                 android:id= "@+id/rd_msg"
                 style= "@style/main_btn_style"
                 android:layout_width= "wrap_content"
                 android:layout_height= "wrap_content"
                 android:drawableTop= "@drawable/msg_icon"
                 android:text= "信息"  />
             <RadioButton
                 android:id= "@+id/rd_more"
                 style= "@style/main_btn_style"
                 android:layout_width= "wrap_content"
                 android:layout_height= "wrap_content"
                 android:drawableTop= "@drawable/more_icon"
                 android:text= "更多"  />
         </RadioGroup>
     </LinearLayout>
</TabHost>

styles.xml

1
2
3
4
5
6
7
8
9
<style name= "main_btn_style" >
        <item name= "android:button" >@ null </item>
        <item name= "android:textSize" >10dp</item>
        <item name= "android:textColor" >#ffffff</item>
        <item name= "android:gravity" >center_horizontal</item>
        <item name= "android:drawablePadding" >4dp</item>
        <item name= "android:layout_weight" > 1.0 </item>
        <item name= "android:background" >@drawable/main_btn_bg_d</item>
    </style>

main_btn_bg_d.xml

1
2
3
4
5
<?xml version= "1.0"  encoding= "utf-8" ?>
<selector xmlns:android= "http://schemas.android.com/apk/res/android" >
     <item android:drawable= "@drawable/main_btn_bg"  android:state_enabled= "true"  android:state_pressed= "true" ></item>
     <item android:drawable= "@drawable/main_btn_bg"  android:state_checked= "true"  android:state_enabled= "true" ></item>
</selector>

这里需要注意的是:

1.main.xml中:TabWidget的id必须是@android:id/tabs,FrameLayout的id必须是 @android:id/tabcontent。

2.把TabWidget的Visibility设置成了gone!也就是默认难看的风格不见了2011-3-1_2.jpg取而代之的是5个带风格的单选按钮.


MainActivity类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package  com.zhf.android_tabhost;
import  android.app.TabActivity;
import  android.content.Intent;
import  android.os.Bundle;
import  android.widget.RadioGroup;
import  android.widget.RadioGroup.OnCheckedChangeListener;
import  android.widget.TabHost;
import  android.widget.TabHost.TabSpec;
public  class  MainActivity  extends  TabActivity {
     private  TabHost tabHost;
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
     @Override
     public  void  onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.main);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
         tabHost =  this .getTabHost();
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
         TabSpec homeSpec = tabHost.newTabSpec( "home" ).setIndicator( "home" ).setContent( new  Intent( this ,HomeActivity. class ));
         TabSpec writeSpec = tabHost.newTabSpec( "write" ).setIndicator( "write" ).setContent( new  Intent( this ,WriteActivity. class ));
         TabSpec msgSpec = tabHost.newTabSpec( "msg" ).setIndicator( "msg" ).setContent( new  Intent( this ,MsgActivity. class ));
         TabSpec moreSpec = tabHost.newTabSpec( "more" ).setIndicator( "more" ).setContent( new  Intent( this ,MoreActivity. class ));
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
         tabHost.addTab(homeSpec);
         tabHost.addTab(writeSpec);
         tabHost.addTab(msgSpec);
         tabHost.addTab(moreSpec);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
         RadioGroup rg = (RadioGroup)  this .findViewById(R.id.radioGroup);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
         rg.setOnCheckedChangeListener( new  OnCheckedChangeListener() {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
             @Override
             public  void  onCheckedChanged(RadioGroup group,  int  checkedId) {
                 switch  (checkedId) {
                 case  R.id.rd_home:
                     tabHost.setCurrentTabByTag( "home" );
                     break ;
                 case  R.id.rd_wt:
                     tabHost.setCurrentTabByTag( "write" );
                     break ;
                 case  R.id.rd_msg:
                     tabHost.setCurrentTabByTag( "msg" );
                     break ;
                 case  R.id.rd_more:
                     tabHost.setCurrentTabByTag( "more" );
                     break ;
                 default :
                     break ;
                 }
             }
         });
     }
}

注:

1.由于TabWidget被隐藏,所以相关的事件也会无效,这里取巧用RadioGroup与RadioButton的特性来处理切换,然后监听事件调用setCurrentTabByTag来切换Activity。

2.注意即使TabWidget被隐藏,也要为其设置indicator,否则会保持。

效果图:

174435324.png

点击底部就可以实现切换不同的Activity的操作了,这里需要注意的一点是,切换底部菜单时不会重新调用onCreate()方法的!!)



二.底部回调接口实现(使用Fragment)--- 重要!


这种方式使用了最新的Fragment,采用了底部导航栏回调接口的方法,来切换底部菜单,并且每次切换回重新调用onCreate()方法!!


main.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?xml version= "1.0"  encoding= "utf-8" ?>
<LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android"
     xmlns:tools= "http://schemas.android.com/tools"
     android:layout_width= "fill_parent"
     android:layout_height= "fill_parent"
     android:orientation= "vertical"
     tools:context= ".MainActivity"  >
     <LinearLayout
         android:layout_width= "fill_parent"
         android:layout_height= "0dp"
         android:layout_weight= "10"
         android:orientation= "vertical"  >
         <RelativeLayout
             android:id= "@+id/main_title_RelativeLayout"
             android:layout_width= "fill_parent"
             android:layout_height= "50dp"
             android:background= "@drawable/fragment_bottom_normal"
             android:orientation= "horizontal"  >
             <TextView
                 android:id= "@+id/main_title_TextView"
                 android:layout_width= "wrap_content"
                 android:layout_height= "wrap_content"
                 android:layout_centerInParent= "true"
                 android:text= "主页"
                 android:textColor= "@android:color/white"
                 android:textSize= "24sp"  />
         </RelativeLayout>
         <FrameLayout
             android:id= "@+id/main_detail_FrameLayout"
             android:layout_width= "fill_parent"
             android:layout_height= "fill_parent"
             android:background= "#ffffff"  >
         </FrameLayout>
     </LinearLayout>
     <fragment
         android:id= "@+id/bottom_fragment"
         android:name= "com.zhf.frameworkdemo02.fragments.BottomFragment"
         android:layout_width= "fill_parent"
         android:layout_height= "0dp"
         android:layout_weight= "1"  />
</LinearLayout>


这里由于我们底部菜单我们采用了fragment,所以布局里面要留出位置!


BottomFragment类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package  com.zhf.frameworkdemo02.fragments;
import  com.zhf.frameworkdemo02.R;
import  android.app.Activity;
import  android.os.Bundle;
import  android.support.v4.app.Fragment;
import  android.view.LayoutInflater;
import  android.view.View;
import  android.view.ViewGroup;
import  android.widget.RadioGroup;
import  android.widget.RadioGroup.OnCheckedChangeListener;
/**
  * 页面底部导航栏
  *
  * @author ZHF
  *
  */
public  class  BottomFragment  extends  Fragment {
     //默认回调接口实现类的对象
     private  Callbacks callbacks = defaultCallbacks;
     /** Fragment和Activity建立关联的时候调用 **/
     @Override
     public  void  onAttach(Activity activity) {
         super .onAttach(activity);
         //当前类是否实现了底部导航栏点击事件回调接口
         if (!(activity  instanceof  Callbacks)) {
             throw  new  IllegalStateException( "Activity must implements fragment's callbacks !" );
         }
         callbacks = (Callbacks) activity;
     }
     /** 为Fragment加载布局时调用 **/
     @Override
     public  View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
         RadioGroup radioGroup = (RadioGroup) inflater.inflate(R.layout.fragment_bottom, container,  false );
         //绑定监听器
         radioGroup.setOnCheckedChangeListener(changeListener);
         return  radioGroup;
     }
                                                                                                                                                                                                                                                                                                                   
     /**RadioGroup监听器**/
     private  OnCheckedChangeListener changeListener =  new  OnCheckedChangeListener() {
         @Override
         public  void  onCheckedChanged(RadioGroup group,  int  checkedId) {
             System.out.println(checkedId);
             callbacks.onItemSelected(checkedId);  //调用接口中方法
         }
     };
     public  interface  Callbacks{
         /**导航栏回调接口**/
         public  void  onItemSelected( int  item);
     }
     /**默认回调实现类的对象**/
     private  static  Callbacks defaultCallbacks =  new  Callbacks() {
         @Override
         public  void  onItemSelected( int  item) {
         //什么都不干
         }
     };
                                                                                                                                                                                                                                                                                                                   
     /**Fragment和Activity解除关联的时候调用**/
     @Override
     public  void  onDetach() {
         super .onDetach();
        callbacks = defaultCallbacks;
     }
}

底部菜单布局fragment_bottom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<?xml version= "1.0"  encoding= "utf-8" ?>
<RadioGroup xmlns:android= "http://schemas.android.com/apk/res/android"
     android:layout_width= "fill_parent"
     android:layout_height= "fill_parent"
     android:orientation= "horizontal"  >
     <RadioButton
         android:id= "@+id/fragment_bottom_home"
         android:layout_width= "fill_parent"
         android:layout_height= "fill_parent"
         android:layout_weight= "1"
         android:background= "@drawable/fragment_bottom_selector"
         android:button= "@null"
         android:drawableTop= "@drawable/main_readiobutton_home"
         android:gravity= "center"
         android:text= "@string/home"
         android:textColor= "@color/white"
         android:textSize= "12sp"  />
     <View
         android:layout_width= "1dp"
         android:layout_height= "fill_parent"
         android:background= "@color/white"  />
     <RadioButton
         android:id= "@+id/fragment_bottom_order"
         android:layout_width= "fill_parent"
         android:layout_height= "fill_parent"
         android:layout_weight= "1"
         android:background= "@drawable/fragment_bottom_selector"
         android:button= "@null"
         android:drawableTop= "@drawable/main_readiobutton_order"
         android:gravity= "center"
         android:text= "@string/order"
         android:textColor= "@color/white"
         android:textSize= "12sp"  />
     <View
         android:layout_width= "1dp"
         android:layout_height= "fill_parent"
         android:background= "@color/white"
         />
     <RadioButton
         android:id= "@+id/fragment_bottom_notice"
         android:layout_width= "fill_parent"
         android:layout_height= "fill_parent"
         android:layout_weight= "1"
         android:background= "@drawable/fragment_bottom_selector"
         android:button= "@null"
         android:drawableTop= "@drawable/main_readiobutton_notice"
         android:gravity= "center"
         android:text= "@string/notice"
         android:textColor= "@color/white"
         android:textSize= "12sp"  />
     <View
         android:layout_width= "1dp"
         android:layout_height= "fill_parent"
         android:background= "@color/white"  />
     <RadioButton
         android:id= "@+id/fragment_bottom_more"
         android:layout_width= "fill_parent"
         android:layout_height= "fill_parent"
         android:layout_weight= "1"
         android:background= "@drawable/fragment_bottom_selector"
         android:button= "@null"
         android:drawablePadding= "3dip"
         android:drawableTop= "@drawable/main_readiobutton_more"
         android:gravity= "center"
         android:text= "@string/more"
         android:textColor= "@color/white"
         android:textSize= "12sp"  />
</RadioGroup>


这里我们定义了一个框架类:GeneralFragment(所有的fragment界面都需继承它)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package  com.zhf.frameworkdemo02.fragments;
import  java.io.Serializable;
import  com.zhf.frameworkdemo02.R;
import  com.zhf.frameworkdemo02.view.OrderView;
import  com.zhf.frameworkdemo02.view.HomeView;
import  com.zhf.frameworkdemo02.view.MoreView;
import  com.zhf.frameworkdemo02.view.NoticeView;
import  android.os.Bundle;
import  android.support.v4.app.Fragment;
import  android.view.LayoutInflater;
import  android.view.View;
import  android.view.ViewGroup;
import  android.widget.TextView;
/**
  * 框架类,抽象公共方法
  * @author ZHF
  *
  */
public  class  GeneralFragment  extends  Fragment  implements  Serializable{
     /**
      *
      */
     private  static  final  long  serialVersionUID = 1L;
                                                                                                                                                                                                                                                               
     private  int  item;  //用于区分底部菜单项
     protected  static  View main_title_RelativeLayout;  //标题栏
     protected  final  static  String key =  "Bundle" ;    //跳转值传递key的名称
                                                                                                                                                                                                                                                               
     @Override
     public  void  onCreate(Bundle savedInstanceState) {
         // TODO Auto-generated method stub
         super .onCreate(savedInstanceState);
         if (getArguments() !=  null ) {   //根据接收子类传来的arguments判断item的哪一项
             if (getArguments().containsKey(MainFragment.Item)) {
                 item = getArguments().getInt(MainFragment.Item);
             }
         }
     }
                                                                                                                                                                                                                                                               
     /**为Fragment加载布局时调用 **/
     @Override
     public  View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
         View view = inflater.inflate(R.layout.fragment_general, container,  false );
         GeneralFragment fragment =  null ;
         switch (item) {
         case  R.id.fragment_bottom_home:   //初始化主页
             fragment =  new  HomeView();
             break ;
         case  R.id.fragment_bottom_order:
             fragment =  new  OrderView();   //初始化订单
              break ;
         case  R.id.fragment_bottom_notice:
             fragment =  new  NoticeView();    //初始化公告
             break ;
         case  R.id.fragment_bottom_more:
             fragment =  new  MoreView();   //初始化更多
             break ;
         default :
             break ;
         }
         if (fragment !=  null ) {
             //更换mainView中间的内容(home,msg,at,more)
             getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.general_fragment, fragment).commit();
         }
         main_title_RelativeLayout =  ((View) container.getParent()).findViewById(R.id.main_title_RelativeLayout);
         //将生成的view返回
         return  view;
     }
                                                                                                                                                                                                                                                               
     /**设置标题**/
     protected  void  setTitle(Object title) {
         if (main_title_RelativeLayout !=  null ) {
             //标题栏中的文字
             TextView mTvTitle = (TextView) main_title_RelativeLayout.findViewById(R.id.main_title_TextView);
             if (mTvTitle !=  null ) {
                 if (title  instanceof  Integer) {   //整型
                     mTvTitle.setText((Integer)title);
                 else  //字符类型
                     mTvTitle.setText((CharSequence)title);
                 }
             }
         }
     }
                                                                                                                                                                                                                                                               
     /**页面跳转值传递**/
     protected  void  setBundle(Object... objects) {
         Bundle arguments =  new  Bundle();
         arguments.putSerializable(key, objects);
         GeneralFragment generalFragment =  new  GeneralFragment();
         generalFragment.setArguments(arguments);
     }
                                                                                                                                                                                                                                                               
     /**获取所传递的值**/
     protected  Object[] getBundle() {
         if (getArguments() !=  null ) {
             System.out.println( "getBundle" );
             if (getArguments().containsKey(key)) {
                 Object[] object = (Object[]) getArguments().getSerializable(key);
                 return  object;
             }
         }
         return  null ;
     }
                                                                                                                                                                                                                                                               
     /**无参页面跳转**/
     protected  void  toIntent(GeneralFragment generalFragment) {
         if (generalFragment !=  null ) {
             getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.general_fragment, generalFragment).commit();
         }
     }
}


程序入口MainFragment:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package  com.zhf.frameworkdemo02.fragments;
import  com.zhf.frameworkdemo02.R;
import  android.os.Bundle;
import  android.support.v4.app.FragmentActivity;
import  android.support.v4.app.FragmentManager;
/**
  *MainView
  * @author ZHF
  *
  */
public  class  MainFragment  extends  FragmentActivity  implements  BottomFragment.Callbacks {
                                                                                                                                                                                                                                  
     public  final  static  String  Item =  "item" ;
                                                                                                                                                                                                                                  
     @Override
     protected  void  onCreate(Bundle savedInstanceState) {
         // TODO Auto-generated method stub
         super .onCreate(savedInstanceState);
         setContentView(R.layout.main);
         //初始化默认调用接口中item选中方法
         onItemSelected(R.id.fragment_bottom_home);
     }
     @Override
     public  void  onItemSelected( int  item) {
         Bundle arguments =  new  Bundle();
         arguments.putInt(Item, item);  //将选中的底部radio的Id放进去
         GeneralFragment generalFragment =  new  GeneralFragment();
         generalFragment.setArguments(arguments);  //设置参数值
         //这里根据item的ID进行界面跳转
         FragmentManager fm = getSupportFragmentManager();
         fm.beginTransaction().replace(R.id.main_detail_FrameLayout, generalFragment).commit();
     }
}


说明:这里我们的每个界面都将采用Fragment,故每个界面需重写onCreateView()


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package  com.zhf.frameworkdemo02.view;
import  android.os.Bundle;
import  android.view.LayoutInflater;
import  android.view.View;
import  android.view.ViewGroup;
import  com.zhf.frameworkdemo02.R;
import  com.zhf.frameworkdemo02.fragments.GeneralFragment;
/**
  * 主页面
  * @author ZHF
  *
  */
public  class  HomeView  extends  GeneralFragment{
     @Override
     public  void  onCreate(Bundle savedInstanceState) {
         // TODO Auto-generated method stub
         super .onCreate(savedInstanceState);
         super .setTitle( "主页" );
     }
                                                                                                                                               
     @Override
     public  View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
         return  inflater.inflate(R.layout.home, container,  false );
     }
}

(其他三个略)

最终效果图:

225533378.png


ok!大功告成!相当实用的!有兴趣的可以学习一下!


源码下载:http://down.51cto.com/data/1009354



     本文转自zhf651555765 51CTO博客,原文链接:http://blog.51cto.com/smallwoniu/1324123,如需转载请自行联系原作者


相关文章
|
2月前
|
物联网 区块链 vr&ar
未来已来:探索区块链、物联网与虚拟现实技术的融合与应用安卓与iOS开发中的跨平台框架选择
【8月更文挑战第30天】在科技的巨轮下,新技术不断涌现,引领着社会进步。本文将聚焦于当前最前沿的技术——区块链、物联网和虚拟现实,探讨它们各自的发展趋势及其在未来可能的应用场景。我们将从这些技术的基本定义出发,逐步深入到它们的相互作用和集成应用,最后展望它们如何共同塑造一个全新的数字生态系统。
|
27天前
|
前端开发 JavaScript C#
移动应用开发中的跨平台框架解析
【9月更文挑战第5天】在移动应用开发领域,跨平台框架因其“一次编写,处处运行”的便利性而受到开发者的青睐。本文将深入探讨几种流行的跨平台框架,包括React Native、Flutter和Xamarin,并比较它们的优势与局限。我们将通过代码示例揭示这些框架如何简化移动应用的开发过程,同时保持高性能和良好的用户体验。无论你是新手还是有经验的开发者,这篇文章都将成为你了解和选择跨平台框架的宝贵资源。
50 19
|
15天前
|
前端开发 Java 数据库
💡Android开发者必看!掌握这5大框架,轻松打造爆款应用不是梦!🏆
在Android开发领域,框架犹如指路明灯,助力开发者加速应用开发并提升品质。本文将介绍五大必备框架:Retrofit简化网络请求,Room优化数据库访问,MVVM架构提高代码可维护性,Dagger 2管理依赖注入,Jetpack Compose革新UI开发。掌握这些框架,助你在竞争激烈的市场中脱颖而出,打造爆款应用。
80 3
|
22天前
|
编译器 Android开发 开发者
带你了解Android Jetpack库中的依赖注入框架:Hilt
本文介绍了Hilt,这是Google为Android开发的依赖注入框架,基于Dagger构建,旨在简化依赖注入过程。Hilt通过自动化的组件和注解减少了DI的样板代码,提高了应用的可测试性和可维护性。文章详细讲解了Hilt的主要概念、基本用法及原理,帮助开发者更好地理解和应用Hilt。
40 8
|
24天前
|
人工智能 开发框架 搜索推荐
移动应用开发的未来:跨平台框架与AI的融合
在移动互联网飞速发展的今天,移动应用开发已成为技术革新的前沿阵地。本文将探讨跨平台框架的兴起,以及人工智能技术如何与移动应用开发相结合,从而引领行业走向更加智能化、高效化的未来。文章通过分析当前流行的跨平台开发工具和AI技术的应用实例,为读者提供对未来移动应用开发的独到见解和预测。
47 3
|
25天前
|
开发框架 前端开发 Android开发
移动应用开发的演变:从原生到跨平台框架
在数字化时代,移动应用已成为我们日常生活不可或缺的一部分。随着技术的不断演进,移动应用开发也经历了从原生开发到跨平台框架的变革。本文将探讨这一演变过程,分析不同开发模式的优势与挑战,并展望未来移动应用开发的发展趋势。
|
2月前
|
设计模式 Java Android开发
探索安卓应用开发:从新手到专家的旅程探索iOS开发中的SwiftUI框架
【8月更文挑战第29天】本文旨在通过一个易于理解的旅程比喻,带领读者深入探讨安卓应用开发的各个方面。我们将从基础概念入手,逐步过渡到高级技术,最后讨论如何维护和推广你的应用。无论你是编程新手还是有经验的开发者,这篇文章都将为你提供有价值的见解和实用的代码示例。让我们一起开始这段激动人心的旅程吧!
|
2月前
|
API Android开发
Android使用AlertDialog实现弹出菜单
本文分享了在Android开发中使用AlertDialog实现弹出菜单的方法,并通过代码示例和错误处理,展示了如何避免因资源ID找不到导致的crash问题。
36 1
|
24天前
|
人工智能 开发框架 前端开发
移动应用开发的未来:探索跨平台框架与AI的融合
随着智能手机的普及和移动技术的飞速发展,移动应用已成为我们日常生活的一部分。本文将探讨移动应用开发的最新趋势,特别是跨平台开发框架的兴起和人工智能技术的结合如何塑造未来移动应用的发展方向。我们将从React Native和Flutter等流行框架谈起,分析它们如何简化开发流程、降低成本并提高应用性能。同时,本文也将深入讨论人工智能如何在用户体验、安全性和个性化服务方面为移动应用带来革命性的变化。最后,我们将展望未来移动应用开发的新机遇和挑战。
22 0
|
28天前
|
开发框架 缓存 前端开发
移动应用开发的未来趋势:跨平台框架与性能优化
随着智能手机的普及和移动计算能力的提升,移动应用开发正迎来前所未有的机遇与挑战。本文将探讨移动应用开发的最新趋势,重点分析跨平台开发框架的兴起以及开发者如何通过性能优化来满足用户对高质量移动体验的需求。我们将从技术角度出发,深入讨论Flutter、React Native等热门框架的优势与局限,并分享实用的性能优化技巧,旨在为移动应用开发者提供有价值的参考和启示。
下一篇
无影云桌面