首页 > 代码库 > Android UI设计框架[1]: ViewPager+Fragment实现底部图标文字的导航栏(IconTabPageIndicator)

Android UI设计框架[1]: ViewPager+Fragment实现底部图标文字的导航栏(IconTabPageIndicator)

版权声明:

本文参考“Android开发技巧——实现底部图标文字的导航栏”一文,地址为:http://blog.csdn.net/maosidiaoxian/article/details/38864679

 

基础知识:

1) Fragment是在Android 3.0(API 11)版本引入的,如果使用的是3.0之前的系统,需要先导入android-support-v4的jar包才能使用Fragment功能。

 

实现思路:

1) 先定义两个接口:

IconPagerAdapter

public interface IconPagerAdapter {    int getIconResId(int index);    int getCount();}

PageIndicator

import android.support.v4.view.ViewPager; public interface PageIndicator extends ViewPager.OnPageChangeListener {    void setViewPager(ViewPager view);    void setViewPager(ViewPager view, int initialPosition);    void setCurrentItem(int item);    void setOnPageChangeListener(ViewPager.OnPageChangeListener listener);    void notifyDataSetChanged();}

2) 新建一个类IconTabPageIndicator,继承LinearLayout并实现PageIndicator接口:

import android.content.Context;import android.support.v4.view.PagerAdapter;import android.support.v4.view.ViewPager;import android.util.AttributeSet;import android.view.View;import android.view.ViewGroup;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.TextView;import com.localbuyapp.R;import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;/** * User: Geek_Soledad(msdx.android@qq.com) * Date: 2014-08-27 * Time: 09:20 * FIXME */public class IconTabPageIndicator extends LinearLayout implements PageIndicator {    /**     * Title text used when no title is provided by the adapter.     */    private static final CharSequence EMPTY_TITLE = "";    /**     * Interface for a callback when the selected tab has been reselected.     */    public interface OnTabReselectedListener {        /**         * Callback when the selected tab has been reselected.         *         * @param position Position of the current center item.         */        void onTabReselected(int position);    }    private Runnable mTabSelector;    private final View.OnClickListener mTabClickListener = new View.OnClickListener() {        public void onClick(View view) {            TabView tabView = (TabView) view;            final int oldSelected = mViewPager.getCurrentItem();            final int newSelected = tabView.getIndex();            mViewPager.setCurrentItem(newSelected);            if (oldSelected == newSelected && mTabReselectedListener != null) {                mTabReselectedListener.onTabReselected(newSelected);            }        }    };    private final LinearLayout mTabLayout;    private ViewPager mViewPager;    private ViewPager.OnPageChangeListener mListener;    private int mSelectedTabIndex;    private OnTabReselectedListener mTabReselectedListener;    private int mTabWidth;    public IconTabPageIndicator(Context context) {        this(context, null);    }    public IconTabPageIndicator(Context context, AttributeSet attrs) {        super(context, attrs);        setHorizontalScrollBarEnabled(false);        mTabLayout = new LinearLayout(context, null, R.attr.tabPageIndicator);        addView(mTabLayout, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));    }    public void setOnTabReselectedListener(OnTabReselectedListener listener) {        mTabReselectedListener = listener;    }    @Override    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        final int widthMode = View.MeasureSpec.getMode(widthMeasureSpec);        final boolean lockedExpanded = widthMode == View.MeasureSpec.EXACTLY;        final int childCount = mTabLayout.getChildCount();        if (childCount > 1 && (widthMode == MeasureSpec.EXACTLY || widthMode == MeasureSpec.AT_MOST)) {            mTabWidth = MeasureSpec.getSize(widthMeasureSpec) / childCount;        } else {            mTabWidth = -1;        }        final int oldWidth = getMeasuredWidth();        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        final int newWidth = getMeasuredWidth();        if (lockedExpanded && oldWidth != newWidth) {            // Recenter the tab display if we‘re at a new (scrollable) size.            setCurrentItem(mSelectedTabIndex);        }    }    private void animateToTab(final int position) {        final View tabView = mTabLayout.getChildAt(position);        if (mTabSelector != null) {            removeCallbacks(mTabSelector);        }        mTabSelector = new Runnable() {            public void run() {                final int scrollPos = tabView.getLeft() - (getWidth() - tabView.getWidth()) / 2;                mTabSelector = null;            }        };        post(mTabSelector);    }    @Override    public void onAttachedToWindow() {        super.onAttachedToWindow();        if (mTabSelector != null) {            // Re-post the selector we saved            post(mTabSelector);        }    }    @Override    public void onDetachedFromWindow() {        super.onDetachedFromWindow();        if (mTabSelector != null) {            removeCallbacks(mTabSelector);        }    }    private void addTab(int index, CharSequence text, int iconResId) {        final TabView tabView = new TabView(getContext());        tabView.mIndex = index;        tabView.setOnClickListener(mTabClickListener);        tabView.setText(text);        if (iconResId > 0) {            tabView.setIcon(iconResId);        }        mTabLayout.addView(tabView, new LinearLayout.LayoutParams(0, MATCH_PARENT, 1));    }    @Override    public void onPageScrollStateChanged(int arg0) {        if (mListener != null) {            mListener.onPageScrollStateChanged(arg0);        }    }    @Override    public void onPageScrolled(int arg0, float arg1, int arg2) {        if (mListener != null) {            mListener.onPageScrolled(arg0, arg1, arg2);        }    }    @Override    public void onPageSelected(int arg0) {        setCurrentItem(arg0);        if (mListener != null) {            mListener.onPageSelected(arg0);        }    }    @Override    public void setViewPager(ViewPager view) {        if (mViewPager == view) {            return;        }        if (mViewPager != null) {            mViewPager.setOnPageChangeListener(null);        }        final PagerAdapter adapter = view.getAdapter();        if (adapter == null) {            throw new IllegalStateException("ViewPager does not have adapter instance.");        }        mViewPager = view;        view.setOnPageChangeListener(this);        notifyDataSetChanged();    }    public void notifyDataSetChanged() {        mTabLayout.removeAllViews();        PagerAdapter adapter = mViewPager.getAdapter();        IconPagerAdapter iconAdapter = null;        if (adapter instanceof IconPagerAdapter) {            iconAdapter = (IconPagerAdapter) adapter;        }        final int count = adapter.getCount();        for (int i = 0; i < count; i++) {            CharSequence title = adapter.getPageTitle(i);            if (title == null) {                title = EMPTY_TITLE;            }            int iconResId = 0;            if (iconAdapter != null) {                iconResId = iconAdapter.getIconResId(i);            }            addTab(i, title, iconResId);        }        if (mSelectedTabIndex > count) {            mSelectedTabIndex = count - 1;        }        setCurrentItem(mSelectedTabIndex);        requestLayout();    }    @Override    public void setViewPager(ViewPager view, int initialPosition) {        setViewPager(view);        setCurrentItem(initialPosition);    }    @Override    public void setCurrentItem(int item) {        if (mViewPager == null) {            throw new IllegalStateException("ViewPager has not been bound.");        }        mSelectedTabIndex = item;        mViewPager.setCurrentItem(item);        final int tabCount = mTabLayout.getChildCount();        for (int i = 0; i < tabCount; i++) {            final View child = mTabLayout.getChildAt(i);            final boolean isSelected = (i == item);            child.setSelected(isSelected);            if (isSelected) {                animateToTab(item);            }        }    }        /**     * For fragment slide     */    @Override    public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {        mListener = listener;    }    private class TabView extends LinearLayout {        private int mIndex;        private ImageView mImageView;        private TextView mTextView;        public TabView(Context context) {            super(context, null, R.attr.tabView);            View view = View.inflate(context, R.layout.tab_view, null);            mImageView = (ImageView) view.findViewById(R.id.tab_image);            mTextView = (TextView) view.findViewById(R.id.tab_text);//            this.addView(view);            this.addView(view, MATCH_PARENT, MATCH_PARENT);        }        @Override        public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {            super.onMeasure(widthMeasureSpec, heightMeasureSpec);            // Re-measure if we went beyond our maximum size.            if (mTabWidth > 0) {                super.onMeasure(MeasureSpec.makeMeasureSpec(mTabWidth, MeasureSpec.EXACTLY),                        heightMeasureSpec);            }        }        public void setText(CharSequence text) {            mTextView.setText(text);        }        public void setIcon(int resId) {            if (resId > 0) {                mImageView.setImageResource(resId);            }        }        public int getIndex() {            return mIndex;        }    }}

这里内部类TabView直接使用布局文件来实现(tab_view.xml代码这里未贴出)。

3) 在Activity中使用IconTabPageIndicator(直接包含在Activity的布局文件中):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:tools="http://schemas.android.com/tools"      android:layout_width="match_parent"      android:layout_height="match_parent"      tools:context=".MyActivity">        <xxx.IconTabPageIndicator          android:id="@+id/indicator"          android:layout_alignParentBottom="true"          android:layout_width="match_parent"          android:layout_height="wrap_content"/>      <android.support.v4.view.ViewPager          android:layout_above="@id/indicator"          android:id="@+id/view_pager"          android:layout_width="match_parent"          android:layout_height="match_parent"/>  </RelativeLayout>
import android.app.ActionBar;import android.content.Intent;import android.os.Bundle;import android.support.v4.app.Fragment;import android.support.v4.app.FragmentActivity;import android.support.v4.app.FragmentManager;import android.support.v4.app.FragmentPagerAdapter;import android.support.v4.view.ViewPager;import android.view.Menu;import android.view.MenuInflater;import android.view.MenuItem;import android.view.ViewConfiguration;import android.widget.SearchView;import android.widget.SearchView.OnQueryTextListener;import android.widget.ShareActionProvider;import android.widget.Toast;import com.xxx.R;import com.viewpagerindicator.IconPagerAdapter;import com.viewpagerindicator.IconTabPageIndicator;import java.lang.reflect.Field;import java.util.ArrayList;import java.util.List;public class MainActivity extends FragmentActivity{    // Debugging    private static final String TAG = "MainActivity";    private static final boolean D = true;        // Member fields    private ViewPager mViewPager;    private IconTabPageIndicator mIndicator;    private FragmentPagerAdapter mAdapter;      private List<BaseFragment> mFragments = new ArrayList<BaseFragment>();         @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);                // 隐藏ActionBar        ActionBar actionBar = getActionBar();          actionBar.hide();                // 控件初始化        initViews();    }    private void initViews() {        // 实例化ViewPager        mViewPager = (ViewPager) findViewById(R.id.view_pager);                // 实例化TabPageIndicator        mIndicator = (IconTabPageIndicator) findViewById(R.id.indicator);                // 初始化Fragments        mFragments = initFragments();                // 实例化FragmentPageAdapter        mAdapter = new FragmentAdapter(mFragments, getSupportFragmentManager());                // ViewPager的adapter,使得fragments与ViewPager关联         mViewPager.setAdapter(mAdapter);                 // 设置ViewPager与TabPageIndicator关联        mIndicator.setViewPager(mViewPager);    }        private List<BaseFragment> initFragments() {        List<BaseFragment> fragments = new ArrayList<BaseFragment>();                // 添加Fragments到存放Fragment的List        IndexFragment indexFragment = new IndexFragment();        indexFragment.setTitle("首页");        indexFragment.setIconId(R.drawable.tab_user_selector);        fragments.add(indexFragment);        NearbyFragment nearbyFragment = new NearbyFragment();        nearbyFragment.setTitle("附近");        nearbyFragment.setIconId(R.drawable.tab_record_selector);        fragments.add(nearbyFragment);        MyinfoFragment myFragment = new MyinfoFragment();        myFragment.setTitle("我的");        myFragment.setIconId(R.drawable.tab_user_selector);        fragments.add(myFragment);                return fragments;    }        class FragmentAdapter extends FragmentPagerAdapter implements IconPagerAdapter {            private List<BaseFragment> mFragments;        public FragmentAdapter(List<BaseFragment> fragments, FragmentManager fm) {            super(fm);            mFragments = fragments;        }        @Override        public Fragment getItem(int i) {            return mFragments.get(i);        }        @Override        public int getIconResId(int index) {            return mFragments.get(index).getIconId();        }        @Override        public int getCount() {            return mFragments.size();        }        @Override        public CharSequence getPageTitle(int position) {            return mFragments.get(position).getTitle();        }    }}

4) 可以看到MainActivity中,与ViewPager关联的Fragment List不是Fragment类型的,而是BaseFragment(继承自Fragment),是因为

BaseFragment需要多加两个属性title和iconId,title对应TabView的文字,iconId对应TabView的图片索引:

import com.xxx.R;import android.os.Bundle;import android.support.annotation.Nullable;import android.support.v4.app.Fragment;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;/** * User: Geek_Soledad(msdx.android@qq.com) * Date: 2014-08-27 * Time: 09:01 * FIXME */public class BaseFragment extends Fragment {    private String title;    private int iconId;    public String getTitle() {        return title;    }    public void setTitle(String title) {        this.title = title;    }    public int getIconId() {        return iconId;    }    public void setIconId(int iconId) {        this.iconId = iconId;    }    @Override    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {        View view = inflater.inflate(R.layout.fragment, null, false);        TextView textView = (TextView) view.findViewById(R.id.text);        textView.setText(getTitle());        return view;    }}

5) 再定义每个ViewPager对应的Fragment(继承自BaseFragment),如:

import android.content.Intent;import android.os.Bundle;import android.support.annotation.Nullable;import android.support.v4.app.Fragment;import android.view.LayoutInflater;import android.view.View;import android.view.View.OnClickListener;import android.view.ViewGroup;import android.widget.Button;import android.widget.TextView;import android.widget.Toast;/** * User: Jay(jayhust@gmail.com) * Date: 2015-01-29 * Time: 11:40 * Notes: Extentable fragments: Fragment/DialogFragment/ListFragment/PreferenceFragment * FIXME */public class IndexFragment extends BaseFragment {    // Member field    private Button btn_index_test;        @Override    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {        View view = inflater.inflate(R.layout.fragment_index, null, false);         return view;    }        @Override      public void onActivityCreated(Bundle savedInstanceState) {          super.onActivityCreated(savedInstanceState);          Button btn_index_test = (Button) getActivity().findViewById(R.id.btn_index_test);          btn_index_test.setOnClickListener(new OnClickListener() {              @Override              public void onClick(View v) {                  TextView textView = (TextView) getActivity().findViewById(R.id.text_index_hint);                  Toast.makeText(getActivity(), textView.getText(), Toast.LENGTH_LONG).show();              }          });      } }

其对应的布局文件fragment_index.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:gravity="center_horizontal"    android:background="#eee"    tools:context=".MainActivity">         <TextView        android:id="@+id/text_index_hint"        android:textAppearance="@android:style/TextAppearance.Large"        android:text="Index Fragment"        android:layout_width="wrap_content"        android:layout_height="wrap_content"/>        <Button         android:id="@+id/btn_index_test"        android:layout_below="@id/text_index_hint"        android:layout_alignRight="@id/text_index_hint"        android:paddingTop="10dp"        android:text="index test"        android:layout_width="wrap_content"        android:layout_height="wrap_content"/>    </RelativeLayout>

 

Android UI设计框架[1]: ViewPager+Fragment实现底部图标文字的导航栏(IconTabPageIndicator)