首页 > 编程技术 > android

Xamarin框架开发Android搜索框 Search Dialog实例

发布时间:2016-9-20 19:55

Android搜索有Search Dialog及SearchView两种方式,本教程我们讲讲用Xamarin框架如果开发ndroid搜索框 Search Dialog。

Android 的搜索有两种可用方式:Search Dialog,SearchView。

SearchView 简单,随意使用,这里主要说说 Search Dialog 的基本用法, 因为 Xamarin 的处理方式稍稍和 原生 Android 有些不同。

效果:



Searchable

要使用 Search Dialog 需要配置一个搜索配置文件 : 放到Resources/xml 目录下 。

如果xml 目录不存在,需要手动创建一个。

文件名随便, 一般取 searchable.xml

<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/SearchLabel"
    android:hint="@string/SearchPlaceHolder"
    >
</searchable>

根节点 必须是 searchable 。

android:label 是必填项

android:hint 就是 html5 中的 placeholder

其它属选项请参考:

http://developer.android.com/guide/topics/search/searchable-config.html

Activity 启用 Search Diaog 功能

要启用 Search Dialog , 还必须在 Activity 上开启搜索

在原生的 Android App 里可以直接修改 manifest 文件。

如下 :

<activity android:name="Search" >
  <intent-filter>
    <action android:name="android.intent.action.SEARCH" />
  </intent-filter>
  <meta-data android:name="android.app.searchable" android:resource="@xml/searchable"/>
</activity>

<activity android:name=".MainActivity" >
  <meta-data android:name="android.app.default_searchable"
             android:value=".Search" />
</activity>

android:resource="@xml/searchable" 即指上面的配置文件 (xml/searchable.xml)

黄色标注出来的,为固定字符串。

这一部分可以参考:

http://developer.android.com/guide/topics/search/search-dialog.html

在 Xamarin 下, manifest 文件即 properties 下面的 AndroidManifest.xml



该文件由 Xamarin 自行维护, 不推荐直接修改。

要开启 Activity 的搜索, 可以这样:

1, 新建一个 SearchActivity

[MetaData("android.app.searchable", Resource = "@xml/searchable")]
[IntentFilter(new[] { Intent.ActionSearch })]
[Activity(Label = "SearchActivity", Name = "aA.SearchA")] // aA.SearchA , aA为包名, 必须为小写字母开头
public class SearchActivity : Activity {
    protected override void OnCreate(Bundle bundle) {
        base.OnCreate(bundle);


        if (this.Intent.Action.Equals(Intent.ActionSearch)) {
            var query = this.Intent.GetStringExtra(SearchManager.Query);
            Toast.MakeText(this, query, ToastLength.Short);
        }
    }
}

2,在要使用 Search Dialog 的 Activity 上这样写:

[MetaData("android.app.default_searchable", Value = "aA.SearchA")]
[Activity(Label = "Search", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity {

其中 SearchActivity 上的 Activity 必须指定 Name, 而且必须是 xxx.xxx.xxx 的结构,如果只写 xxx , 编译会报错:缺少 package 名称。



package 名称必须以小写字母开头, 否则打包的时会报错:



在需要使用 Search Dialog 的 Activity 上 (上面示例中的的 MainActivity)的 MetaData 中指定 Value 为 SearchActivity 的 Name (aA.SearchA)

费这个劲加这个 Name 是因为 :

http://developer.xamarin.com/guides/android/advanced_topics/working_with_androidmanifest.xml/

Activity Name

Beginning with Xamarin.Android 5.1, the type name of an activity is based on the MD5SUM of the assembly-qualified name of the type being exported. This allows the same fully-qualified name to be provided from two different assemblies and not get a packaging error. (Before Xamarin.Android 5.1, the default type name of the activity was created from the lowercased namespace and the class name.)

If you wish to override this default and explicitly specify the name of your activity, use the Name property:

在 Xamarin.Android 5.1 以后, activity 的名字会被 MD5SUM 处理, 像这样:



编译后, 可以查看 obj\Debug\android\AndroidManifest.xml 的最终结果。

如何获取输入搜索内容

要使用 Search Dialog 可见,需要在启用了 Search Dialog 的 Activity 上触发:onSearchRequested 方法。

private void Btn_Click(object sender, EventArgs e) {
    this.OnSearchRequested();
}

有些 Android 机, 会自带一个 搜索按钮, 点这个按钮,也是一样会调用这个 OnSearchRequested.

当用户执行搜索的时候,系统会创建一个 Intent 存储用户的查询。

在 SearchActivity 中,

if (this.Intent.Action.Equals(Intent.ActionSearch)) {
    var query = this.Intent.GetStringExtra(SearchManager.Query);
    Toast.MakeText(this, query, ToastLength.Short);
}

如果想传递额外的参数到 SearchActivity, 可以这样传递:

public override bool OnSearchRequested() {
            var bundle = new Bundle();
            bundle.PutBoolean("Key1", true);
            this.StartSearch(null, false, bundle, false);
            return true;
        }

获取额外参数可以这样:

var bundle = intent.GetBundleExtra(SearchManager.AppData);
if (bundle != null) {
    var key1 = bundle.GetBoolean("Key1");
    var key2 = bundle.GetBoolean("Key2");
}



Android搜索框架开发


Android是google的产品,所以自然是少不了搜索。先看看Android一些应用中的搜索对话框。


s1

图1 Android中的全局搜索


s2

图2 联系人搜索


s3

图3 音乐搜索

以上都是通过按下实体键盘上的搜索按钮弹出的一个搜索对话框,当然搜索关键词提示是少不了的。如何实现呢?慢慢来!呵呵。

一、配置搜索描述文件

在res中的xml文件加创建sreachable.xml,内容如下:

<searchable xmlns:android="http://schemas.android.com/apk/res/android"
        android:label="@string/search_label"
        android:hint="@string/search_hint"
        android:searchSettingsDescription="@string/settings_description">

二、创建SearchableMusicActivity.java

至少需要实现onCreate方法显示出来吧。

三、配置AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.halzhang.android.search" android:versionCode="1"
    android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".SearchableMusicActivity"
            android:label="@string/app_name" android:theme="@android:style/Theme.NoTitleBar">
            <intent-filter>
               <action android:name="android.intent.action.MAIN" />
               <category android:name="android.intent.category.LAUNCHER" />
           </intent-filter>
           <intent-filter>
           <!-- 配置action -->
               <action android:name="android.intent.action.SEARCH" />
           </intent-filter>
           <!-- 指定搜索的配置文件 -->
           <meta-data android:name="android.app.searchable"
               android:resource="@xml/searchable" />
       </activity>
       <meta-data android:name="android.app.default_searchable"
           android:value=".SearchableMusicActivity" />

通过以上三步就能实现搜索对话框了。

device


android开发自定义UI模板应用非常广范,因为我们得根据自己的设计风格,本文我们将通过图文教程讲解android UI自定义模板。

每个设计良好的App都是自定义标题栏,在自定义标题栏的过程中大部分人可能都是自定义一个标题的xml文件,然后在需要的地方直接通过include来引用,这比起在每个布局文件中写标题栏已经进化很多了,但仍然不是最简单有效的方法,我们为什么不能自定义一个标题控件呢?今天就带大家自己做一个标题栏控件。效果图如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="ToolBar">
        <attr name="title" format="string" />
        <attr name="titleTextSize" format="dimension" />
        <attr name="titleTextColor" format="color" />
        <attr name="leftBackground" format="reference|color" />
        <attr name="leftText" format="string" />
        <attr name="leftTextColor" format="reference|color" />
        <attr name="rightBackground" format="reference|color" />
        <attr name="rightText" format="string" />
        <attr name="rightTextColor" format="reference|color" />
    </declare-styleable>
</resources>


前面的name是我们要使用的属性名称,后面的format表示该属性接受的值的格式,string表示该属性的值是一个字符串,color表示该属性的值是一个颜色值,dimension表示该属性的值是一个尺寸,reference表示该属性的值可以参考某一个资源id,其他常见的format值还有:boolean(布尔值)、float(浮点值)、integer(整型值)、fraction(百分数)、enum(枚举值)、flag(位或运算)。

第二步:自定义标题类
在Java文件中自定义一个类继承RelativeLayout,并实现它的构造方法,我们的标题栏由三部分组成,左右两边各是一个Button,中间是一个TextView,因此我们在这个布局文件中要做的事就是对这三个控件进行处理。

先声明标题栏的三个空间及相关参数,这些参数都是根据atts.xml中来设置的,因为我们在引用自定义控件的时候是从xml中引用的,属性的设置都在xml文件中,我们从xml文件中拿到属性的值后再对控件设置赋值。

    /**
     * 标题栏的三个控件
     */
    private Button leftBtn, rightBtn;
    private TextView title;
    /**
     * 左边按钮的属性
     */
    private int leftTextColor;
    private Drawable leftBackground;
    private String leftText;
    /**
     * 右边按钮的属性
     */
    private int rightTextColor;
    private Drawable rightBackground;
    private String rightText;
    /**
     * 中间TextView的属性
     */
    private int titleTextColor;
    private String titleText;
    private float titleTextSize;
    /**
     * 三个控件的布局参数
     */
    private LayoutParams leftParams, rightParams, titleParams;


下面是构造方法,构造方法传入两个参数,一个是上下文参数,另外一个是AttributeSet,AttributeSet是一个属性的集合,用它可以处理一组xml标签集合。使用ta.getXXX方法,我们可以先从xml文件获得属性的值,然后把这些值设置给控件。最后通过LayoutParams来设置控件的宽高,设置好宽高之后,调用addView方法,添加控件。

    public MyToolBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray ta = context.obtainStyledAttributes(attrs,
                R.styleable.ToolBar);
        leftTextColor = ta.getColor(R.styleable.ToolBar_leftTextColor, 0);
        leftBackground = ta.getDrawable(R.styleable.ToolBar_leftBackground);
        leftText = ta.getString(R.styleable.ToolBar_leftText);
        rightTextColor = ta.getColor(R.styleable.ToolBar_rightTextColor, 0);
        rightBackground = ta.getDrawable(R.styleable.ToolBar_rightBackground);
        rightText = ta.getString(R.styleable.ToolBar_rightText);
        titleText = ta.getString(R.styleable.ToolBar_title);
        titleTextColor = ta.getColor(R.styleable.ToolBar_titleTextColor, 0);
        titleTextSize = ta.getDimension(R.styleable.ToolBar_titleTextSize, 0);
        //对ta进行回收
        ta.recycle();
        leftBtn = new Button(context);
        rightBtn = new Button(context);
        title = new TextView(context);
        /**
         * 设置属性
         */
        leftBtn.setText(leftText);
        leftBtn.setTextColor(leftTextColor);
        leftBtn.setBackground(leftBackground);
        rightBtn.setText(rightText);
        rightBtn.setTextColor(rightTextColor);
        rightBtn.setBackground(rightBackground);
        title.setText(titleText);
        title.setTextColor(titleTextColor);
        title.setTextSize(titleTextSize);
        title.setGravity(Gravity.CENTER);
        //设置整体背景颜色
        setBackgroundColor(0x7CFC0055);
        leftParams = new LayoutParams(
                android.view.ViewGroup.LayoutParams.WRAP_CONTENT,
                android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
        leftParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, TRUE);
        //添加控件
        addView(leftBtn, leftParams);
        rightParams = new LayoutParams(
                android.view.ViewGroup.LayoutParams.WRAP_CONTENT,
                android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
        rightParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, TRUE);
        addView(rightBtn, rightParams);
        titleParams = new LayoutParams(
                android.view.ViewGroup.LayoutParams.WRAP_CONTENT,
                android.view.ViewGroup.LayoutParams.MATCH_PARENT);
        titleParams.addRule(RelativeLayout.CENTER_IN_PARENT, TRUE);
        addView(title, titleParams);
    }


第三步:引用我们定义的控件
自定义好控件之后,我们就可以使用自定义的控件了,在主布局的xml文件中引用我们自定义的控件。自定义控件的前三个属性都是以android:开头,这表示这些属性都是系统的,后面的属性以custombar开头,表示这些属性都是我们自定义的,为了能够使用自定义的custombar,我们需要在RelativeLayout中添加一句:

xmlns:custombar="http://schemas.android.com/apk/res/com.example.mytoolbar"

注意后面的com.example.mytoolbar是你应用的包名称。如果阁下使用的不是eclipse而是android studio,那么这一行不用这么麻烦,只需要写上:

xmlns:custombar="http://schemas.android.com/apk/res-auto"

我们自定义的属性就是我们在atts.xml中声明的要设置的属性。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custombar="http://schemas.android.com/apk/res/com.example.mytoolbar"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <com.example.mytoolbar.MyToolBar
        android:id="@+id/mytoolbar"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        custombar:leftBackground="@android:color/holo_blue_light"
        custombar:leftText="返回"
        custombar:leftTextColor="@android:color/black"
        custombar:rightBackground="@android:color/holo_blue_light"
        custombar:rightText="更多"
        custombar:rightTextColor="@android:color/black"
        custombar:title="标题栏"
        custombar:titleTextColor="@android:color/black"
        custombar:titleTextSize="18sp" >
    </com.example.mytoolbar.MyToolBar>
</RelativeLayout>


做完这些工作之后,运行你的项目,就能看到我们在文章开头给出的那个画面了。

第四步:为自定义控件添加事件

好像还少点什么,是的,我们的控件都还没有点击事件。要给事件设置点击事件,需要先在自定义控件中声明一个事件接口,并声明一个接口的实例:

private OnToolBarClickListener listener;
    public interface OnToolBarClickListener {
        /**
         * 左边按钮点击事件
         */
        public void leftClick();
        /**
         * 右边按钮点击事件
         */
        public void rightClick();
    }


然后暴露出来一个方法给其他类调用,这个方法的参数就是这个接口:

    public void setOnToolBarClickListener(OnToolBarClickListener listener) {
        this.listener = listener;
    }

最后在左右两个按钮的点击事件中调用接口中的方法即可,聪明的看官猜猜这是什么模式?

  

      leftBtn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                listener.leftClick();
            }
        });
        rightBtn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                listener.rightClick();
            }
        });


方法写好了,我们在MainActivity中调用看看:

public class MainActivity extends Activity {
    private MyToolBar toolBar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getActionBar().hide();
        this.toolBar = (MyToolBar) this.findViewById(R.id.mytoolbar);
        toolBar.setOnToolBarClickListener(new OnToolBarClickListener() {
            
            @Override
            public void rightClick() {
                Toast.makeText(MainActivity.this,"右边点击", Toast.LENGTH_LONG).show();
            }
            
            @Override
            public void leftClick() {
                Toast.makeText(MainActivity.this,"左边点击", Toast.LENGTH_LONG).show();
            }
        });
    }
}


Dashboard Android用户自定义UI设计模板


Dashboard,一种专门针对入口界面设计的应用程序,Dashboard (为仪表板之意)原来是苹果公司 Mac OS X v10.4 Tiger 作业系统中的应用程序,用作widget的小型应用程式之执行基础。

本文我们将简要介绍Android的用户自定义UI设计模板Dashboard,它借助清晰且尺寸巨大的图标来标示出主要功能及可选区域,用以为用户提供适用的最新信息。


Android用户自定义UI设计模板-Dashboard

我们回顾Goole I/O 2010年大会,其推介的Android用户界面设计模板(Android UI design patterns)可以提供相关功能以简化用户的操作界面。这体现的正是Dashboard的特色。


选项卡模式

问题

在移动类产品的实际使用中,借助清晰快速的导航来实现主要功能显得极为重要。它们应该便捷有效,帮助用户迅速实现某些基本的操作(例如在社交网站上发布动态,发送消息或是拍照等)。


解决方案

解决方案

应用程序的入口界面应当具备清爽的视觉体验及易于访问的特性(尤其是针对常用的应用程序)。

更多实例

facebook


miso


picplz


twitter

结论

◆简便迅捷地实现主要功能

◆清晰友好的入口界面

◆便于用户理解及掌握

◆不失时机地向用户展示品牌形象

◆所提供的选项应提示当前应用程序的基本信息或作用范围


我们知道做安卓app开发的朋友经常会用到一个抓包了,而我们要介绍的fidder是一个非常不错的工具了,下面一起来看Fiddler抓包记录的工具使用详解
做Android等应用开发离不了抓包工具,Fiddler 是一个相当不错的抓取http/https 的工具了

 

下载的话直接百度搜索Fiddler 下载即可:

 

在手机里的wifi里面设置代理ip和端口即可完成监听

 

安装完成注意设置:
findler4

 

我们一起来看一篇Android Studio Git第一次提交的例子吧,希望此例子能够对各位朋友带来有效的帮助哦。
终于决定开始用android studio 写程序了,遇到的第一件事就是如何向git提交代码。下面整理一下第一次提交的过程。

 

1.打开AS的配置面板,找到Git的选项

 

无标题

 

2.在右边的 Path to Git executable 找到Git的可执行程序,点击右边的Test按钮。出现下图说明成功了。

 

1

 

3.找到VCS菜单, 选择 Enable Version Control Integration,在下拉框中选择 Git , 点击 OK,Module 中的文件都变成了红色。

 

4.选择项目,右键-》git->add,然后再选择 Commit Directory..,如下图,Commit Message 这里是必填项。点击 Commit 按钮。然后选择Push…

 

10400400

 

5.第一次是需要先设置远程主机的, 将Git@OSC仓库的HTTPS连接拷贝到URL里面。

 

10400402

 

6.最后选择需要提交的项目,点击Push按钮即可
本文我们将介绍在Android开发很常见的tab滑动切换效果,本文讲了两例,一个是ViewPage+Fragment实现区域顶部tab滑动切换,还有一个是FragmentTabHost+Fragment实现底部tab切换,欢迎交流。

Android开发中ViewPage+Fragment实现区域顶部tab滑动切换


本教程我们将说说tab导航,导航分为一层和两层(底部区块+区域内头部导航),主要实现方案有RadioGroup+ViewPage+Fragment、Viewpager Indicator、ActionBar Tabs、FragmentTabHost+Fragment等,下面我们先采用RadioGroup+ViewPage+Fragment实现区域头部导航。

如图所示:



案例主要组件

1、先看一下MainActivity布局

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
      <HorizontalScrollView
        android:id="@+id/hvChannel"
         android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbars="none"
        >
        <RadioGroup
         android:id="@+id/rgChannel"
         android:layout_width="wrap_content"
        android:layout_height="wrap_content" android:orientation="horizontal">
            
        </RadioGroup> 
    </HorizontalScrollView>
      <android.support.v4.view.ViewPager
              android:id="@+id/vpNewsList"
               android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
          >
      </android.support.v4.view.ViewPager>
</LinearLayout>

       



2、MainActivity代码:

public class MainActivity extends FragmentActivity implements OnPageChangeListener{
    private ViewPager viewPager;
    private RadioGroup rgChannel=null;
    private HorizontalScrollView hvChannel;
    private PageFragmentAdapter adapter=null;
    private List<Fragment> fragmentList=new ArrayList<Fragment>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }
    private void initView(){
        rgChannel=(RadioGroup)super.findViewById(R.id.rgChannel);
        viewPager=(ViewPager)super.findViewById(R.id.vpNewsList);
        hvChannel=(HorizontalScrollView)super.findViewById(R.id.hvChannel);
        rgChannel.setOnCheckedChangeListener(
                new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup group, 
                    int checkedId) {
                viewPager.setCurrentItem(checkedId);        
            }
        });
        viewPager.setOnPageChangeListener(this);
        initTab();//动态产生RadioButton
        initViewPager();
        rgChannel.check(0);
    }
    private void initTab(){
        List<Channel> channelList=ChannelDb.getSelectedChannel();
        for(int i=0;i<channelList.size();i++){
            RadioButton rb=(RadioButton)LayoutInflater.from(this).
                    inflate(R.layout.tab_rb, null);
            rb.setId(i);
            rb.setText(channelList.get(i).getName());
            RadioGroup.LayoutParams params=new 
            RadioGroup.LayoutParams(RadioGroup.LayoutParams.WRAP_CONTENT,
                            RadioGroup.LayoutParams.WRAP_CONTENT);
            rgChannel.addView(rb,params);
        }
        
    }
    private void initViewPager(){
        List<Channel> channelList=ChannelDb.getSelectedChannel();
        for(int i=0;i<channelList.size();i++){
            NewsFragment frag=new NewsFragment();
            Bundle bundle=new Bundle();
            bundle.putString("weburl", channelList.get(i).getWeburl());
            bundle.putString("name", channelList.get(i).getName());
            frag.setArguments(bundle);     //向Fragment传入数据
            fragmentList.add(frag);
        }
        adapter=new PageFragmentAdapter(super.getSupportFragmentManager(),fragmentList);
        viewPager.setAdapter(adapter);
        //viewPager.setOffscreenPageLimit(0);
    }
    
    /**
     * 滑动ViewPager时调整ScroollView的位置以便显示按钮
     * @param idx
     */
    private void setTab(int idx){
        RadioButton rb=(RadioButton)rgChannel.getChildAt(idx);
        rb.setChecked(true);
        int left=rb.getLeft();
        int width=rb.getMeasuredWidth();
        DisplayMetrics metrics=new DisplayMetrics();
        super.getWindowManager().getDefaultDisplay().getMetrics(metrics);
        int screenWidth=metrics.widthPixels;
        int len=left+width/2-screenWidth/2;
        hvChannel.smoothScrollTo(len, 0);//滑动ScroollView
    }
    @Override
    public void onPageScrollStateChanged(int arg0) {
    
    }
    @Override
    public void onPageScrolled(int arg0, float arg1, int arg2) {
    }
    @Override
    public void onPageSelected(int position) {
        // TODO Auto-generated method stub
        setTab(position);
    }
}




其中initTab()方法实现向RadioGroup动态添加RadioButton

导航按钮数据来源于ChannelDb


    private static List<Channel>   selectedChannel=new ArrayList<Channel>();
    static{
        selectedChannel.add(new Channel("","头条",0,"",""));
        selectedChannel.add(new Channel("","娱乐",0,"",""));
        selectedChannel.add(new Channel("","体育",0,"",""));
        selectedChannel.add(new Channel("","财经",0,"",""));
        selectedChannel.add(new Channel("","热点",0,"",""));
        selectedChannel.add(new Channel("","科技",0,"",""));
        selectedChannel.add(new Channel("","图片",0,"",""));
        selectedChannel.add(new Channel("","汽车",0,"",""));
        selectedChannel.add(new Channel("","时尚",0,"",""));
    }
    public static  List<Channel> getSelectedChannel(){
         return selectedChannel;
    }



导航按钮外观:tab_rb.xml和tab_selector.xml背景选择器(实现选择后带红色下划线效果)

<?xml version="1.0" encoding="utf-8"?>
<RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="wrap_content"
                android:layout_height="30dp"
                android:text="今日"
                android:background="@drawable/tab_selector"
                android:paddingLeft="15dp"
                android:paddingRight="15dp"
                 android:paddingTop="10dp"
                android:paddingBottom="10dp"
                  android:button="@null"
                />
tab_selector.xml:
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
      <item android:state_checked="true" ><!-- 选中状态 -->
        <layer-list >
            <item >
                <shape android:shape="rectangle">
                    <stroke android:width="5dp"  android:color="#ff0000"/>    
                </shape>
            </item>
            <item  android:bottom="5dp" >
                <shape android:shape="rectangle" >
                        <solid android:color="#fff"/>
               </shape>
            </item>
        </layer-list> 
    </item>
    <item ><!-- 默认状态 -->
        <shape >
                <solid  android:color="#FAFAFA"/>
        </shape>
    </item>
</selector>




3、PageFragmentAdapter适配器

public class PageFragmentAdapter extends FragmentPagerAdapter{
    private List<Fragment> fragmentList;
    private FragmentManager fm;
    public PageFragmentAdapter(FragmentManager fm,List<Fragment> fragmentList){
        super(fm);
        this.fragmentList=fragmentList;
        this.fm=fm;
    }
    @Override
    public Fragment getItem(int idx) {
        return fragmentList.get(idx%fragmentList.size());
    }
    @Override
    public int getCount() {
        return fragmentList.size();
    }
    @Override  
    public int getItemPosition(Object object) {  
       return POSITION_NONE;  //没有找到child要求重新加载
    }  }


4、NewsFragment组件:

public class NewsFragment extends Fragment {
    private String weburl;
    private String channelName;
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
    }
    private View view;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if(view==null){//优化View减少View的创建次数    
            //该部分可通过xml文件设计Fragment界面,再通过LayoutInflater转换为View组件
            //这里通过代码为fragment添加一个TextView
            TextView tvTitle=new TextView(getActivity());
            tvTitle.setText(channelName);
            tvTitle.setTextSize(16);
            tvTitle.setGravity(Gravity.CENTER);
            tvTitle.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
            view=tvTitle;
        }
        ViewGroup parent=(ViewGroup)view.getParent();
        if(parent!=null){//如果View已经添加到容器中,要进行删除,负责会报错
            parent.removeView(view);
        }
        return view;
    }
    @Override
    public void setArguments(Bundle bundle) {//接收传入的数据
        weburl=bundle.getString("weburl");
        channelName=bundle.getString("name");    
    }
    
}


Android开发中FragmentTabHost+Fragment实现底部tab切换


上面我们使用RadioGroup+ViewPage+Fragmen实现了顶部滑动导航,接下来我们使用FragmentTabHost+Fragment实现底部tab切换,效果如图所示



案例主要组件


1、MainActivity布局

  把整个Activity分成两部TabHost和TabContent,TabHost包含各个tab,tab之间切换将在TabContent所关联的FrameLayout区域中显示各自板块的内容

<LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >
    <FrameLayout  android:id="@+id/contentLayout"
         android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"> 
    </FrameLayout>
     <android.support.v4.app.FragmentTabHost
         android:id="@android:id/tabhost"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:background="#F6F6F6"
         >
         <FrameLayout android:id="@android:id/tabcontent"
             android:layout_height="0dp" android:layout_width="0dp"
             />
     </android.support.v4.app.FragmentTabHost>
</LinearLayout>




2、MainActivity代码

public class MainActivity extends FragmentActivity
 implements OnTabChangeListener{
    private FragmentTabHost tabHost;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tabHost=(FragmentTabHost)super.findViewById(android.R.id.tabhost);
        tabHost.setup(this,super.getSupportFragmentManager()
                ,R.id.contentLayout);
        tabHost.getTabWidget().setDividerDrawable(null);
        tabHost.setOnTabChangedListener(this);
        initTab();
    }
    private void initTab(){
        String tabs[]=TabDb.getTabsTxt();
        for(int i=0;i<tabs.length;i++){
            TabSpec tabSpec=tabHost.newTabSpec(tabs[i]).setIndicator(getTabView(i));
            tabHost.addTab(tabSpec,TabDb.getFragments()[i],null);
            tabHost.setTag(i);
        }
    }
    private View getTabView(int idx){
        View view=LayoutInflater.from(this).inflate(R.layout.footer_tabs,null);
        ((TextView)view.findViewById(R.id.tvTab)).setText(TabDb.getTabsTxt()[idx]);
        if(idx==0){
            ((TextView)view.findViewById(R.id.tvTab)).setTextColor(Color.RED);
    ((ImageView)view.findViewById(R.id.ivImg)).setImageResource(TabDb.getTabsImgLight()[idx]);
        }else{
            ((ImageView)view.findViewById(R.id.ivImg)).setImageResource(TabDb.getTabsImg()[idx]);
        }
        return view;
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
    @Override
    public void onTabChanged(String tabId) {
        // TODO Auto-generated method stub
        updateTab();
    }
    private void updateTab(){
        TabWidget tabw=tabHost.getTabWidget();
        for(int i=0;i<tabw.getChildCount();i++){
            View view=tabw.getChildAt(i);
            ImageView iv=(ImageView)view.findViewById(R.id.ivImg);
            if(i==tabHost.getCurrentTab()){
                ((TextView)view.findViewById(R.id.tvTab)).setTextColor(Color.RED);
                iv.setImageResource(TabDb.getTabsImgLight()[i]);
            }else{        ((TextView)view.findViewById(R.id.tvTab)).setTextColor(getResources().getColor(R.color.foot_txt_gray));
                iv.setImageResource(TabDb.getTabsImg()[i]);
            }
            
        }
    }
}




3、TabDb组件

 提供界面设计所需的tab文本、tab图片和Fragment类型数据

public class TabDb {
    public static String[] getTabsTxt(){
        String[] tabs={"新闻","阅读","试听","发现"," 我"};
        return tabs;
    }
    public static int[] getTabsImg(){
        int[] ids={R.drawable.foot_news_normal,R.drawable.foot_read_normal,R.drawable.foot_vdio_normal,R.drawable.foot_fond_normal,R.drawable.foot_out_normal};
        return ids;
    }
    public static int[] getTabsImgLight(){
        int[] ids={R.drawable.foot_news_light,R.drawable.foot_read_light,R.drawable.foot_vdio_light,R.drawable.foot_found_light,R.drawable.foot_out_light};
        return ids;
    }
    public static Class[] getFragments(){
        Class[] clz={NewsFragment.class,ReadFragment.class,VideoFragment.class,FoundFragment.class,OwnerFragment.class};
        return clz;
    }
}




4、每个tab各自对应的Fragment组件

  共5个Fragment为NewsFragment、ReadFragment、FoundFragment、OwnerFragment、VideoFragment,根据不同板块各自设计界面,这里重点是如何实现底部tab切换,简单布局一下即可,以NewsFragment为例代码如下:

public class NewsFragment extends Fragment {
    @Override
    public void onAttach(Activity activity) {
        // TODO Auto-generated method stub
        super.onAttach(activity);
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        TextView tvTitle=new TextView(super.getActivity());
        tvTitle.setText("新闻");
        tvTitle.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
        tvTitle.setGravity(Gravity.CENTER);
        tvTitle.setTextSize(30);
        return tvTitle;
    }
    @Override
    public void setArguments(Bundle args) {
        // TODO Auto-generated method stub
        super.setArguments(args);
    }
}




5、tab布局样式(footer_tabs.xml)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" 
    android:gravity="center"
    android:padding="5dp"
    android:background="#F6F6F6"
    >
    <ImageView
        android:id="@+id/ivImg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
       />
    <TextView
        android:id="@+id/tvTab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/ivImg"
          android:textColor="#AEAEAE"
        android:text="新闻" android:layout_marginTop="2dp"/>


标签:[!--infotagslink--]

您可能感兴趣的文章: