Reputation: 131
I am currently working on a tabbed layout using fragments for an application for Android >= 4.0. The tabs are not in the action bar. I don't need a new activity for every tab. I always show the same amount and same kind of data.
Since there is no "best practice" guide for my purposes (I think?!) I post my code here (which is working). I hope you find some passages where I can do some (performance) improvements and where I did something that is not "best practice" (e.g. architecture). I already think about the passage where I use the Gridview in the fragment class.
The activity which should show the tabbed layout
public class LevelActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_level);
}
}
The xml file for the above activity
<fragment
class="com.test.puzzle.tabs.TabsFragment"
android:id="@+id/tabs_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
My fragment class:
public class TabsFragment extends Fragment implements OnTabChangeListener {
public static final String TAB_1 = "Pack 1";
public static final String TAB_2 = "Pack 2";
private View mRoot;
private TabHost mTabHost;
private int mCurrentTab;
private TabFragmentAdapter mAdapter;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mRoot = inflater.inflate(R.layout.tabs_fragment, container, false);
mTabHost = (TabHost) mRoot.findViewById(android.R.id.tabhost);
setupTabs();
return mRoot;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setRetainInstance(true);
mTabHost.setOnTabChangedListener(this);
mTabHost.setCurrentTab(mCurrentTab);
updateTab(R.id.tab_1);
}
private void setupTabs() {
mTabHost.setup(); // you must call this before adding your tabs!
mTabHost.addTab(newTab(TAB_1, R.id.tab_1));
mTabHost.addTab(newTab(TAB_2, R.id.tab_2));
}
private TabSpec newTab(String tag, int tabContentId) {
TabSpec spec = mTabHost.newTabSpec(tag);
spec.setContent(tabContentId);
spec.setIndicator(tag);
return spec;
}
@Override
public void onTabChanged(String tabId) {
if (TAB_1.equals(tabId)) {
updateTab(R.id.tab_1);
mCurrentTab = 0;
}
if (TAB_2.equals(tabId)) {
updateTab(R.id.tab_2);
mCurrentTab = 1;
}
}
private void updateTab(int viewId) {
final GridView grid = (GridView) mRoot.findViewById(viewId);
if (mAdapter == null) {
mAdapter = new TabFragmentAdapter(mRoot.getContext(), mTabHost.getCurrentTabTag());
}
grid.setAdapter(mAdapter);
}
}
My xml layout file for the fragment:
<?xml version="1.0" encoding="utf-8"?>
<TabHost
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TabWidget
android:id="@android:id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<GridView
android:id="@+id/tab_1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="2"
android:verticalSpacing="20dp"
android:horizontalSpacing="20dp">
</GridView>
<GridView
android:id="@+id/tab_2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="2"
android:verticalSpacing="20dp"
android:horizontalSpacing="20dp">
</GridView>
</FrameLayout>
</LinearLayout>
</TabHost>
My adapter class for the fragements data
public class TabFragmentAdapter extends BaseAdapter {
private Context mContext;
private String mPackString;
private final String[] WORDS = {"test3", "test6", "test4", "test4",
"test1", "test2", "test7", "test3", "test9", "test6",
"test3", "test7"};
public TabFragmentAdapter(Context context, String packString) {
mContext = context;
mPackString = packString;
}
@Override
public int getCount() {
return WORDS.length;
}
@Override
public Object getItem(int i) {
return WORDS[i];
}
@Override
public long getItemId(int i) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
ViewHolder viewHolder;
if (view == null) { // if it's not recycled, initialize some attributes
final LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.list_item, parent, false);
viewHolder = new ViewHolder(view);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
viewHolder.getTextView().setText(WORDS[position]);
return view;
}
private class ViewHolder {
private final View mRoot;
private TextView mText;
public ViewHolder(View root) {
mRoot = root;
}
public TextView getTextView() {
if (mText == null) {
mText = (TextView) mRoot.findViewById(R.id.text);
}
return mText;
}
}
}
My list item xml
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="match_parent"
></TextView>
Upvotes: 1
Views: 2090
Reputation: 1142
I answered a related question that might help you as it details how to make tabs with fragments. My suggestion is to use the separate fragments for each tab (I think it makes everything much easier), but depending on your implementation you may want to pursue another direction.
Upvotes: 2
Reputation: 157
One thing I've noticed is that you should do this:
mRoot = inflater.inflate(R.layout.tabs_fragment, container, false);
instead of this
mRoot = inflater.inflate(R.layout.tabs_fragment, null);
Check out this link:
http://www.doubleencore.com/2013/05/layout-inflation-as-intended/
Upvotes: 1