首先作为一名菜鸟,尤其是记忆不好菜鸟,主动手写笔记记忆一些东西还是很有必要的,至少对于我而言。

言归正传,首先当大家看到这个需求,会想到布局中的选项卡控件,TabHost与TabWidget,其中这两个的区别,我的理解就是TabHost是装有选项卡+选项卡内容(FrameLayout)的容器,而TabWidget则就是底部或者顶部的那四个按钮。

再说布局中的注意事项的时候首先我们先看下布局,我这里只列出常用的这个方法

注意事项: 如上图,我已经用红线标注出来(网上有很多的总结,这里我自己再总结下,便于以后自己查看),首先

1、注意控件的顺序(FrameLayout与TabWidget顺序可变)。

2、FrameLayout、TabWidget这2个布局控件的id是系统定义好的,不能变,如图红框里的。其中TabHost控件id可使用系统定义好的,也可以自己定义。

3、在使用LinearLayout包裹FrameLayout与TabWidget时,若想实现四个Tab位于底部(默认是顶部),那么必须在FrameLayout中添加属性android:layout_weight="1"。若使用RelativeLayout包裹,则需要在TabWidget控件中添加属性android:layout_alignParentBottom="true"。其他的情况也没试过,这两种就是这样子,要问为什么这么做,大家可以试一下,实践证明就是这样子☺。

这些是布局中的一些问题,大家若是还有补充的或者发现我哪里有错误,欢迎大家补充并指出来,本菜鸟有错必改(*^__^*) 嘻嘻。

在实际开发中,我们会发现切换tab时会出现fagment重建,为了避免这种情况,这里给出一种方法,也是我们项目中用到:重写了控件TabHost

public class TabFragmentHost extends TabHost implements
		TabHost.OnTabChangeListener {
	private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
	private FrameLayout mRealTabContent;
	private Context mContext;
	private FragmentManager mFragmentManager;
	private int mContainerId;
	private OnTabChangeListener mOnTabChangeListener;
	private TabInfo mLastTab;
	private boolean mAttached;

	static final class TabInfo {
		private final String tag;
		private final Class<?> clss;
		private final Bundle args;
		private Fragment fragment;

		TabInfo(String _tag, Class<?> _class, Bundle _args) {
			tag = _tag;
			clss = _class;
			args = _args;
		}
	}

	static class DummyTabFactory implements TabContentFactory {
		private final Context mContext;

		public DummyTabFactory(Context context) {
			mContext = context;
		}

		@Override
		public View createTabContent(String tag) {
			View v = new View(mContext);
			v.setMinimumWidth(0);
			v.setMinimumHeight(0);
			return v;
		}
	}

	static class SavedState extends BaseSavedState {
		String curTab;

		SavedState(Parcelable superState) {
			super(superState);
		}

		private SavedState(Parcel in) {
			super(in);
			curTab = in.readString();
		}

		@Override
		public void writeToParcel(Parcel out, int flags) {
			super.writeToParcel(out, flags);
			out.writeString(curTab);
		}

		@Override
		public String toString() {
			return "FragmentTabHost.SavedState{"
					+ Integer.toHexString(System.identityHashCode(this))
					+ " curTab=" + curTab + "}";
		}

		public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
			public SavedState createFromParcel(Parcel in) {
				return new SavedState(in);
			}

			public SavedState[] newArray(int size) {
				return new SavedState[size];
			}
		};
	}

	public TabFragmentHost(Context context) {
		// Note that we call through to the version that takes an AttributeSet,
		// because the simple Context construct can result in a broken object!
		super(context, null);
		initFragmentTabHost(context, null);
	}

	public TabFragmentHost(Context context, AttributeSet attrs) {
		super(context, attrs);
		initFragmentTabHost(context, attrs);
	}

	private void initFragmentTabHost(Context context, AttributeSet attrs) {
		TypedArray a = context.obtainStyledAttributes(attrs,
				new int[] { android.R.attr.inflatedId }, 0, 0);
		mContainerId = a.getResourceId(0, 0);
		a.recycle();

		super.setOnTabChangedListener(this);
	}

	private void ensureHierarchy(Context context) {
		// If owner hasn't made its own view hierarchy, then as a convenience
		// we will construct a standard one here.
		if (findViewById(android.R.id.tabs) == null) {
			LinearLayout ll = new LinearLayout(context);
			ll.setOrientation(LinearLayout.VERTICAL);
			addView(ll, new LayoutParams(
					ViewGroup.LayoutParams.MATCH_PARENT,
					ViewGroup.LayoutParams.MATCH_PARENT));

			TabWidget tw = new TabWidget(context);
			tw.setId(android.R.id.tabs);
			tw.setOrientation(TabWidget.HORIZONTAL);
			ll.addView(tw, new LinearLayout.LayoutParams(
					ViewGroup.LayoutParams.MATCH_PARENT,
					ViewGroup.LayoutParams.WRAP_CONTENT, 0));

			FrameLayout fl = new FrameLayout(context);
			fl.setId(android.R.id.tabcontent);
			ll.addView(fl, new LinearLayout.LayoutParams(0, 0, 0));

			mRealTabContent = fl = new FrameLayout(context);
			mRealTabContent.setId(mContainerId);
			ll.addView(fl, new LinearLayout.LayoutParams(
					LinearLayout.LayoutParams.MATCH_PARENT, 0, 1));
		}
	}

	/**
	 * @deprecated Don't call the original TabHost setup, you must instead call
	 *             {@link #setup(Context, FragmentManager)} or
	 *             {@link #setup(Context, FragmentManager, int)}.
	 */
	@Override
	@Deprecated
	public void setup() {
		throw new IllegalStateException(
				"Must call setup() that takes a Context and FragmentManager");
	}

	public void setup(Context context, FragmentManager manager) {
		ensureHierarchy(context); // Ensure views required by super.setup()
		super.setup();
		mContext = context;
		mFragmentManager = manager;
		ensureContent();
	}

	public void setup(Context context, FragmentManager manager, int containerId) {
		ensureHierarchy(context); // Ensure views required by super.setup()
		super.setup();
		mContext = context;
		mFragmentManager = manager;
		mContainerId = containerId;
		ensureContent();
		mRealTabContent.setId(containerId);

		// We must have an ID to be able to save/restore our state. If
		// the owner hasn't set one at this point, we will set it ourself.
		if (getId() == View.NO_ID) {
			setId(android.R.id.tabhost);
		}
	}

	private void ensureContent() {
		if (mRealTabContent == null) {
			mRealTabContent = (FrameLayout) findViewById(mContainerId);
			if (mRealTabContent == null) {
				throw new IllegalStateException(
						"No tab content FrameLayout found for id "
								+ mContainerId);
			}
		}
	}

	@Override
	public void setOnTabChangedListener(OnTabChangeListener l) {
		mOnTabChangeListener = l;
	}

	public void addTab(TabSpec tabSpec, Class<?> clss, Bundle args) {
		tabSpec.setContent(new DummyTabFactory(mContext));
		String tag = tabSpec.getTag();

		TabInfo info = new TabInfo(tag, clss, args);

		if (mAttached) {
			// If we are already attached to the window, then check to make
			// sure this tab's fragment is inactive if it exists. This shouldn't
			// normally happen.
			info.fragment = mFragmentManager.findFragmentByTag(tag);
			if (info.fragment != null && !info.fragment.isDetached()) {
				FragmentTransaction ft = mFragmentManager.beginTransaction();
				// ft.detach(info.fragment);
				ft.hide(info.fragment);
				ft.commit();
			}
		}

		mTabs.add(info);
		addTab(tabSpec);
	}

	@Override
	protected void onAttachedToWindow() {
		super.onAttachedToWindow();

		String currentTab = getCurrentTabTag();

		// Go through all tabs and make sure their fragments match
		// the correct state.
		FragmentTransaction ft = null;
		for (int i = 0; i < mTabs.size(); i++) {
			TabInfo tab = mTabs.get(i);
			tab.fragment = mFragmentManager.findFragmentByTag(tab.tag);
			// if (tab.fragment != null && !tab.fragment.isDetached()) {
			if (tab.fragment != null) {
				if (tab.tag.equals(currentTab)) {
					// The fragment for this tab is already there and
					// active, and it is what we really want to have
					// as the current tab. Nothing to do.
					mLastTab = tab;
				} else {
					// This fragment was restored in the active state,
					// but is not the current tab. Deactivate it.
					if (ft == null) {
						ft = mFragmentManager.beginTransaction();
					}
					// ft.detach(tab.fragment);
					ft.hide(tab.fragment);
				}
			}
		}

		// We are now ready to go. Make sure we are switched to the
		// correct tab.
		mAttached = true;
		ft = doTabChanged(currentTab, ft);
		if (ft != null) {
			ft.commit();
			mFragmentManager.executePendingTransactions();
		}
	}

	@Override
	protected void onDetachedFromWindow() {
		super.onDetachedFromWindow();
		mAttached = false;
	}

	@Override
	protected Parcelable onSaveInstanceState() {
		Parcelable superState = super.onSaveInstanceState();
		SavedState ss = new SavedState(superState);
		ss.curTab = getCurrentTabTag();
		return ss;
	}

	@Override
	protected void onRestoreInstanceState(Parcelable state) {
		SavedState ss = (SavedState) state;
		super.onRestoreInstanceState(ss.getSuperState());
		setCurrentTabByTag(ss.curTab);
	}

	@Override
	public void onTabChanged(String tabId) {
		if (mAttached) {
			FragmentTransaction ft = doTabChanged(tabId, null);
			if (ft != null) {
				ft.commit();
			}
		}
		if (mOnTabChangeListener != null) {
			mOnTabChangeListener.onTabChanged(tabId);
		}
	}

	private FragmentTransaction doTabChanged(String tabId,
											 FragmentTransaction ft) {
		TabInfo newTab = null;
		for (int i = 0; i < mTabs.size(); i++) {
			TabInfo tab = mTabs.get(i);
			if (tab.tag.equals(tabId)) {
				newTab = tab;
			}
		}
		if (newTab == null) {
			throw new IllegalStateException("No tab known for tag " + tabId);
		}
		if (mLastTab != newTab) {
			if (ft == null) {
				ft = mFragmentManager.beginTransaction();
			}
			if (mLastTab != null) {
				if (mLastTab.fragment != null) {
					// ft.detach(mLastTab.fragment);
					ft.hide(mLastTab.fragment);
				}
			}
			if (newTab != null) {
				if (newTab.fragment == null) {
					newTab.fragment = Fragment.instantiate(mContext,
							newTab.clss.getName(), newTab.args);
					ft.add(mContainerId, newTab.fragment, newTab.tag);
				} else {
					// ft.attach(newTab.fragment);
					ft.show(newTab.fragment);
				}
			}

			mLastTab = newTab;
		}
		return ft;
	}
}
代码有点多,其实与原类差不多,只是将attach与dettach方法改为show和hide,防止切换tab导致fragment重建。

在实际开发中(本例子在Activity中所要注意的)

private int[] tabImgRes;
private Class[] fragments;
private String[] tabTags;


1、若是不继承TabActivity,则不要忘记在Activity首先要调用mFragmentTabHost.setup()方法,我们上面的代码是重写了setup方法。

2、mFragmentTabHost.addTab(spec)将每个tab添加到TabHost中(实际开发中,一个for循环即可),我们上面的代码是重写了addTab方法(

for (int i = 0; i < fragments.length; i++) {
    tabFragmentHost.addTab(tabFragmentHost.newTabSpec(tabTags[i]).setIndicator(getTab(i)), fragments[i], bundle);
}

)。

3、若是处理点击tab事件,直接调用mFragmentTabHost.setOnTabChangedListener即可。

4、获取当前tab

public int getCurrentTabIndex() {
        return tabFragmentHost.getCurrentTab();
    }
5、切换相应的fragment

public void switchToIndex(int index) {
        tabFragmentHost.setCurrentTab(index - 1);
    }
6、getTab(int i)方法返回一个view作为setIndicator中的参数

private View getTab(int i) {
        View view = getLayoutInflater().inflate(R.layout.item_main_tab, null);
        TextView mainTextView = (TextView) view.findViewById(R.id.mainTextView);
        mainTextView.setText(tabTags[i]);
        ImageView img = (ImageView) view.findViewById(R.id.img);
        img.setImageResource(tabImgRes[i]);
  
        return view;
    }
最后附上关于TabWidget android中文API来自 点击打开链接
以上就是此次的笔记,同样希望能帮助到其他人,文中有错的或者需要补充的,请多多指出。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐