FragmentTabHostUnderLineDemo【FragmentTabHost带下划线】
版权声明:本文为HaiyuKing原创文章,转载请注明出处!
前言
使用FragmentTabHost实现顶部选项卡(带下划线效果)展现。
效果图
代码分析
1、该Demo中采用的是FragmentTabHost的布局方案之一【命名为常规布局写法】;
2、使用自定义的FragmentTabHost;
3、切换回来后,可以保持打开的网页,而不是显示首页。【因为切换时执行的是show/hide,而不是attach/detach】
使用步骤
一、项目组织结构图
注意事项:
1、 导入类文件后需要change包名以及重新import R文件路径
2、 Values目录下的文件(strings.xml、dimens.xml、colors.xml等),如果项目中存在,则复制里面的内容,不要整个覆盖
二、导入步骤
将自定义的MyFragmentTabHost复制到项目中
- package com.why.project.fragmenttabhostunderlinedemo.views.tab;
- import android.content.Context;
- import android.content.res.TypedArray;
- import android.os.Bundle;
- import android.os.Parcel;
- import android.os.Parcelable;
- import android.support.annotation.NonNull;
- import android.support.annotation.Nullable;
- import android.support.v4.app.Fragment;
- import android.support.v4.app.FragmentManager;
- import android.support.v4.app.FragmentTransaction;
- import android.util.AttributeSet;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.FrameLayout;
- import android.widget.LinearLayout;
- import android.widget.TabHost;
- import android.widget.TabWidget;
- import java.util.ArrayList;
- /**
- * Created by HaiyuKing
- * Used 仿照FragmentTabHost并更改doTabChanged方法实现切换Fragment的时候不刷新fragment
- */
- public class MyFragmentTabHost extends TabHost
- implements TabHost.OnTabChangeListener {
- private final ArrayList<MyFragmentTabHost.TabInfo> mTabs = new ArrayList<>();
- private FrameLayout mRealTabContent;
- private Context mContext;
- private FragmentManager mFragmentManager;
- private int mContainerId;
- private TabHost.OnTabChangeListener mOnTabChangeListener;
- private MyFragmentTabHost.TabInfo mLastTab;
- private boolean mAttached;
- static final class TabInfo {
- final
- @NonNull
- String tag;
- final
- @NonNull
- Class<?> clss;
- final
- @Nullable
- Bundle args;
- Fragment fragment;
- TabInfo(@NonNull String _tag, @NonNull Class<?> _class, @Nullable Bundle _args) {
- tag = _tag;
- clss = _class;
- args = _args;
- }
- }
- static class DummyTabFactory implements TabHost.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);
- }
- 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 "MyFragmentTabHost.SavedState{"
- + Integer.toHexString(System.identityHashCode(this))
- + " curTab=" + curTab + "}";
- }
- public static final Parcelable.Creator<MyFragmentTabHost.SavedState> CREATOR
- = new Parcelable.Creator<MyFragmentTabHost.SavedState>() {
- @Override
- public MyFragmentTabHost.SavedState createFromParcel(Parcel in) {
- return new MyFragmentTabHost.SavedState(in);
- }
- @Override
- public MyFragmentTabHost.SavedState[] newArray(int size) {
- return new MyFragmentTabHost.SavedState[size];
- }
- };
- }
- public MyFragmentTabHost(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 MyFragmentTabHost(Context context, AttributeSet attrs) {
- super(context, attrs);
- initFragmentTabHost(context, attrs);
- }
- private void initFragmentTabHost(Context context, AttributeSet attrs) {
- final 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 FrameLayout.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 ourselves.
- 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(@NonNull TabHost.TabSpec tabSpec, @NonNull Class<?> clss,
- @Nullable Bundle args) {
- tabSpec.setContent(new MyFragmentTabHost.DummyTabFactory(mContext));
- final String tag = tabSpec.getTag();
- final MyFragmentTabHost.TabInfo info = new MyFragmentTabHost.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()) {
- final FragmentTransaction ft = mFragmentManager.beginTransaction();
- ft.detach(info.fragment);
- ft.commit();
- }
- }
- mTabs.add(info);
- addTab(tabSpec);
- }
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- final String currentTag = getCurrentTabTag();
- // Go through all tabs and make sure their fragments match
- // the correct state.
- FragmentTransaction ft = null;
- for (int i = 0, count = mTabs.size(); i < count; i++) {
- final MyFragmentTabHost.TabInfo tab = mTabs.get(i);
- tab.fragment = mFragmentManager.findFragmentByTag(tab.tag);
- if (tab.fragment != null && !tab.fragment.isDetached()) {
- if (tab.tag.equals(currentTag)) {
- // 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);
- }
- }
- }
- // We are now ready to go. Make sure we are switched to the
- // correct tab.
- mAttached = true;
- ft = doTabChanged(currentTag, ft);
- if (ft != null) {
- ft.commit();
- mFragmentManager.executePendingTransactions();
- }
- }
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mAttached = false;
- }
- @Override
- protected Parcelable onSaveInstanceState() {
- Parcelable superState = super.onSaveInstanceState();
- MyFragmentTabHost.SavedState ss = new MyFragmentTabHost.SavedState(superState);
- ss.curTab = getCurrentTabTag();
- return ss;
- }
- @Override
- protected void onRestoreInstanceState(Parcelable state) {
- if (!(state instanceof MyFragmentTabHost.SavedState)) {
- super.onRestoreInstanceState(state);
- return;
- }
- MyFragmentTabHost.SavedState ss = (MyFragmentTabHost.SavedState) state;
- super.onRestoreInstanceState(ss.getSuperState());
- setCurrentTabByTag(ss.curTab);
- }
- @Override
- public void onTabChanged(String tabId) {
- if (mAttached) {
- final FragmentTransaction ft = doTabChanged(tabId, null);
- if (ft != null) {
- ft.commit();
- }
- }
- if (mOnTabChangeListener != null) {
- mOnTabChangeListener.onTabChanged(tabId);
- }
- }
- @Nullable
- private FragmentTransaction doTabChanged(@Nullable String tag,
- @Nullable FragmentTransaction ft) {
- final MyFragmentTabHost.TabInfo newTab = getTabInfoForTag(tag);
- if (mLastTab != newTab) {
- if (ft == null) {
- ft = mFragmentManager.beginTransaction();
- }
- if (mLastTab != null) {
- if (mLastTab.fragment != null) {
- // ft.detach(mLastTab.fragment);
- ft.hide(mLastTab.fragment);//http://blog.csdn.net/w1054993544/article/details/37658183
- }
- }
- 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);//http://blog.csdn.net/w1054993544/article/details/37658183
- }
- }
- mLastTab = newTab;
- }
- return ft;
- }
- @Nullable
- private MyFragmentTabHost.TabInfo getTabInfoForTag(String tabId) {
- for (int i = 0, count = mTabs.size(); i < count; i++) {
- final MyFragmentTabHost.TabInfo tab = mTabs.get(i);
- if (tab.tag.equals(tabId)) {
- return tab;
- }
- }
- return null;
- }
- }
MyFragmentTabHost
代码是复制的系统的FragmentTabHost,只有一小部分和系统不一样的代码:
将tab_top_underline_item.xml文件复制到项目中
- <?xml version="1.0" encoding="utf-8"?>
- <!-- 带有下划线的顶部选项卡子项的布局文件(选择图片界面) -->
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/toptabLayout"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:paddingTop="@dimen/tab_top_underline_padding"
- android:paddingLeft="@dimen/tab_top_underline_padding"
- android:paddingRight="@dimen/tab_top_underline_padding"
- >
- <!-- 标题 -->
- <TextView
- android:id="@+id/top_title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:text=""
- android:textSize="@dimen/tab_top_underline_title_size"
- android:textColor="@color/tab_text_normal_top"
- android:layout_alignParentTop="true"
- android:layout_centerHorizontal="true" />
- <!-- 下划线-->
- <!-- android:background="@color/tab_underline_selected_top" -->
- <View
- android:id="@+id/top_underline"
- android:layout_width="match_parent"
- android:layout_height="@dimen/tab_top_underline_height"
- android:background="@color/tab_underline_normal_top"
- android:layout_below="@id/top_title"
- android:layout_centerHorizontal="true"
- android:layout_marginTop="@dimen/tab_top_underline_padding"
- />
- </RelativeLayout>
tab_top_underline_item
在colors.xml文件中添加以下代码:【后续可根据实际情况更改背景颜色、文字颜色值】
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <color name="colorPrimary">#3F51B5</color>
- <color name="colorPrimaryDark">#303F9F</color>
- <color name="colorAccent">#FF4081</color>
- <!-- *********************************顶部选项卡区域********************************* -->
- <!-- 顶部选项卡下划线背景色 -->
- <color name="tab_underline_normal_top">#00ffffff</color>
- <color name="tab_underline_selected_top">#FF7700</color>
- <!-- 顶部选项卡文本颜色 -->
- <color name="tab_text_normal_top">#191919</color>
- <color name="tab_text_selected_top">#FF7700</color>
- </resources>
在dimens.xml文件中添加以下代码:【后续可根据实际情况更改底部选项卡区域的高度值、文字大小值】
- <resources>
- <!-- Default screen margins, per the Android Design guidelines. -->
- <dimen name="activity_horizontal_margin">16dp</dimen>
- <dimen name="activity_vertical_margin">16dp</dimen>
- <!-- *********************************顶部选项卡区域********************************* -->
- <!-- 选项卡的内边距 -->
- <dimen name="tab_top_underline_padding">10dp</dimen>
- <!-- 选项卡标题的文字大小 -->
- <dimen name="tab_top_underline_title_size">18sp</dimen>
- <!-- 选项卡标题的下划线高度 -->
- <dimen name="tab_top_underline_height">3dp</dimen>
- </resources>
至此,选项卡子项的布局所需的文件已集成到项目中了。
在AndroidManifest.xml文件中添加网络请求的权限【demo中用到的】
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.why.project.fragmenttabhostunderlinedemo">
- <!-- ======================授权访问网络(HttpUtil)========================== -->
- <!-- 允许程序打开网络套接字 -->
- <uses-permission android:name="android.permission.INTERNET"/>
- <application
- android:allowBackup="true"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:supportsRtl="true"
- android:theme="@style/AppTheme">
- <activity android:name=".MainActivity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
- </application>
- </manifest>
三、使用方法
在Activity布局文件中引用MyFragmentTabHost【注意:TabWidget的android:layout_width="match_parent"】
- <?xml version="1.0" encoding="utf-8"?>
- <!-- 顶部选项卡区域 -->
- <com.why.project.fragmenttabhostunderlinedemo.views.tab.MyFragmentTabHost
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/tab_top_underline_ftabhost_layout"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- >
- <!-- 必须要有LinearLayout,因为FragmentTabHost属于FrameLayout帧布局 -->
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
- <!-- 选项卡区域 -->
- <!--注意:原来的配置:android:layout_height="?attr/actionBarSize"-->
- <TabWidget
- android:id="@android:id/tabs"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top|center_horizontal"/>
- <!-- 分割线 -->
- <View
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:background="#cfcfcf">
- </View>
- <!-- 碎片切换区域,且其id必须为@android:id/tabcontent -->
- <FrameLayout
- android:id="@android:id/tabcontent"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- />
- </LinearLayout>
- </com.why.project.fragmenttabhostunderlinedemo.views.tab.MyFragmentTabHost>
创建需要用到的fragment类和布局文件【后续可根据实际情况更改命名,并且需要重新import R文件】
fragment_web.xml文件布局如下
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <!-- webview -->
- <WebView
- android:id="@+id/web_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"></WebView>
- </LinearLayout>
WebViewFragment
- package com.why.project.fragmenttabhostunderlinedemo.fragment;
- import android.os.Bundle;
- import android.util.Log;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.webkit.WebView;
- import android.webkit.WebViewClient;
- import com.why.project.fragmenttabhostunderlinedemo.R;
- /**
- * @Created HaiyuKing
- * @Used 首页界面——碎片界面
- */
- public class WebViewFragment extends BaseFragment{
- private static final String TAG = "WebViewFragment";
- /**View实例*/
- private View myView;
- private WebView web_view;
- /**传递过来的参数*/
- private String bundle_param;
- //重写
- public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
- //使用FragmentTabHost时,Fragment之间切换时每次都会调用onCreateView方法,导致每次Fragment的布局都重绘,无法保持Fragment原有状态。
- //http://www.cnblogs.com/changkai244/p/4110173.html
- if(myView==null){
- myView = inflater.inflate(R.layout.fragment_web, container, false);
- //接收传参
- Bundle bundle = this.getArguments();
- bundle_param = bundle.getString("param");
- }
- //缓存的rootView需要判断是否已经被加过parent, 如果有parent需要从parent删除,要不然会发生这个rootview已经有parent的错误。
- ViewGroup parent = (ViewGroup) myView.getParent();
- if (parent != null) {
- parent.removeView(myView);
- }
- return myView;
- }
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- super.onActivityCreated(savedInstanceState);
- //初始化控件以及设置
- initView();
- //初始化数据
- initData();
- //初始化控件的点击事件
- initEvent();
- }
- @Override
- public void onResume() {
- super.onResume();
- }
- @Override
- public void onPause() {
- super.onPause();
- }
- @Override
- public void onDestroy() {
- super.onDestroy();
- }
- /**
- * 初始化控件
- */
- private void initView() {
- web_view = (WebView) myView.findViewById(R.id.web_view);
- //设置支持js脚本
- // web_view.getSettings().setJavaScriptEnabled(true);
- web_view.setWebViewClient(new WebViewClient() {
- /**
- * 重写此方法表明点击网页内的链接由自己处理,而不是新开Android的系统browser中响应该链接。
- */
- @Override
- public boolean shouldOverrideUrlLoading(WebView webView, String url) {
- //webView.loadUrl(url);
- return false;
- }
- });
- }
- /**
- * 初始化数据
- */
- public void initData() {
- Log.e("tag","{initData}bundle_param="+bundle_param);
- web_view.loadUrl(bundle_param);//加载网页
- }
- /**
- * 初始化点击事件
- * */
- private void initEvent(){
- }
- }
在Activity中使用如下【继承FragmentActivity或者其子类】
- package com.why.project.fragmenttabhostunderlinedemo;
- import android.content.Context;
- import android.os.Bundle;
- import android.support.v4.app.Fragment;
- import android.support.v7.app.AppCompatActivity;
- import android.view.View;
- import android.widget.TabHost;
- import android.widget.TextView;
- import android.widget.Toast;
- import com.why.project.fragmenttabhostunderlinedemo.fragment.WebViewFragment;
- import com.why.project.fragmenttabhostunderlinedemo.views.tab.MyFragmentTabHost;
- import java.util.ArrayList;
- public class MainActivity extends AppCompatActivity {
- private MyFragmentTabHost mTopUnderlineFTabHostLayout;
- //选项卡子类集合
- private ArrayList<TabItem> tabItemList = new ArrayList<TabItem>();
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- initTabList();
- initFTabHostLayout();
- setFTabHostData();
- initEvents();
- }
- /**
- * 初始化选项卡数据集合
- */
- private void initTabList() {
- //底部选项卡对应的Fragment类使用的是同一个Fragment,那么需要考虑切换Fragment时避免重复加载UI的问题】
- tabItemList.add(new TabItem(this,"百度",WebViewFragment.class));
- tabItemList.add(new TabItem(this,"博客园",WebViewFragment.class));
- tabItemList.add(new TabItem(this,"CSDN",WebViewFragment.class));
- }
- /**
- * 初始化FragmentTabHost
- */
- private void initFTabHostLayout() {
- //实例化
- mTopUnderlineFTabHostLayout = (MyFragmentTabHost) findViewById(R.id.tab_top_underline_ftabhost_layout);
- mTopUnderlineFTabHostLayout.setup(this, getSupportFragmentManager(), android.R.id.tabcontent);//最后一个参数是碎片切换区域的ID值
- // 去掉分割线
- mTopUnderlineFTabHostLayout.getTabWidget().setDividerDrawable(null);
- }
- /**
- * 设置选项卡的内容
- */
- private void setFTabHostData() {
- //Tab存在于TabWidget内,而TabWidget是存在于TabHost内。与此同时,在TabHost内无需在写一个TabWidget,系统已经内置了一个TabWidget
- for (int i = 0; i < tabItemList.size(); i++) {
- //实例化一个TabSpec,设置tab的名称和视图
- TabHost.TabSpec spec = mTopUnderlineFTabHostLayout.newTabSpec(tabItemList.get(i).getTabTitle()).setIndicator(tabItemList.get(i).getTabView());
- // 添加Fragment
- //初始化传参:http://bbs.csdn.net/topics/391059505
- Bundle bundle = new Bundle();
- if(i == 0 ){
- bundle.putString("param", "http://www.baidu.com");
- }else if(i == tabItemList.size() - 1){
- bundle.putString("param", "http://blog.csdn.net");
- }else{
- bundle.putString("param", "http://www.cnblogs.com");
- }
- mTopUnderlineFTabHostLayout.addTab(spec, tabItemList.get(i).getTabFragment(), bundle);
- }
- //默认选中第一项
- mTopUnderlineFTabHostLayout.setCurrentTab(0);
- tabItemList.get(0).setChecked(true);
- }
- private void initEvents() {
- //选项卡的切换事件监听
- mTopUnderlineFTabHostLayout.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
- @Override
- public void onTabChanged(String tabId) {
- //重置Tab样式
- for (int i = 0; i < tabItemList.size(); i++) {
- TabItem tabitem = tabItemList.get(i);
- if (tabId.equals(tabitem.getTabTitle())) {
- tabitem.setChecked(true);
- } else {
- tabitem.setChecked(false);
- }
- }
- Toast.makeText(MainActivity.this, tabId, Toast.LENGTH_SHORT).show();
- }
- });
- }
- /**
- * 选项卡子项类*/
- class TabItem{
- private Context mContext;
- private TextView top_title;
- private View top_underline;
- //底部选项卡对应的文字
- private String tabTitle;
- //底部选项卡对应的Fragment类
- private Class<? extends Fragment> tabFragment;
- public TabItem(Context mContext, String tabTitle, Class tabFragment){
- this.mContext = mContext;
- this.tabTitle = tabTitle;
- this.tabFragment = tabFragment;
- }
- public Class<? extends Fragment> getTabFragment() {
- return tabFragment;
- }
- public String getTabTitle() {
- return tabTitle;
- }
- /**
- * 获取底部选项卡的布局实例并初始化设置*/
- private View getTabView() {
- //============引用选项卡的各个选项的布局文件=================
- View toptabitemView = View.inflate(mContext,R.layout.tab_top_underline_item, null);
- //===========设置选项卡的文字==========
- top_title = (TextView) toptabitemView.findViewById(R.id.top_title);
- //设置选项卡的文字
- top_title.setText(tabTitle);
- //===========设置选项卡控件的下划线==========
- top_underline = (View) toptabitemView.findViewById(R.id.top_underline);
- return toptabitemView;
- }
- /**
- * 更新文字颜色
- */
- public void setChecked(boolean isChecked) {
- if(tabTitle != null){
- if(isChecked){
- //修改文字颜色
- top_title.setTextColor(getResources().getColor(R.color.tab_text_selected_top));
- //修改下划线的颜色
- top_underline.setBackgroundColor(getResources().getColor(R.color.tab_underline_selected_top));
- }else{
- //修改文字颜色
- top_title.setTextColor(getResources().getColor(R.color.tab_text_normal_top));
- //修改下划线的颜色
- top_underline.setBackgroundColor(getResources().getColor(R.color.tab_underline_normal_top));
- }
- }
- }
- }
- }
混淆配置
无
参考资料
Android的FragmentTabHost使用(顶部或底部菜单栏)
Android_ FragmentTabHost切换Fragment时避免重复加载UI
使用FragmentTabHost+TabLayout+ViewPager实现双层嵌套Tab
如何自定义FragmentTabHost中某一个Tab的点击效果
FragmentTabHost+fragment中获得fragment的对象
fragment中的attach/detach方法说明(网上拷贝,只为作笔记)
FragmentTabHost切换Fragment,与ViewPager切换Fragment时重新onCreateView的问题
项目demo下载地址
https://github.com/haiyuKing/FragmentTabHostUnderLineDemo
FragmentTabHostUnderLineDemo【FragmentTabHost带下划线】的更多相关文章
- 关于python中带下划线的变量和函数 的意义
总结: 变量: 1. 前带_的变量: 标明是一个私有变量, 只用于标明, 外部类还是可以访问到这个变量 2. 前带两个_ ,后带两个_ 的变量: 标明是内置变量, 3. 大写加下划线的变量: ...
- delphi 仅带下划线的TEdit控件
在做录入框的时候,很希望有一个只带下划线的文本框,网上介绍的很多,有自己做组件的,须不知Delphi下只需要简单设置几个属性即可达到目的.
- geotools导入shp文件到Oracle数据库时表名带下划线的问题解决
问题: 最近在做利用geotools导入shp文件到Oracle表中,发现一个问题Oracle表名带下划线时导入失败,问题代码行: dsOracle.getFeatureWriterAppend(or ...
- [转]关于python中带下划线的变量和函数的意义
Python 的代码风格由 PEP 8 描述.这个文档描述了 Python 编程风格的方方面面.在遵守这个文档的条件下,不同程序员编写的 Python 代码可以保持最大程度的相似风格.这样就易于阅读, ...
- TabTopUnderLineLayout【自定义顶部选项卡(带下划线)】
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 自定义顶部选项卡布局LinearLayout类,实现带下划线样式的效果. 备注:如果配合Fragment的话,MainActivit ...
- TabTopAutoLayout【自定义顶部选项卡区域(带下划线)(动态选项卡数据且可滑动)】
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 自定义顶部选项卡布局LinearLayout类,实现带下划线且可滑动效果.[实际情况中建议使用RecyclerView] 备注:如果 ...
- Python里的单下划线,双下划线,以及前后都带下划线的意义
Python里的单下划线,双下划线,以及前后都带下划线的意义: 单下划线如:_name 意思是:不能通过from modules import * 导入,如需导入需要:from modules imp ...
- 【转】关于python中带下划线的变量和函数 的意义
http://www.blogjava.net/lincode/archive/2011/02/02/343859.html 总结: 变量: 1. 前带_的变量: 标明是一个私有变量, 只用于标明 ...
- 带下划线的 HTTP Header无法获取到可能是因为nginx
背景:新版本修改了个功能是在老版本的基础上做的,同一个接口,需要兼容老版本,因此让前台在header中封装了 version版本号,client_type 客户端类型,根据这两个字段判断接口要走的逻辑 ...
随机推荐
- java-直接选择排序
直接选择排序是一种简单的排序方法,它每次从当前待排序的区间中选择出最小的元素,把该元素与该区间的第一个元素交换. 第一次从a[0]~a[n-1]中选取最小值,与a0]交换,第二次从a[1]~a[n-1 ...
- get.go
//获取空间文件 )) resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err ...
- disk.go
package disk import "syscall" //空间使用结构体 type DiskStatus struct { Size uint64 Used ...
- BZOJ_3994_[SDOI2015]约数个数和_莫比乌斯反演
BZOJ_3994_[SDOI2015]约数个数和_莫比乌斯反演 Description 设d(x)为x的约数个数,给定N.M,求 Input 输入文件包含多组测试数据. 第一行,一个整数T,表 ...
- 复仇者联盟3热映,我用python爬取影评告诉你它都在讲什么
Python(发音:英[?pa?θ?n],美[?pa?θɑ:n]),是一种面向对象.直译式电脑编程语言,也是一种功能强大的通用型语言,已经具有近二十年的发展历史,成熟且稳定.它包含了一组完善而且容易理 ...
- 实验吧——隐写术之复杂的QR_code
好久没有更新隐写术方面的题目了,对不起各位小可爱,今天我会多多更新几篇文章,来慰藉你们! 永远爱你们的 ---------新宝宝 1:复杂的QR_code 解题思路:保存图片之后使用在线解码工具,并没 ...
- JavaWeb学习总结(转载)
JavaWeb学习总结(五十三)--Web应用中使用JavaMail发送邮件 JavaWeb学习总结(五十二)--使用JavaMail创建邮件和发送邮件 JavaWeb学习总结(五十 ...
- 深入理解数据库磁盘存储(Disk Storage)
数据库管理系统将数据存储在磁盘.磁带以及其他的裸设备上,虽然这些设备的访问速度相比内存慢很多,但其非易失性和大容量的特点使他们成为数据存储的不二之选. 本文主要讨论大型数据库产品的磁盘存储内部结构,这 ...
- 《k8s 源码分析》- Custom Controller 之 Informer
Custom Controller 之 Informer 概述 架构概览 reflector - List & Watch API Server Reflector 对象 ListAndWat ...
- MySQL之父造访腾讯云 为腾讯云数据库开源点赞
近日,技术大牛 MariaDB 公司创始人兼CTO Michael Widenius(又名Monty).MariaDB 基金会主席 Kaj 来到中国,针对MariaDB与腾讯云的技术合作进行回访.去年 ...