I wanted to see if anyone has had success with customization of tabs using FragmentTabHost that comes with the new Android API level 17.
I was excited to be able to nest a tabHost within my ViewPager SherlockFragments, but I'm having trouble doing simple things like moving the tabs to the bottom or changing the layout of the tabs.
Has anyone seen a good example of using this functionality?
This is the only example I could find in the Android docs, and theres just about nothing that describes its use. It also seems to ignore whatever is defined in the layout for R.id.fragment1.
My question I suppose would be if anyone has come across a good tutorial re:FragmentTabHost
or if they have an idea about how to a) put the nested tabs at the bottom or b) change the layout of said tabs.
I've tried all the usual methods, but since it appears the XML layout file is overridden, I haven't had much luck.
private FragmentTabHost mTabHost;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
setContentView(R.layout.fragment_tabs);
mTabHost = (FragmentTabHost)findViewById(android.R.id.tabhost);
mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
mTabHost.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"),
FragmentStackSupport.CountingFragment.class, null);
mTabHost.addTab(mTabHost.newTabSpec("contacts").setIndicator("Contacts"),
LoaderCursorSupport.CursorLoaderListFragment.class, null);
mTabHost.addTab(mTabHost.newTabSpec("custom").setIndicator("Custom"),
LoaderCustomSupport.AppListFragment.class, null);
mTabHost.addTab(mTabHost.newTabSpec("throttle").setIndicator("Throttle"),
LoaderThrottleSupport.ThrottledLoaderListFragment.class, null);
return mTabHost;
}
After doing some research, it appears there may be a glitch with initializing the FragmentTabHost in the support library. The user here on Google code has provided a suggestion to this:
FragmentTabHost.java
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);
// If owner hasn't made its own view hierarchy, then as a convenience
// we will construct a standard one here.
/***** HERE COMMENT CODE BECAUSE findViewById(android.R.id.tabs) EVERY TIME IS NULL WE HAVE OWN LAYOUT ******//
// if (findViewById(android.R.id.tabs) == null) {
// LinearLayout ll = new LinearLayout(context);
// ll.setOrientation(LinearLayout.VERTICAL);
// addView(ll, new FrameLayout.LayoutParams(
// ViewGroup.LayoutParams.FILL_PARENT,
// ViewGroup.LayoutParams.FILL_PARENT));
//
// TabWidget tw = new TabWidget(context);
// tw.setId(android.R.id.tabs);
// tw.setOrientation(TabWidget.HORIZONTAL);
// ll.addView(tw, new LinearLayout.LayoutParams(
// ViewGroup.LayoutParams.FILL_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.FILL_PARENT, 0, 1));
// }
}
XML Layout for fragment:
<android.support.v4.app.FragmentTabHost
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">
<FrameLayout
android:id="#android:id/tabcontent"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="0"/>
<FrameLayout
android:id="#+id/realtabcontent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<TabWidget
android:id="#android:id/tabs"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0"/>
</LinearLayout>
</android.support.v4.app.FragmentTabHost>
I finally got to the bottom of this. There is an issue with FragmentTabHost.java which will always create a TabHost element for you, no matter what you define in XML and inflate beforehand.
As such, I commented out that part of code when writing my own version of FragmentTabHost.java.
Make sure to use your new version of this in your XML layout, <com.example.app.MyFragmentTabHost
And of course inflate it:
Fragment1.java:
mTabHost = (MyFragmentTabHost) view.findViewById(android.R.id.tabhost);
mTabHost.setup(getActivity(), getChildFragmentManager(), android.R.id.tabcontent);
MyFragmentTabHost.java:
package com.example.app;
import java.util.ArrayList;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
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.widget.FrameLayout;
import android.widget.TabHost;
/**
* Special TabHost that allows the use of {#link Fragment} objects for
* its tab content. When placing this in a view hierarchy, after inflating
* the hierarchy you must call {#link #setup(Context, FragmentManager, int)}
* to complete the initialization of the tab host.
*
*/
public class MyFragmentTabHost 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 TabHost.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 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);
}
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 Parcelable.Creator<SavedState> CREATOR
= new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new 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) {
TypedArray a = context.obtainStyledAttributes(attrs,
new int[] { android.R.attr.inflatedId }, 0, 0);
mContainerId = a.getResourceId(0, 0);
a.recycle();
super.setOnTabChangedListener(this);
/*** REMOVE THE REST OF THIS FUNCTION ***/
/*** findViewById(android.R.id.tabs) IS NULL EVERY TIME ***/
}
/**
* #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) {
super.setup();
mContext = context;
mFragmentManager = manager;
ensureContent();
}
public void setup(Context context, FragmentManager manager, int containerId) {
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(TabHost.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.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.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);
}
}
}
// 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);
}
}
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);
}
}
mLastTab = newTab;
}
return ft;
}
}
I think, it was a mistake to set method initFragmentTabHost() to constructor. At that time TabHost don't his children - it happens after. LinearLayout, for example, work with his children in onMeasure() method (grepcode). ViewGroup in constructor just init variables, and set mChildrenCount = 0 (grepcode).
All what I can did, it's only costumize FragmentTabHost:
<android.support.v4.app.FragmentTabHost xmlns:a="http://schemas.android.com/apk/res/android"
a:id="#android:id/tabhost"
style="#style/Widget.TabHost"
a:inflatedId="#+id/content" />
And costumize Tabs (have problems with tab heights, I solve them in code):
<LinearLayout xmlns:a="http://schemas.android.com/apk/res/android"
style="#style/Widget.Tab" >
<TextView
a:id="#android:id/title"
style="#style/Widget.TabTitle" />
</LinearLayout>
In code:
tabSpec = mTabHost.newTabSpec(tag).setIndicator(createTab(caption));
...
private View createTab(CharSequence title) {
final View v = View.inflate(getActivity(), LAYOUT_TAB, null);
((TextView) v.findViewById(android.R.id.title)).setText(title);
return v;
}
I think other customization with TabWidget we can do only with programmatically manipulating, like this:
final View tabs = (TabWidget) mTabHost.findViewById(android.R.id.tabs);
final ViewGroup parent = (ViewGroup) mTabHost.getChildAt(0);
parent.removeView(tabs);
parent.addView(tabs);
IMHO, this is not good.
as far as i tested jamisOn solution is good. It is important to not initialize MyFragmentTabHost with its constructor. At least if the class holding the MyFragmentTabHost is a fragment. I haven`t tested with a FragmentActivity...
I'd like to mention some more issues with FragmentTabHost. I'm using a ViewPager where each page (View) contains a FragmenTabHost and I had to overcome several problems:
1) FragmentTabHost assumes that it's the only FragmentTabHost in its parent FragmentManager (2nd argument to FragmentTabHost.setup()). This causes the rest of the problems...
2) the "tags" you provide when calling addTab() are passed straight through to the FragmentManager, so if you just use hardcoded tags for all your pages (a perfectly reasonable thing to do) your first page will create tab fragments while every other page will reuse those tabs. Yes, page 2 controls page 1...
Solution is to generate unique tag names. I appended the page number to the hardcoded strings:
public Object instantiateItem( ViewGroup container, int position )
{
...
tabHost.addTab( tabHost.newTabSpec( "tab1_" + position ) ...);
tabHost.addTab( tabHost.newTabSpec( "tab2_" + position ) ...);
tabHost.addTab( tabHost.newTabSpec( "tab3_" + position ) ...);
...
}
3) All tab fragments get placed in a container identified only by "view id" (the 3rd argument to FragmentTabHost.setup()). This means that when the FragmentManager resolves the viewId to a View, it always finds the first instance (from the first page). All your other pages are ignored.
Solution to this is to assign unique ids to your "tab content" views, for example:
public Object instantiateItem( ViewGroup container, int position )
{
View view = m_inflater.inflate(R.layout.page, null);
View tabContent = view.findViewById(R.id.realtabcontent);
tabContent.setId(m_nextViewId);
m_nextViewId++;
MyFragmentTabHost tabHost = (MyFragmentTabHost) view.findViewById(android.R.id.tabhost);
tabHost.setup(m_activity, m_activity.getSupportFragmentManager(), tabContent.getId());
...
}
4) It doesn't remove tab fragments when destroyed. While the ViewPager destroys unused Views as you swipe, the FragmentTabHosts contained within those views "leak" the tab fragments. When the ViewPager re-instantiates a previously seen page (using previously used tags), FragmentTabHost will notice that the fragments for those tabs already exist and simply reattach them. This blows up because the fragments point to views that have been destroyed by the ViewPager.
The solution is to remove fragments when FragmentTabHost is destroyed. You'll want to add this code to onDetachedFromWindow() in your local copy of FragmentTabHost.java
class MyFragmentTabHost
{
...
protected void onDetachedFromWindow()
{
super.onDetachedFromWindow();
mAttached = false;
boolean removeFragments = false;
if( mContext instanceof Activity )
{
Activity activity = (Activity)mContext;
removeFragments = !activity.isDestroyed();
}
if( removeFragments )
{
FragmentTransaction ft = null;
for (int i = 0; i < mTabs.size(); i++)
{
TabInfo tab = mTabs.get(i);
if (tab.fragment != null)
{
if (ft == null)
{
ft = mFragmentManager.beginTransaction();
}
ft.remove(tab.fragment);
}
}
if (ft != null)
{
ft.commit();
mFragmentManager.executePendingTransactions();
}
}
}
You could probably also work around these issues by using a FragmentPagerAdapter or FragmentStatePagerAdapter (makes Fragments) instead of a standard PagerAdapter (makes Views). Then you'd call FragmentTabHost.setup( ... fragment.getChildFragmentManager() ... ).
Related
I'm working on an Android Studio app and I would like to hava an indicator of in which fragment user is.
There is 4 pages, each one with some fragments and I would like to highlight the fragment where user is (the yellow bar)
Actually, the yellow bar don't move when fragment change.
Is it possible to make changement automatic or have I to programm the bar for each fragment ?
I don't know if it can help, but I use androidx and ViewPager2
public void setUp(final FormActivity context, final Toolbar toolbar, final Spinner spinner, final DrawerLayout drawerLayout, final ViewPager2 pager, final SlidingTabLayout tabs, FragmentActivity supportFragmentActivity) {
this.drawerLayout = drawerLayout;
this.pager = pager;
this.tabs = tabs;
this.progressBar = view.findViewById(R.id.progressBar);
In the .xml file :
<pack.myrhs.views.NVHeaderTextView
android:id="#+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_marginEnd="#dimen/drawer_side_margin
android:layout_marginRight="#dimen/drawer_side_margin"
android:layout_marginBottom="#dimen/drawer_divider_margin"
android:text="loading..."
android:textColor="#color/textIconsColor"
android:visibility="gone" />
And that's the NVHeaderTextView class:
public class NVHeaderTextView extends AppCompatTextView {
public NVHeaderTextView(Context context, AttributeSet attrs) {
super(context, attrs);
if(isInEditMode())
return;
String fontName = "fonts/Roboto-Medium.ttf";
Typeface typeface = Typeface.createFromAsset(context.getAssets(), fontName);
setTypeface(typeface);
setTextSize(14);
setTextColor(Color.argb((int) (255 * 1.00), 255, 255, 255));
int flags = getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG
| Paint.ANTI_ALIAS_FLAG;
setPaintFlags(flags);
}
}
UPDATE
I'm using SlidingTabLayout, so the TabLayoutMediator doesn't work (it seems to me).
I'm now, using the setViewPager() method:
#Override
protected void onPostExecute(Void params) {
pager.setAdapter(adapter);
tabs.setViewPager(pager);
if (adapter != null)
adapter.notifyDataSetChanged();
progressBar.setVisibility(View.GONE);
drawerLayout.closeDrawers();
cancel(true);
}
Thanks for advance.
SOLUTION
I finally solve my problem by switching my SlindingTabLayout to TabLayout.
In my setUp() method for my pages:
// Creation of the link between the tabLayout and the pager
tabs.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener(){
#Override
public void onTabSelected (TabLayout.Tab tab){
pager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected (TabLayout.Tab tab){
}
#Override
public void onTabReselected (TabLayout.Tab tab){
}
});
pager.registerOnPageChangeCallback(new OnPageChangeCallback() {
#Override
public void onPageSelected ( int position){
tabs.selectTab(tabs.getTabAt(position));
}
});
With the init of the tabs for each page:
drawerPageListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id){
if (currentPage != position) {
if (position != 1) { //not page2
//TOOLBAR
spinner.setVisibility(View.GONE);
}
adapter = null;
switch (position) {
case 0:
adapter = pageOneAdapter;
toolbar.setTitle(getResources().getString(R.string.page1));
currentPage = 0;
// Set up of the TabLayout
tabs.removeAllTabs();
tabs.addTab(tabs.newTab().setText("A"));
tabs.addTab(tabs.newTab().setText("B"));
tabs.addTab(tabs.newTab().setText("C"));
tabs.addTab(tabs.newTab().setText("D"));
break;
}
}
}
});
I'm new to android programming and I can't find a way to switch between tab1 to tab2 in a TabLayout, when the user clicks a button located in the tab1.
It may be something very simple, but I am clueless in my first app.
I have tried the following at first:
TabLayout.Tab tab = tabLayout.getTabAt(1);
tab.select();
And it used to work, but I changed the code and, at some point, it just didn't work anymore.
I also triedtab.getCustomView().setSelected(true);, but I got NullPointerException. So I checked in a if statement if tab was null, and it wasn't.
And then I tried
tabLayout.setScrollPosition(1,0f,true);
ViewPager viewPager = new ViewPager(mainView.getContext());
viewPager.setCurrentItem(1);
But none of the solutions above worked for me.
Here is my code:
View view;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
try {
view = inflater.inflate(R.layout.fragment_main, container, false);
Button GoB = view.findViewById(R.id.GoB);
final EditText USETV = view.findViewById(R.id.USETV);
final EditText commandEV = view.findViewById(R.id.CommandTV);
final SqlHelper db = new SqlHelper(getContext(), "myDatabase", null, 1);
GoB.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
String a = "";
if (USETV.getText().toString().length() > 0) {
a += "USE " + USETV.getText().toString() + " ;";
}
a += commandEV.getText().toString();
String[][] c = db.SqlQuery(a);
LayoutInflater factory = getLayoutInflater();
View resultView = factory.inflate(R.layout.fragment_result, null);
TableLayout tableLayout = resultView.findViewById(R.id.ResultContainer);
tableLayout.removeAllViews();
View mainView = factory.inflate(R.layout.main_activity,null);
TabLayout tabLayout = mainView.findViewById(R.id.tabs);
if (c[0].length > 0 && c[1].length > 0) {
TabLayout.Tab tab = tabLayout.getTabAt(1);
//tab.select();
//tab.getCustomView().setSelected(true);
//tabLayout.setScrollPosition(1,0f,true);
//ViewPager viewPager = new ViewPager(mainView.getContext());
//viewPager.setCurrentItem(1);
//
// do some stuff
}
} catch (Exception e) {
showException(e);
}
}
});
} catch (Exception e) {
showException(e);
}
return view;
}
TabLayout and ViewPager belong to your Activity, so in your Fragment you have to call Activity function to switch tab
Here is an example:
public class MyActivity extends Activity {
private TabLayout mTabLayout;
private ViewPager mViewPager;
#Override
public onCreate(...) {
MyFrament myFragment = new MyFragment(this);
// Add fragment to Viewpager ...
// Attach ViewPager to TabLayout ...
}
public void switchTab(int index) {
// Check index ...
mViewPager.setCurrentItem(index);
}
}
then
public class MyFragment extends Fragment {
private Context mContext;
private Button mButton;
public MyFragment(Context context) {
mContext = context;
}
#Override
public View onCreateView(...) {
...
mButton.setOnClickListener(v->{
((MyActivity)mContext).switchTab(1);
});
...
}
}
Hope this help!
Try putting these two lines inside your button's handler :
ActionBar actionBar = (ActionBar)getActivity().getActionBar();
actionBar.setSelectedNavigationItem(1);
Right Click on your package name
new > activity > tabActivity click ok
Chose layout name whatever you want e.g (Example.java).
Select Navigation style is Action Bar Tabs(which is option 2) and click Finish
5.create two new Fragments
6.Go to the java file here Example.java
After open Example.java file paste the blow code in
SectionsPagerAdapter extends FragmentPagerAdapter
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class below).
switch(position){
case 0:
return new Chats();
case 1:
return new Status();
case 2:
return new Call();
}
return PlaceholderFragment.newInstance(position + 1);
}
#Override
public int getCount() {
// Show 3 total pages.
return 3;
}
}
I am having troubles getting Android to set my listener. Somehow the context isn't of the type I am expecting it to be. I'm not sure where I am going wrong.
Below is AddEditCharacterFragment.java, where it is throwing an exception because context isn't of the type I expect.
public class AddEditCharacterFragment extends Fragment {
public static final String ARG_PARAM1 = "param1";
private InitiativeTrackerDBHelper mHelper;
private String mParam1;
private Character mCharacter;
public AddEditCharacterFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #return A new instance of fragment AddEditCharacterFragment.
*/
// TODO: Rename and change types and number of parameters
public static AddEditCharacterFragment newInstance() {
AddEditCharacterFragment fragment = new AddEditCharacterFragment();
Bundle args = new Bundle();
//args.putInt(ARG_PARAM1, id);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_add_character, container, false);
mHelper = new InitiativeTrackerDBHelper(getActivity());
mCharacter = mHelper.addCharacter();
EditText characterNameEditText = (EditText) v.findViewById(R.id.character_name_text_edit);
characterNameEditText.setText(mCharacter.getName());
characterNameEditText.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence c, int start, int before, int count) {
mCharacter.setName(c.toString());
}
public void beforeTextChanged(CharSequence c, int start, int before, int after) {
}
public void afterTextChanged(Editable c) {
}
});
EditText modifierPicker =
(EditText) v.findViewById(R.id.modEditText);
modifierPicker.setText(Integer.toString(mCharacter.getModifier()));
modifierPicker.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence c, int start, int before, int count) {
mCharacter.setModifier(Integer.parseInt(c.toString()));
}
public void beforeTextChanged(CharSequence c, int start, int before, int after) {
}
public void afterTextChanged(Editable c) {
}
});
Button saveButton = (Button) v.findViewById(R.id.saveButton);
saveButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mHelper != null)
{
mHelper.updateCharacter(mCharacter);
Toast.makeText(getActivity(), "Update complete!", Toast.LENGTH_LONG).show();
mListener.onCharacterSave();
}
}
});
return v;
}
private OnCharacterSave mListener;
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnCharacterSave) {
mListener = (OnCharacterSave) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnCharacterSave {
public void onCharacterSave();
}
}
AddEditCharacterActivity is the activity for the fragment above.
public class AddEditCharacterActivity extends SingleFragmentActivity
implements AddEditCharacterFragment.OnCharacterSave {
#Override
protected Fragment createFragment() {
return AddEditCharacterFragment.newInstance();
}
#Override
public void onCharacterSave() {
FragmentManager fm = getFragmentManager();
// Get the container for the character list
InitiativeListFragment initiativeListFragment = (InitiativeListFragment)
fm.findFragmentById(R.id.fragmentContainer);
// Update the UI
initiativeListFragment.updateInitiativeList();
}
}
InitiativeTrackerActivity which is using an intent to start the AddEditCharacterActivity and subsequently AddEditCharacterFragment.
public class InitiativeTrackerActivity extends SingleFragmentActivity
implements InitiativeListFragment.OnCharacterListListener, AddEditCharacterFragment.OnCharacterSave {
#Override
protected Fragment createFragment() {
return InitiativeListFragment.newInstance();
}
#Override
public void onAddCharacter() {
Intent intent = new Intent(this, AddEditCharacterActivity.class);
startActivity(intent);
}
#Override
public void onCharacterSave() {
FragmentManager fm = getFragmentManager();
// Get the container for the character list
InitiativeListFragment initiativeListFragment = (InitiativeListFragment)
fm.findFragmentById(R.id.fragmentContainer);
// Update the UI
initiativeListFragment.updateInitiativeList();
}
}
And the base class of SingleFragmentActivity for reference:
public abstract class SingleFragmentActivity extends AppCompatActivity {
protected abstract Fragment createFragment();
protected int getLayoutId() {
return R.layout.activity_single_fragment;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutId());
FragmentManager fm = getFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.fragmentContainer);
if (fragment == null) {
fragment = createFragment();
fm.beginTransaction()
.add(R.id.fragmentContainer, fragment)
.commit();
}
}
}
And InitiativeListFragment.java
package com.example.twistedpurpose.finalproject;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.app.Fragment;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CursorAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* A simple {#link Fragment} subclass.
* Activities that contain this fragment must implement the
* {#link InitiativeListFragment.OnCharacterListListener} interface
* to handle interaction events.
* Use the {#link InitiativeListFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class InitiativeListFragment extends Fragment {
private InitiativeTrackerDBHelper.CharacterCursor mCursor;
private CharacterCursorAdapter adapter;
private OnCharacterListListener mListener;
public InitiativeListFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #return A new instance of fragment InitiativeListFragment.
*/
public static InitiativeListFragment newInstance() {
return new InitiativeListFragment();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (adapter != null) {
adapter.notifyDataSetChanged();
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_initiative_list, container, false);
//getActivity().deleteDatabase("characters.db");
Context context = getActivity();
// 1. Create a new InitiativeTrackerDBHelper
InitiativeTrackerDBHelper dbHelper = new InitiativeTrackerDBHelper(context);
// 2. Query the characters and obtain a cursor (store in mCursor).
mCursor = dbHelper.queryCharacters();
// Find ListView to populate
ListView characterListView = (ListView) v.findViewById(R.id.character_listView);
// Setup cursor adapter using cursor from last step
adapter = new CharacterCursorAdapter(context, mCursor);
// Attach cursor adapter to the ListView
characterListView.setAdapter(adapter);
Button rollButton = (Button) v.findViewById(R.id.rollBtn);
rollButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
InitiativeTrackerDBHelper dbHelper = new InitiativeTrackerDBHelper(getContext());
List<Character> characterList = dbHelper.getCharacters();
InitiativeRoller.rollInitiative(characterList);
for (Character c : characterList) {
dbHelper.updateCharacter(c);
}
updateInitiativeList();
Toast.makeText(getContext(), "Roll initiative!", Toast.LENGTH_SHORT).show();
}
});
Button addButton = (Button) v.findViewById(R.id.addBtn);
addButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mListener != null) {
mListener.onAddCharacter();
}
}
});
return v;
}
public void updateInitiativeList(){
if(mCursor != null && adapter != null){
mCursor.requery();
adapter.notifyDataSetChanged();
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnCharacterListListener) {
mListener = (OnCharacterListListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnCharacterListListener {
public void onAddCharacter();
}
/**
* A character cursor adaptor for adding characters
* to a list
*/
private static class CharacterCursorAdapter extends CursorAdapter {
private InitiativeTrackerDBHelper.CharacterCursor mCharacterCursor;
public CharacterCursorAdapter(Context context, InitiativeTrackerDBHelper.CharacterCursor cursor) {
super(context, cursor, 0);
mCharacterCursor = cursor;
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// Use a layout inflater to get a row view
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
return inflater.inflate(R.layout.character_listview, parent, false);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView characterName = (TextView) view.findViewById(R.id.name);
TextView characterMod = (TextView) view.findViewById(R.id.mod);
TextView characterInit = (TextView) view.findViewById(R.id.init);
characterName.setText(mCharacterCursor.getCharacter().getName());
characterMod.setText(Integer.toString(mCharacterCursor.getCharacter().getModifier()));
characterInit.setText(Integer.toString(mCharacterCursor.getCharacter().getTotalInitiative()));
}
}
}
Your problem is that you do NOT implement the Interface in your activity…
public class AddEditCharacterActivity extends SingleFragmentActivity {
This does not implement OnCharacterSave.
This is what I meant with the earlier comment.
UPDATE:
You are misunderstanding Fragments.
// Get the container for the character list -> This is not true. You're not getting the "Container", you're trying to get an actual instance of a fragment.
InitiativeListFragment initiativeListFragment = (InitiativeListFragment)
fm.findFragmentById(R.id.fragmentContainer);
This would be fine, if that fragment were there.
Let me put it in a more graphic way, this is what you're doing… (give or take)
Start Activity XXX (SingleFragmentActivity).
At some point, InitiativeListFragment in R.id.fragmentContainer is replaced by AddEditCharacterActivity / AddEditCharacterFragment combo.
At this point, R.id.fragmentContainer contains a fragment of type AddEditCharacterFragment.
Since your Activity implements OnCharacterSave, so far so good.
Still in the same activity/fragment combo, you call onCharacterSave() which is implemented (see #4), so all is good.
You then tell the Fragment manager to get you the fragment in R.id.fragmentContainer and you explicitly say (aka: cast) that the Fragment is of the type InitiativeListFragment, but… your Activity should know this is not the case… because the current fragment is AddEditCharacterFragment.
What you ought to do is:
Re-Read about FragmentManager and FragmentTransactions.
If you're going to pass info to another Fragment that is not currently visible/started/attached/etc. then you have to obtain a reference (via TAG if you have one).
Then maybe add it to a container if possible while passing the "data" via a Bundle.
It's completely unclear what you're trying to do and it what order because your code doesn't really have a lot of separation of concerns so as you can see your Activities and Fragments are becoming monolithic monsters full of code and business logic. There are solutions and alternatives (Read about Model-View-Presenter or similar patterns) that can ease the mess while providing an easier environment to test your code.
That being said, regardless of the complexity of your code, I believe you need to understand WHY you're getting the exception, and I have the feeling that you need to practice that a little bit.
In short… when you do findFragmentById, you do get the Fragment (if existing), but you can't just cast it to whatever you want.
OLD COMMENTS:
newInstance() static methods should generally live inside the Fragments and return new YourFragment();
What I mean is the Fragment creation is usually done via a static method IN the fragment.
Say you have
MyFragment extends Fragment {
public static MyFragment newInstance() {
return new MyFragment();
}
public MyFragment() {
// empty constructor is most of the time needed to restore.
}
}
Then from the activity you usually do what you're doing, but the fragment instance is created by calling MyFragment.newInstance(); (this is how Google does it).
I suggest you add your fragment by Tag as well (it's faster). So you do
final Fragment existing = getSupportFragmentManager().findFragmentByTag(tag);
if (existing == null) {
final Fragment newInstance = MyFragment.newInstance();
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragmentContainer, newInstance, tag)
.commit();
}
Tag is a String and you can keep it in constants (final static String MYFRAGMENT_TAG = "MYFRAGMENT_TAG"; for example).
Are you using Support.V4 fragments? If so you need to change getFragmentManager() to getSupportFragmentManager() (It looks like you are, because you have AppCompatActivity.
Also, the fragment transaction, should be surrounded by if (savedInstaceState == null) { // do it here }
I do not see any problems with creating a fragment instance in your question as stated in other answers.
I think the problem is that your context is AddEditCharacterActivity where you do not implement OnCharacterSave interface.
So you should add:
public class AddEditCharacterActivity extends SingleFragmentActivity implements OnCharacterSave
How i can put icon in my tab using SlidingTabLayout. I just want to change the Titles into Icon. Please help me on how to do it.
Here is the code
ViewPagerAdapter.java
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
CharSequence Titles[]; // This will Store the Titles of the Tabs which are Going to be passed when ViewPagerAdapter is created
int NumbOfTabs; // Store the number of tabs, this will also be passed when the ViewPagerAdapter is created
// Build a Constructor and assign the passed Values to appropriate values in the class
public ViewPagerAdapter(FragmentManager fm,CharSequence mTitles[], int mNumbOfTabsumb) {
super(fm);
this.Titles = mTitles;
this.NumbOfTabs = mNumbOfTabsumb;
}
//This method return the fragment for the every position in the View Pager
#Override
public Fragment getItem(int position) {
if(position == 0) // if the position is 0 we are returning the First tab
{
OrderTab ordertab = new OrderTab();
return ordertab;
}
else if(position==1) // As we are having 2 tabs if the position is now 0 it must be 1 so we are returning second tab
{
ViewOrderTab viewordertab = new ViewOrderTab();
return viewordertab;
}
else
{
OrderStatus orderstatus = new OrderStatus();
return orderstatus;
}
}
// This method return the titles for the Tabs in the Tab Strip
#Override
public CharSequence getPageTitle(int position) {
return Titles[position];
}
// This method return the Number of tabs for the tabs Strip
#Override
public int getCount() {
return NumbOfTabs;
}
public static interface FirstShot
{
public void onFirstShot();
}
}
SlidingTabLayout.java
package com.example.work.mcoatorderingapp;
import android.content.Context;
import android.graphics.Typeface;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.TextView;
/**
* To be used with ViewPager to provide a tab indicator component which give constant feedback as to
* the user's scroll progress.
* <p>
* To use the component, simply add it to your view hierarchy. Then in your
* {#link android.app.Activity} or {#link android.support.v4.app.Fragment} call
* {#link #setViewPager(ViewPager)} providing it the ViewPager this layout is being used for.
* <p>
* The colors can be customized in two ways. The first and simplest is to provide an array of colors
* via {#link #setSelectedIndicatorColors(int...)}. The
* alternative is via the {#link TabColorizer} interface which provides you complete control over
* which color is used for any individual position.
* <p>
* The views used as tabs can be customized by calling {#link #setCustomTabView(int, int)},
* providing the layout ID of your custom layout.
*/
public class SlidingTabLayout extends HorizontalScrollView {
/**
* Allows complete control over the colors drawn in the tab layout. Set with
* {#link #setCustomTabColorizer(TabColorizer)}.
*/
public interface TabColorizer {
/**
* #return return the color of the indicator used when {#code position} is selected.
*/
int getIndicatorColor(int position);
}
private static final int TITLE_OFFSET_DIPS = 24;
private static final int TAB_VIEW_PADDING_DIPS = 16;
private static final int TAB_VIEW_TEXT_SIZE_SP = 12;
private int mTitleOffset;
private int mTabViewLayoutId;
private int mTabViewTextViewId;
private boolean mDistributeEvenly;
private ViewPager mViewPager;
private SparseArray<String> mContentDescriptions = new SparseArray<String>();
private ViewPager.OnPageChangeListener mViewPagerPageChangeListener;
private final SlidingTabStrip mTabStrip;
public SlidingTabLayout(Context context) {
this(context, null);
}
public SlidingTabLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SlidingTabLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// Disable the Scroll Bar
setHorizontalScrollBarEnabled(false);
// Make sure that the Tab Strips fills this View
setFillViewport(true);
mTitleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density);
mTabStrip = new SlidingTabStrip(context);
addView(mTabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
}
/**
* Set the custom {#link TabColorizer} to be used.
*
* If you only require simple custmisation then you can use
* {#link #setSelectedIndicatorColors(int...)} to achieve
* similar effects.
*/
public void setCustomTabColorizer(TabColorizer tabColorizer) {
mTabStrip.setCustomTabColorizer(tabColorizer);
}
public void setDistributeEvenly(boolean distributeEvenly) {
mDistributeEvenly = distributeEvenly;
}
/**
* Sets the colors to be used for indicating the selected tab. These colors are treated as a
* circular array. Providing one color will mean that all tabs are indicated with the same color.
*/
public void setSelectedIndicatorColors(int... colors) {
mTabStrip.setSelectedIndicatorColors(colors);
}
/**
* Set the {#link ViewPager.OnPageChangeListener}. When using {#link SlidingTabLayout} you are
* required to set any {#link ViewPager.OnPageChangeListener} through this method. This is so
* that the layout can update it's scroll position correctly.
*
* #see ViewPager#setOnPageChangeListener(ViewPager.OnPageChangeListener)
*/
public void OnPageChangeListener(ViewPager.OnPageChangeListener listener) {
mViewPagerPageChangeListener = listener;
}
/**
* Set the custom layout to be inflated for the tab views.
*
* #param layoutResId Layout id to be inflated
* #param textViewId id of the {#link TextView} in the inflated view
*/
public void setCustomTabView(int layoutResId, int textViewId) {
mTabViewLayoutId = layoutResId;
mTabViewTextViewId = textViewId;
}
/**
* Sets the associated view pager. Note that the assumption here is that the pager content
* (number of tabs and tab titles) does not change after this call has been made.
*/
public void setViewPager(ViewPager viewPager) {
mTabStrip.removeAllViews();
mViewPager = viewPager;
if (viewPager != null) {
viewPager.setOnPageChangeListener(new InternalViewPagerListener());
populateTabStrip();
}
}
/**
* Create a default view to be used for tabs. This is called if a custom tab view is not set via
* {#link #setCustomTabView(int, int)}.
*/
protected TextView createDefaultTabView(Context context) {
TextView textView = new TextView(context);
textView.setGravity(Gravity.CENTER);
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP);
textView.setTypeface(Typeface.DEFAULT_BOLD);
textView.setLayoutParams(new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
TypedValue outValue = new TypedValue();
getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground,
outValue, true);
textView.setBackgroundResource(outValue.resourceId);
textView.setAllCaps(true);
int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density);
textView.setPadding(padding, padding, padding, padding);
return textView;
}
private void populateTabStrip() {
final PagerAdapter adapter = mViewPager.getAdapter();
final View.OnClickListener tabClickListener = new TabClickListener();
for (int i = 0; i < adapter.getCount(); i++) {
View tabView = null;
TextView tabTitleView = null;
if (mTabViewLayoutId != 0) {
// If there is a custom tab view layout id set, try and inflate it
tabView = LayoutInflater.from(getContext()).inflate(mTabViewLayoutId, mTabStrip,
false);
tabTitleView = (TextView) tabView.findViewById(mTabViewTextViewId);
}
if (tabView == null) {
tabView = createDefaultTabView(getContext());
}
if (tabTitleView == null && TextView.class.isInstance(tabView)) {
tabTitleView = (TextView) tabView;
}
if (mDistributeEvenly) {
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) tabView.getLayoutParams();
lp.width = 0;
lp.weight = 1;
}
tabTitleView.setText(adapter.getPageTitle(i));
tabView.setOnClickListener(tabClickListener);
String desc = mContentDescriptions.get(i, null);
if (desc != null) {
tabView.setContentDescription(desc);
}
mTabStrip.addView(tabView);
if (i == mViewPager.getCurrentItem()) {
tabView.setSelected(true);
}
tabTitleView.setTextColor(getResources().getColorStateList(R.color.selector));
tabTitleView.setTextSize(14);
}
}
public void setContentDescription(int i, String desc) {
mContentDescriptions.put(i, desc);
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (mViewPager != null) {
scrollToTab(mViewPager.getCurrentItem(), 0);
}
}
private void scrollToTab(int tabIndex, int positionOffset) {
final int tabStripChildCount = mTabStrip.getChildCount();
if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) {
return;
}
View selectedChild = mTabStrip.getChildAt(tabIndex);
if (selectedChild != null) {
int targetScrollX = selectedChild.getLeft() + positionOffset;
if (tabIndex > 0 || positionOffset > 0) {
// If we're not at the first child and are mid-scroll, make sure we obey the offset
targetScrollX -= mTitleOffset;
}
scrollTo(targetScrollX, 0);
}
}
private class InternalViewPagerListener implements ViewPager.OnPageChangeListener {
private int mScrollState;
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
int tabStripChildCount = mTabStrip.getChildCount();
if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
return;
}
mTabStrip.onViewPagerPageChanged(position, positionOffset);
View selectedTitle = mTabStrip.getChildAt(position);
int extraOffset = (selectedTitle != null)
? (int) (positionOffset * selectedTitle.getWidth())
: 0;
scrollToTab(position, extraOffset);
if (mViewPagerPageChangeListener != null) {
mViewPagerPageChangeListener.onPageScrolled(position, positionOffset,
positionOffsetPixels);
}
}
#Override
public void onPageScrollStateChanged(int state) {
mScrollState = state;
if (mViewPagerPageChangeListener != null) {
mViewPagerPageChangeListener.onPageScrollStateChanged(state);
}
}
#Override
public void onPageSelected(int position) {
if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
mTabStrip.onViewPagerPageChanged(position, 0f);
scrollToTab(position, 0);
}
for (int i = 0; i < mTabStrip.getChildCount(); i++) {
mTabStrip.getChildAt(i).setSelected(position == i);
}
if (mViewPagerPageChangeListener != null) {
mViewPagerPageChangeListener.onPageSelected(position);
}
}
}
private class TabClickListener implements View.OnClickListener {
#Override
public void onClick(View v) {
for (int i = 0; i < mTabStrip.getChildCount(); i++) {
if (v == mTabStrip.getChildAt(i)) {
mViewPager.setCurrentItem(i);
return;
}
}
}
}
}
The Fragments are OrderTab.java the same code with ViewOrderTab.java and OrderStatus.java
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;
public class OrderStatus extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v =inflater.inflate(R.layout.orderstatus_list,container,false);
return v;
}
}
MainActivity.java
EditText search;
ProgressDialog pDialog;
Toolbar toolbar;
ViewPager pager;
ViewPagerAdapter adapter;
SlidingTabLayout tabs;
CharSequence Titles[] = {"Order Product", "Cart", "Order Status"};
int Numboftabs = 3;
String titlebar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Creating The Toolbar and setting it as the Toolbar for the activity
toolbar = (Toolbar) findViewById(R.id.tool_bar);
setSupportActionBar(toolbar);
// Creating The ViewPagerAdapter and Passing Fragment Manager, Titles fot the Tabs and Number Of Tabs.
adapter = new ViewPagerAdapter(getSupportFragmentManager(), Titles, Numboftabs);
// Assigning ViewPager View and setting the adapter
pager = (ViewPager) findViewById(R.id.pager);
pager.setAdapter(adapter);
// Assiging the Sliding Tab Layout View
tabs=(SlidingTabLayout)
findViewById(R.id.tabs);
tabs.setDistributeEvenly(true); // To make the Tabs Fixed set this true, This makes the tabs Space Evenly in Available width
// Setting Custom Color for the Scroll bar indicator of the Tab View
tabs.setCustomTabColorizer(new SlidingTabLayout.TabColorizer()
{
#Override
public int getIndicatorColor(int position) {
return getResources().getColor(R.color.tabsScrollColor);
}
}
);
// Setting the ViewPager For the SlidingTabsLayout
tabs.setViewPager(pager);
Try
private int[] imageResId = {
R.drawable.ic_home,
R.drawable.ic_my_timeline,
R.drawable.ic_my_pages,
R.drawable.ic_my_groups,
R.drawable.ic_liked_pages
};
#Override
public CharSequence getPageTitle(int position) {
Drawable image = mContext.getResources().getDrawable(imageResId[position]);
image.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight());
SpannableString sb = new SpannableString(" ");
ImageSpan imageSpan = new ImageSpan(image, ImageSpan.ALIGN_BOTTOM);
sb.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return sb;
}
instead of
#Override
public CharSequence getPageTitle(int position) {
return Titles[position];
}
in your ViewPagerAdapter class.
EDIT1:
In your activity change
adapter = new ViewPagerAdapter(getSupportFragmentManager(), Titles, Numboftabs);
to
adapter = new ViewPagerAdapter(this, getSupportFragmentManager(), Titles, Numboftabs);
Then in your ViewPagerAdapter following changes are needed.
Context mContext;
public ViewPagerAdapter(Context context, FragmentManager fm,CharSequence mTitles[], int mNumbOfTabsumb) {
super(fm);
this.mContext = context;
this.Titles = mTitles;
this.NumbOfTabs = mNumbOfTabsumb;
}
EDIT2:
try extending FragmentPagerAdapter instead of FragmentStatePagerAdapter in your ViewPagerAdapter.
In your main activity code should be this:
tabs=(SlidingTabLayout)findViewById(R.id.tabs);
tabs.setCustomTabView(R.layout.custom_tab, 0);
Here is custom_tab.xml:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp"
android:textStyle="bold"
android:background="?android:selectableItemBackground"
android:padding="16dp"
android:gravity="center" />
hope this helps!
I am using a viewpager "tabs + swipe" and I would like to set different titles in the actionBar for each fragment so that when I switch, title changes.
I tried several things without success, only the last title displays... and does not change anymore when I switch...
First, make your activity implement an OnPageChangeListener.
Then, when you create your ViewPager, you can use mViewPager.setOnPageChangeListener(this) so that your activity will receive callbacks when the page changes.
Finally, you need to implement the OnPageChangeListener callbacks. Your onPageSelected() method should be something like this:
#Override
public abstract void onPageSelected(int position) {
setTitle(getTitleFromPosition(position));
}
The other two callbacks can be empty.
Though the question is a bit outdated I would suggest my solution. Scenario: tabs+swipe and every tab have fragment navigation stack. So action bar title can be changed not only through switching and swiping tabs but with navigation in every tab. To provide title per fragment I declared TitleProvider interface, so if fragment has custom title it must implement this interface.
public interface TitleProvider {
CharSequence getTitle();
}
Below there is custom FragmentPagerAdapter, that handles switching, swiping, navigation and title update:
public class TabsAdapter extends FragmentPagerAdapter implements
TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener {
private final FragmentActivity activity;
private final TabHost tabHost;
private final ViewPager viewPager;
private final ArrayList<Fragment> fragments = new ArrayList<Fragment>();
private final Hashtable<Fragment, Stack<Class<?>>> fragmentBackstack = new Hashtable<Fragment, Stack<Class<?>>>();
static class DummyTabFactory implements TabHost.TabContentFactory {
private final Context context;
public DummyTabFactory(Context context) {
this.context = context;
}
#Override
public View createTabContent(String tag) {
View v = new View(context);
v.setMinimumWidth(0);
v.setMinimumHeight(0);
return v;
}
}
public TabsAdapter(FragmentActivity activity, TabHost tabHost,
ViewPager pager) {
super(activity.getSupportFragmentManager());
this.activity = activity;
this.tabHost = tabHost;
viewPager = pager;
tabHost.setOnTabChangedListener(this);
viewPager.setAdapter(this);
viewPager.setOnPageChangeListener(this);
}
public void addTab(String tag, int drawableId, Fragment fragment,
int tabIndicatorId) {
TabSpec tabSpec = tabHost.newTabSpec(tag);
tabSpec.setContent(new DummyTabFactory(activity.getApplicationContext()));
View tabIndicator = LayoutInflater.from(
activity.getApplicationContext()).inflate(tabIndicatorId,
tabHost.getTabWidget(), false);
TextView title = (TextView) tabIndicator.findViewById(R.id.tab_title);
if (fragment instanceof TitleProvider) {
title.setText(((TitleProvider) fragment).getTitle());
}
ImageView icon = (ImageView) tabIndicator.findViewById(R.id.tab_icon);
icon.setImageResource(drawableId);
tabSpec.setIndicator(tabIndicator);
fragments.add(fragment);
tabHost.addTab(tabSpec);
notifyDataSetChanged();
}
#Override
public int getCount() {
return fragments.size();
}
#Override
public Fragment getItem(int position) {
return fragments.get(position);
}
#Override
public int getItemPosition(Object object) {
int returnCode;
if (fragments.contains(object)) {
returnCode = POSITION_UNCHANGED;
} else {
returnCode = POSITION_NONE;
}
return returnCode;
}
#Override
public void onTabChanged(String tabId) {
int position = tabHost.getCurrentTab();
viewPager.setCurrentItem(position);
updateTitle();
}
#Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
// Unfortunately when TabHost changes the current tab, it kindly
// also takes care of putting focus on it when not in touch mode.
// The jerk.
// This hack tries to prevent this from pulling focus out of our
// ViewPager.
TabWidget widget = tabHost.getTabWidget();
int oldFocusability = widget.getDescendantFocusability();
widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
tabHost.setCurrentTab(position);
widget.setDescendantFocusability(oldFocusability);
}
#Override
public void onPageScrollStateChanged(int state) {
}
public void navigate(Fragment fromFragment, Fragment toFragment) {
startUpdate(viewPager);
FragmentTransaction transaction = activity.getSupportFragmentManager()
.beginTransaction();
transaction.remove(fromFragment);
transaction.commit();
Stack<Class<?>> backstack;
if (fragmentBackstack.containsKey(fromFragment)) {
backstack = fragmentBackstack.get(fromFragment);
fragmentBackstack.remove(fromFragment);
} else {
backstack = new Stack<Class<?>>();
}
backstack.push(fromFragment.getClass());
fragmentBackstack.put(toFragment, backstack);
fragments.set(fragments.indexOf(fromFragment), toFragment);
finishUpdate(viewPager);
notifyDataSetChanged();
updateTitle();
}
public Boolean navigateBack() {
startUpdate(viewPager);
Fragment fromFragment = fragments.get(viewPager.getCurrentItem());
if (!fragmentBackstack.containsKey(fromFragment))
return false;
Stack<Class<?>> backstack = fragmentBackstack.get(fromFragment);
if (backstack.isEmpty())
return false;
fragmentBackstack.remove(fromFragment);
Fragment toFragment = Fragment.instantiate(activity, backstack.pop()
.getName());
fragmentBackstack.put(toFragment, backstack);
fragments.set(fragments.indexOf(fromFragment), toFragment);
FragmentTransaction transaction = activity.getSupportFragmentManager()
.beginTransaction();
transaction.remove(fromFragment);
transaction.commit();
finishUpdate(viewPager);
notifyDataSetChanged();
updateTitle();
return true;
}
protected Fragment getCurrentFragment() {
return fragments.get(viewPager.getCurrentItem());
}
protected void updateTitle() {
Fragment fragment = getCurrentFragment();
if (fragment instanceof TitleProvider) {
activity.setTitle(((TitleProvider) fragment).getTitle());
}
}
}
#Override
public void onPageSelected(int position) {
tabHost.setSelectedNavigationItem(position);
if (position == 0){
setTitle(R.string.where_is_the_bus);
}
else if (position == 1){
setTitle(R.string.bus_card);
}
else if (position == 2){
setTitle(R.string.favo);
}
You can make it like this "it's easy right?"