android tabbar切换的实现

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24740977

Android现在实现Tab类型的界面方式越来越多,今天就把常见的实现方式给大家来个总结。目前写了:

1、传统的ViewPager实现

2、FragmentManager+Fragment实现

3、ViewPager+FragmentPagerAdapter实现

4、TabPageIndicator+ViewPager+FragmentPagerAdapter


1、传统的ViewPager实现

主要就是ViewPager+ViewAdapter这个还是比较常见的,就不多说了

效果图:


代码:

[java]  view plain  copy
 
  1. package com.example.mainframework02;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import android.app.Activity;  
  7. import android.os.Bundle;  
  8. import android.support.v4.view.PagerAdapter;  
  9. import android.support.v4.view.ViewPager;  
  10. import android.support.v4.view.ViewPager.OnPageChangeListener;  
  11. import android.view.LayoutInflater;  
  12. import android.view.View;  
  13. import android.view.ViewGroup;  
  14. import android.widget.ImageButton;  
  15. import android.widget.ImageView;  
  16. import android.widget.LinearLayout;  
  17.   
  18. public class TraditionalViewPagerAcvitity extends Activity  
  19. {  
  20.   
  21.     /** 
  22.      * ViewPager 
  23.      */  
  24.     private ViewPager mViewPager;  
  25.     /** 
  26.      * ViewPager的适配器 
  27.      */  
  28.     private PagerAdapter mAdapter;  
  29.     private List mViews;  
  30.     private LayoutInflater mInflater;  
  31.       
  32.     private int currentIndex;  
  33.   
  34.     /** 
  35.      * 底部四个按钮 
  36.      */  
  37.     private LinearLayout mTabBtnWeixin;  
  38.     private LinearLayout mTabBtnFrd;  
  39.     private LinearLayout mTabBtnAddress;  
  40.     private LinearLayout mTabBtnSettings;  
  41.   
  42.     @Override  
  43.     protected void onCreate(Bundle savedInstanceState)  
  44.     {  
  45.         super.onCreate(savedInstanceState);  
  46.         setContentView(R.layout.activity_main);  
  47.         mInflater = LayoutInflater.from(this);  
  48.         mViewPager = (ViewPager) findViewById(R.id.id_viewpager);  
  49.           
  50.         /** 
  51.          * 初始化View 
  52.          */  
  53.         initView();  
  54.           
  55.         mViewPager.setAdapter(mAdapter);  
  56.   
  57.         mViewPager.setOnPageChangeListener(new OnPageChangeListener()  
  58.         {  
  59.   
  60.             @Override  
  61.             public void onPageSelected(int position)  
  62.             {  
  63.                 resetTabBtn();  
  64.                 switch (position)  
  65.                 {  
  66.                 case 0:  
  67.                     ((ImageButton) mTabBtnWeixin.findViewById(R.id.btn_tab_bottom_weixin))  
  68.                             .setImageResource(R.drawable.tab_weixin_pressed);  
  69.                     break;  
  70.                 case 1:  
  71.                     ((ImageButton) mTabBtnFrd.findViewById(R.id.btn_tab_bottom_friend))  
  72.                             .setImageResource(R.drawable.tab_find_frd_pressed);  
  73.                     break;  
  74.                 case 2:  
  75.                     ((ImageButton) mTabBtnAddress.findViewById(R.id.btn_tab_bottom_contact))  
  76.                             .setImageResource(R.drawable.tab_address_pressed);  
  77.                     break;  
  78.                 case 3:  
  79.                     ((ImageButton) mTabBtnSettings.findViewById(R.id.btn_tab_bottom_setting))  
  80.                             .setImageResource(R.drawable.tab_settings_pressed);  
  81.                     break;  
  82.                 }  
  83.   
  84.                 currentIndex = position;  
  85.             }  
  86.   
  87.             @Override  
  88.             public void onPageScrolled(int arg0, float arg1, int arg2)  
  89.             {  
  90.   
  91.             }  
  92.   
  93.             @Override  
  94.             public void onPageScrollStateChanged(int arg0)  
  95.             {  
  96.             }  
  97.         });  
  98.   
  99.     }  
  100.   
  101.     protected void resetTabBtn()  
  102.     {  
  103.         ((ImageButton) mTabBtnWeixin.findViewById(R.id.btn_tab_bottom_weixin))  
  104.                 .setImageResource(R.drawable.tab_weixin_normal);  
  105.         ((ImageButton) mTabBtnFrd.findViewById(R.id.btn_tab_bottom_friend))  
  106.                 .setImageResource(R.drawable.tab_find_frd_normal);  
  107.         ((ImageButton) mTabBtnAddress.findViewById(R.id.btn_tab_bottom_contact))  
  108.                 .setImageResource(R.drawable.tab_address_normal);  
  109.         ((ImageButton) mTabBtnSettings.findViewById(R.id.btn_tab_bottom_setting))  
  110.                 .setImageResource(R.drawable.tab_settings_normal);  
  111.     }  
  112.   
  113.     private void initView()  
  114.     {  
  115.   
  116.         mTabBtnWeixin = (LinearLayout) findViewById(R.id.id_tab_bottom_weixin);  
  117.         mTabBtnFrd = (LinearLayout) findViewById(R.id.id_tab_bottom_friend);  
  118.         mTabBtnAddress = (LinearLayout) findViewById(R.id.id_tab_bottom_contact);  
  119.         mTabBtnSettings = (LinearLayout) findViewById(R.id.id_tab_bottom_setting);  
  120.   
  121.         mViews = new ArrayList();  
  122.         View first = mInflater.inflate(R.layout.main_tab_01, null);  
  123.         View second = mInflater.inflate(R.layout.main_tab_02, null);  
  124.         View third = mInflater.inflate(R.layout.main_tab_03, null);  
  125.         View fourth = mInflater.inflate(R.layout.main_tab_04, null);  
  126.         mViews.add(first);  
  127.         mViews.add(second);  
  128.         mViews.add(third);  
  129.         mViews.add(fourth);  
  130.   
  131.         mAdapter = new PagerAdapter()  
  132.         {  
  133.             @Override  
  134.             public void destroyItem(ViewGroup container, int position, Object object)  
  135.             {  
  136.                 container.removeView(mViews.get(position));  
  137.             }  
  138.   
  139.             @Override  
  140.             public Object instantiateItem(ViewGroup container, int position)  
  141.             {  
  142.                 View view = mViews.get(position);  
  143.                 container.addView(view);  
  144.                 return view;  
  145.             }  
  146.   
  147.             @Override  
  148.             public boolean isViewFromObject(View arg0, Object arg1)  
  149.             {  
  150.                 return arg0 == arg1;  
  151.             }  
  152.   
  153.             @Override  
  154.             public int getCount()  
  155.             {  
  156.                 return mViews.size();  
  157.             }  
  158.         };  
  159.     }  
  160.   
  161. }  
评价:所有的代码都集中在一个Activity中,显得代码比较乱。

2、FragmentManager+Fragment实现

主要利用了Fragment在主内容界面对Fragment的add,hide等事务操作。

效果图:

android tabbar切换的实现_第1张图片

代码:

主Activity

[java]  view plain  copy
 
  1. package com.example.mainframework02.fragment;  
  2.   
  3. import android.annotation.SuppressLint;  
  4. import android.app.Activity;  
  5. import android.app.FragmentManager;  
  6. import android.app.FragmentTransaction;  
  7. import android.os.Bundle;  
  8. import android.view.View;  
  9. import android.view.View.OnClickListener;  
  10. import android.widget.ImageButton;  
  11. import android.widget.LinearLayout;  
  12.   
  13. import com.example.mainframework02.R;  
  14.   
  15. public class FragmentMainActivity extends Activity implements OnClickListener  
  16. {  
  17.     private MainTab02 mTab02;  
  18.     private MainTab01 mTab01;  
  19.     private MainTab03 mTab03;  
  20.     private MainTab04 mTab04;  
  21.   
  22.     /** 
  23.      * 底部四个按钮 
  24.      */  
  25.     private LinearLayout mTabBtnWeixin;  
  26.     private LinearLayout mTabBtnFrd;  
  27.     private LinearLayout mTabBtnAddress;  
  28.     private LinearLayout mTabBtnSettings;  
  29.     /** 
  30.      * 用于对Fragment进行管理 
  31.      */  
  32.     private FragmentManager fragmentManager;  
  33.   
  34.     @SuppressLint("NewApi")  
  35.     @Override  
  36.     protected void onCreate(Bundle savedInstanceState)  
  37.     {  
  38.         super.onCreate(savedInstanceState);  
  39.         setContentView(R.layout.fragment_main);  
  40.         initViews();  
  41.         fragmentManager = getFragmentManager();  
  42.         setTabSelection(0);  
  43.     }  
  44.   
  45.       
  46.   
  47.     private void initViews()  
  48.     {  
  49.   
  50.         mTabBtnWeixin = (LinearLayout) findViewById(R.id.id_tab_bottom_weixin);  
  51.         mTabBtnFrd = (LinearLayout) findViewById(R.id.id_tab_bottom_friend);  
  52.         mTabBtnAddress = (LinearLayout) findViewById(R.id.id_tab_bottom_contact);  
  53.         mTabBtnSettings = (LinearLayout) findViewById(R.id.id_tab_bottom_setting);  
  54.   
  55.         mTabBtnWeixin.setOnClickListener(this);  
  56.         mTabBtnFrd.setOnClickListener(this);  
  57.         mTabBtnAddress.setOnClickListener(this);  
  58.         mTabBtnSettings.setOnClickListener(this);  
  59.     }  
  60.   
  61.     @Override  
  62.     public void onClick(View v)  
  63.     {  
  64.         switch (v.getId())  
  65.         {  
  66.         case R.id.id_tab_bottom_weixin:  
  67.             setTabSelection(0);  
  68.             break;  
  69.         case R.id.id_tab_bottom_friend:  
  70.             setTabSelection(1);  
  71.             break;  
  72.         case R.id.id_tab_bottom_contact:  
  73.             setTabSelection(2);  
  74.             break;  
  75.         case R.id.id_tab_bottom_setting:  
  76.             setTabSelection(3);  
  77.             break;  
  78.   
  79.         default:  
  80.             break;  
  81.         }  
  82.     }  
  83.   
  84.     /** 
  85.      * 根据传入的index参数来设置选中的tab页。 
  86.      *  
  87.      */  
  88.     @SuppressLint("NewApi")  
  89.     private void setTabSelection(int index)  
  90.     {  
  91.         // 重置按钮  
  92.         resetBtn();  
  93.         // 开启一个Fragment事务  
  94.         FragmentTransaction transaction = fragmentManager.beginTransaction();  
  95.         // 先隐藏掉所有的Fragment,以防止有多个Fragment显示在界面上的情况  
  96.         hideFragments(transaction);  
  97.         switch (index)  
  98.         {  
  99.         case 0:  
  100.             // 当点击了消息tab时,改变控件的图片和文字颜色  
  101.             ((ImageButton) mTabBtnWeixin.findViewById(R.id.btn_tab_bottom_weixin))  
  102.                     .setImageResource(R.drawable.tab_weixin_pressed);  
  103.             if (mTab01 == null)  
  104.             {  
  105.                 // 如果MessageFragment为空,则创建一个并添加到界面上  
  106.                 mTab01 = new MainTab01();  
  107.                 transaction.add(R.id.id_content, mTab01);  
  108.             } else  
  109.             {  
  110.                 // 如果MessageFragment不为空,则直接将它显示出来  
  111.                 transaction.show(mTab01);  
  112.             }  
  113.             break;  
  114.         case 1:  
  115.             // 当点击了消息tab时,改变控件的图片和文字颜色  
  116.             ((ImageButton) mTabBtnFrd.findViewById(R.id.btn_tab_bottom_friend))  
  117.                     .setImageResource(R.drawable.tab_find_frd_pressed);  
  118.             if (mTab02 == null)  
  119.             {  
  120.                 // 如果MessageFragment为空,则创建一个并添加到界面上  
  121.                 mTab02 = new MainTab02();  
  122.                 transaction.add(R.id.id_content, mTab02);  
  123.             } else  
  124.             {  
  125.                 // 如果MessageFragment不为空,则直接将它显示出来  
  126.                 transaction.show(mTab02);  
  127.             }  
  128.             break;  
  129.         case 2:  
  130.             // 当点击了动态tab时,改变控件的图片和文字颜色  
  131.             ((ImageButton) mTabBtnAddress.findViewById(R.id.btn_tab_bottom_contact))  
  132.                     .setImageResource(R.drawable.tab_address_pressed);  
  133.             if (mTab03 == null)  
  134.             {  
  135.                 // 如果NewsFragment为空,则创建一个并添加到界面上  
  136.                 mTab03 = new MainTab03();  
  137.                 transaction.add(R.id.id_content, mTab03);  
  138.             } else  
  139.             {  
  140.                 // 如果NewsFragment不为空,则直接将它显示出来  
  141.                 transaction.show(mTab03);  
  142.             }  
  143.             break;  
  144.         case 3:  
  145.             // 当点击了设置tab时,改变控件的图片和文字颜色  
  146.             ((ImageButton) mTabBtnSettings.findViewById(R.id.btn_tab_bottom_setting))  
  147.                     .setImageResource(R.drawable.tab_settings_pressed);  
  148.             if (mTab04 == null)  
  149.             {  
  150.                 // 如果SettingFragment为空,则创建一个并添加到界面上  
  151.                 mTab04 = new MainTab04();  
  152.                 transaction.add(R.id.id_content, mTab04);  
  153.             } else  
  154.             {  
  155.                 // 如果SettingFragment不为空,则直接将它显示出来  
  156.                 transaction.show(mTab04);  
  157.             }  
  158.             break;  
  159.         }  
  160.         transaction.commit();  
  161.     }  
  162.   
  163.     /** 
  164.      * 清除掉所有的选中状态。 
  165.      */  
  166.     private void resetBtn()  
  167.     {  
  168.         ((ImageButton) mTabBtnWeixin.findViewById(R.id.btn_tab_bottom_weixin))  
  169.                 .setImageResource(R.drawable.tab_weixin_normal);  
  170.         ((ImageButton) mTabBtnFrd.findViewById(R.id.btn_tab_bottom_friend))  
  171.                 .setImageResource(R.drawable.tab_find_frd_normal);  
  172.         ((ImageButton) mTabBtnAddress.findViewById(R.id.btn_tab_bottom_contact))  
  173.                 .setImageResource(R.drawable.tab_address_normal);  
  174.         ((ImageButton) mTabBtnSettings.findViewById(R.id.btn_tab_bottom_setting))  
  175.                 .setImageResource(R.drawable.tab_settings_normal);  
  176.     }  
  177.   
  178.     /** 
  179.      * 将所有的Fragment都置为隐藏状态。 
  180.      *  
  181.      * @param transaction 
  182.      *            用于对Fragment执行操作的事务 
  183.      */  
  184.     @SuppressLint("NewApi")  
  185.     private void hideFragments(FragmentTransaction transaction)  
  186.     {  
  187.         if (mTab01 != null)  
  188.         {  
  189.             transaction.hide(mTab01);  
  190.         }  
  191.         if (mTab02 != null)  
  192.         {  
  193.             transaction.hide(mTab02);  
  194.         }  
  195.         if (mTab03 != null)  
  196.         {  
  197.             transaction.hide(mTab03);  
  198.         }  
  199.         if (mTab04 != null)  
  200.         {  
  201.             transaction.hide(mTab04);  
  202.         }  
  203.           
  204.     }  
  205.   
  206. }  

各个TabFragment,一共四个TabFragment,下面贴出两个,基本都一样。

[java]  view plain  copy
 
  1. package com.example.mainframework02.fragment;  
  2.   
  3. import android.annotation.SuppressLint;  
  4. import android.app.Fragment;  
  5. import android.os.Bundle;  
  6. import android.view.LayoutInflater;  
  7. import android.view.View;  
  8. import android.view.ViewGroup;  
  9.   
  10. @SuppressLint("NewApi")  
  11. public class MainTab01 extends Fragment  
  12. {  
  13.   
  14.     @Override  
  15.     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)  
  16.     {  
  17.         return inflater.inflate(com.example.mainframework02.R.layout.main_tab_01, container, false);  
  18.   
  19.     }  
  20.   
  21. }  

[java]  view plain  copy
 
  1. package com.example.mainframework02.fragment;  
  2.   
  3. import android.annotation.SuppressLint;  
  4. import android.app.Fragment;  
  5. import android.os.Bundle;  
  6. import android.view.LayoutInflater;  
  7. import android.view.View;  
  8. import android.view.ViewGroup;  
  9.   
  10. import com.example.mainframework02.R;  
  11.   
  12. @SuppressLint("NewApi")  
  13. public class MainTab02 extends Fragment  
  14. {  
  15.   
  16.     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)  
  17.     {  
  18.         return inflater.inflate(R.layout.main_tab_02, container, false);  
  19.   
  20.     }  
  21.   
  22. }  
评价:每个Fragment中的控件的处理,都是独立到各自的类中,相对来说主Activity简化了不少,可惜没有左右滑动的效果了。


3、ViewPager+Fragment实现

主要通过ViewPager和FragmentPagerAdapter一起来实现。

效果图:

android tabbar切换的实现_第2张图片

代码:

主Activity

[java]  view plain  copy
 
  1. package com.example.mainframework03;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import android.os.Bundle;  
  7. import android.support.v4.app.Fragment;  
  8. import android.support.v4.app.FragmentActivity;  
  9. import android.support.v4.app.FragmentPagerAdapter;  
  10. import android.support.v4.view.ViewPager;  
  11. import android.support.v4.view.ViewPager.OnPageChangeListener;  
  12. import android.widget.ImageButton;  
  13. import android.widget.LinearLayout;  
  14.   
  15. public class MainActivity extends FragmentActivity  
  16. {  
  17.   
  18.     private ViewPager mViewPager;  
  19.     private FragmentPagerAdapter mAdapter;  
  20.     private List mFragments = new ArrayList();  
  21.       
  22.       
  23.     /** 
  24.      * 底部四个按钮 
  25.      */  
  26.     private LinearLayout mTabBtnWeixin;  
  27.     private LinearLayout mTabBtnFrd;  
  28.     private LinearLayout mTabBtnAddress;  
  29.     private LinearLayout mTabBtnSettings;  
  30.   
  31.   
  32.     @Override  
  33.     protected void onCreate(Bundle savedInstanceState)  
  34.     {  
  35.         super.onCreate(savedInstanceState);  
  36.         setContentView(R.layout.activity_main);  
  37.         mViewPager = (ViewPager) findViewById(R.id.id_viewpager);  
  38.   
  39.           
  40.         initView();  
  41.           
  42.           
  43.   
  44.         mAdapter = new FragmentPagerAdapter(getSupportFragmentManager())  
  45.         {  
  46.   
  47.             @Override  
  48.             public int getCount()  
  49.             {  
  50.                 return mFragments.size();  
  51.             }  
  52.   
  53.             @Override  
  54.             public Fragment getItem(int arg0)  
  55.             {  
  56.                 return mFragments.get(arg0);  
  57.             }  
  58.         };  
  59.           
  60.         mViewPager.setAdapter(mAdapter);  
  61.           
  62.           
  63.         mViewPager.setOnPageChangeListener(new OnPageChangeListener()  
  64.         {  
  65.   
  66.             private int currentIndex;  
  67.   
  68.             @Override  
  69.             public void onPageSelected(int position)  
  70.             {  
  71.                 resetTabBtn();  
  72.                 switch (position)  
  73.                 {  
  74.                 case 0:  
  75.                     ((ImageButton) mTabBtnWeixin.findViewById(R.id.btn_tab_bottom_weixin))  
  76.                             .setImageResource(R.drawable.tab_weixin_pressed);  
  77.                     break;  
  78.                 case 1:  
  79.                     ((ImageButton) mTabBtnFrd.findViewById(R.id.btn_tab_bottom_friend))  
  80.                             .setImageResource(R.drawable.tab_find_frd_pressed);  
  81.                     break;  
  82.                 case 2:  
  83.                     ((ImageButton) mTabBtnAddress.findViewById(R.id.btn_tab_bottom_contact))  
  84.                             .setImageResource(R.drawable.tab_address_pressed);  
  85.                     break;  
  86.                 case 3:  
  87.                     ((ImageButton) mTabBtnSettings.findViewById(R.id.btn_tab_bottom_setting))  
  88.                             .setImageResource(R.drawable.tab_settings_pressed);  
  89.                     break;  
  90.                 }  
  91.   
  92.                 currentIndex = position;  
  93.             }  
  94.   
  95.             @Override  
  96.             public void onPageScrolled(int arg0, float arg1, int arg2)  
  97.             {  
  98.   
  99.             }  
  100.   
  101.             @Override  
  102.             public void onPageScrollStateChanged(int arg0)  
  103.             {  
  104.             }  
  105.         });  
  106.   
  107.     }  
  108.       
  109.     protected void resetTabBtn()  
  110.     {  
  111.         ((ImageButton) mTabBtnWeixin.findViewById(R.id.btn_tab_bottom_weixin))  
  112.                 .setImageResource(R.drawable.tab_weixin_normal);  
  113.         ((ImageButton) mTabBtnFrd.findViewById(R.id.btn_tab_bottom_friend))  
  114.                 .setImageResource(R.drawable.tab_find_frd_normal);  
  115.         ((ImageButton) mTabBtnAddress.findViewById(R.id.btn_tab_bottom_contact))  
  116.                 .setImageResource(R.drawable.tab_address_normal);  
  117.         ((ImageButton) mTabBtnSettings.findViewById(R.id.btn_tab_bottom_setting))  
  118.                 .setImageResource(R.drawable.tab_settings_normal);  
  119.     }  
  120.   
  121.     private void initView()  
  122.     {  
  123.   
  124.         mTabBtnWeixin = (LinearLayout) findViewById(R.id.id_tab_bottom_weixin);  
  125.         mTabBtnFrd = (LinearLayout) findViewById(R.id.id_tab_bottom_friend);  
  126.         mTabBtnAddress = (LinearLayout) findViewById(R.id.id_tab_bottom_contact);  
  127.         mTabBtnSettings = (LinearLayout) findViewById(R.id.id_tab_bottom_setting);  
  128.   
  129.         MainTab01 tab01 = new MainTab01();  
  130.         MainTab02 tab02 = new MainTab02();  
  131.         MainTab03 tab03 = new MainTab03();  
  132.         MainTab04 tab04 = new MainTab04();  
  133.         mFragments.add(tab01);  
  134.         mFragments.add(tab02);  
  135.         mFragments.add(tab03);  
  136.         mFragments.add(tab04);  
  137.     }  
  138. }  

还有4个TabFragment,下面贴一个,四个基本一样

[java]  view plain  copy
 
  1. package com.example.mainframework03;  
  2.   
  3. import android.os.Bundle;  
  4. import android.support.v4.app.Fragment;  
  5. import android.view.LayoutInflater;  
  6. import android.view.View;  
  7. import android.view.ViewGroup;  
  8.   
  9. public class MainTab01 extends Fragment  
  10. {  
  11.   
  12.     @Override  
  13.     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)  
  14.     {  
  15.         return  inflater.inflate(R.layout.main_tab_01, container, false);  
  16.       
  17.     }  
  18.   
  19. }  
评价:实现效果和第一种效果一模一样,每个Fragment独自处理自己内部的逻辑,代码整洁很多,并且支持左右滑动。感觉是第一种和第二种的结合版本。


4、TabPageIndicator+ViewPager+FragmentPagerAdapter

实现方式和3是一致的,但是使用了TabPageIndicator作为tab的指示器,效果还是不错的,这个之前写过,就不再贴代码了。

效果图:

android tabbar切换的实现_第3张图片

参考Android 使用Fragment,ViewPagerIndicator 制作csdn app主要框架


好了,就总结了这么多,肯定还有很多别的实现方式,大家可以留言,有时间会继续完善这篇总结的。



第一种和第二种的源码

第三种方式的源码

本来想一起,无奈,一会v4.Fragment一会Fragment就分开了,嘿嘿,各位留个言,赞一个,算是对我的支持。



该博客视频教程已经更新:多种多样的App主界面Tab实现方法 ,期待您的关注。


----------------------------------------------------------------------------------------------------------

博主部分视频已经上线,如果你不喜欢枯燥的文本,请猛戳(初录,期待您的支持):

视频目录地址:本人录制的视频教程

你可能感兴趣的:(安卓)