ActionBar Tab with Custom View not switching - android

I have the following ActionBar with custom tabs:
If I want to switch tabs by clicking in the red areas below it works:
but if I click inside the custom view it doesn't switch the view (i.e. if i click in the below red areas):
(apologies for the bad drawings! -_-)
Here's the code (including setOnClickListener's) which I have tried:
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
mSectionsPagerAdapter = new SectionsPagerAdapter(getFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
// Set up the action bar.
final ActionBar actionBar = getSupportActionBar();
if(actionBar != null) {
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// When swiping between different sections, select the corresponding
// tab. We can also use ActionBar.Tab#select() to do this if we have
// a reference to the Tab.
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
// For each of the sections in the app, add a tab to the action bar.
for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
// Create a tab with text corresponding to the page title defined by
// the adapter. Also specify this Activity object, which implements
// the TabListener interface, as the callback (listener) for when
// this tab is selected.
final int position = i;
LayoutInflater layoutInflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
View rootView = layoutInflater.inflate(R.layout.tabs_add_item, null);
if(rootView != null) {
FontTextView tv = (FontTextView) rootView.findViewById(R.id.tab_title);
tv.setText(mSectionsPagerAdapter.getPageTitle(i));
RelativeLayout rl = (RelativeLayout) rootView.findViewById(R.id.tab);
rl.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.i("ADDITEM", "layout Clicked");
mViewPager.setCurrentItem(position);
}
});
rootView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.i("ADDITEM", "view Clicked");
mViewPager.setCurrentItem(position);
}
});
actionBar.addTab(
actionBar.newTab()
.setCustomView(rootView)
.setTabListener(this));
}
}
}
The relevant setTabListener's:
#Override
public void onTabSelected(ActionBar.Tab tab, android.support.v4.app.FragmentTransaction ft) {
// When the given tab is selected, switch to the corresponding page in
// the ViewPager.
Log.i("ADDITEM", "TAB CLICKED");
mViewPager.setCurrentItem(tab.getPosition());
View v = tab.getCustomView();
if(v != null){
FontTextView tv = (FontTextView) v.findViewById(R.id.tab_title);
tv.setCustomFont(getApplicationContext(), "fonts/seguisb.ttf");
}
}
#Override
public void onTabUnselected(ActionBar.Tab tab, android.support.v4.app.FragmentTransaction ft) {
View v = tab.getCustomView();
if(v != null){
FontTextView tv = (FontTextView) v.findViewById(R.id.tab_title);
tv.setCustomFont(getApplicationContext(), "fonts/segoeui.ttf");
}
}
#Override
public void onTabReselected(ActionBar.Tab tab, android.support.v4.app.FragmentTransaction ft) {
}
and of course the custom tab layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/tab"
xmlns:vers="http://schemas.android.com/apk/res-auto"
android:clickable="true"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
android:padding="0dp">
<uk.verscreative.smart5_a_day.views.widget.FontTextView
android:id="#+id/tab_title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:gravity="center"
android:inputType="textCapCharacters"
android:textColor="#color/white"
android:text="TEXT"
android:singleLine="true"
vers:customTypeface="fonts/segoeui.ttf"
/>
</RelativeLayout>
If you guys need any more detail let me know! Thanks in advance!

I realised that my custom text view was match_parenting so I changed the setOnClickListener to this:
// For each of the sections in the app, add a tab to the action bar.
for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
// Create a tab with text corresponding to the page title defined by
// the adapter. Also specify this Activity object, which implements
// the TabListener interface, as the callback (listener) for when
// this tab is selected.
final int position = i;
LayoutInflater layoutInflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
View rootView = layoutInflater.inflate(R.layout.tabs_add_item, null);
if(rootView != null) {
FontTextView tv = (FontTextView) rootView.findViewById(R.id.tab_title);
tv.setText(mSectionsPagerAdapter.getPageTitle(i));
tv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mViewPager.setCurrentItem(position);
}
});
actionBar.addTab(
actionBar.newTab()
.setCustomView(rootView)
.setTabListener(this));
}
}
add it works now!

Related

ViewPager not showing page content / not refreshing after changing the view

I am using ViewPager / FragmentPagerAdapter in one of my application fragments to display different listviews in each page (see the picture below) :
The problem is that after i change the current view (Fragment) and i reopen it again, the listview isn't rendered (see the picture below) :
The behaviour is random, sometimes the listview are shown when i slide between different tabs/pages.
Here is my fragment code :
public class AstucesFragment extends Fragment implements ActionBar.TabListener {
ActionBar actionBar;
AppSectionsPagerAdapter mAppSectionsPagerAdapter;
ViewPager mViewPager;
public static String[] tabslist = new String[5];
public AstucesFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_astuces, container, false);
tabslist[0] = getActivity().getResources().getString(R.string.astuces_quotidien);
tabslist[1] = getActivity().getResources().getString(R.string.astuces_resto);
tabslist[2] = getActivity().getResources().getString(R.string.astuces_loisirs);
tabslist[3] = getActivity().getResources().getString(R.string.astuces_transports);
tabslist[4] = getActivity().getResources().getString(R.string.astuces_tous);
mAppSectionsPagerAdapter = new AppSectionsPagerAdapter(getActivity().getSupportFragmentManager());
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
mViewPager = (ViewPager) view.findViewById(R.id.astuces_pager);
mViewPager.setAdapter(mAppSectionsPagerAdapter);
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
actionBar.addTab(
actionBar.newTab()
.setCustomView(R.layout.fragment_astuces_tabs_quotidien)
.setTabListener(this));
actionBar.addTab(
actionBar.newTab()
.setCustomView(R.layout.fragment_astuces_tabs_resto)
.setTabListener(this));
actionBar.addTab(
actionBar.newTab()
.setCustomView(R.layout.fragment_astuces_tabs_loisirs)
.setTabListener(this));
actionBar.addTab(
actionBar.newTab()
.setCustomView(R.layout.fragment_astuces_tabs_transports)
.setTabListener(this));
actionBar.addTab(
actionBar.newTab()
.setCustomView(R.layout.fragment_astuces_tabs_tous)
.setTabListener(this));
return view;
}
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
mViewPager.setCurrentItem(tab.getPosition());
Log.i("AstucesFragment","onTabSelected()");
}
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
mViewPager.setCurrentItem(tab.getPosition());
Log.i("AstucesFragment","onTabReselected()");
}
/**
* A {#link android.support.v4.app.FragmentPagerAdapter} that returns a fragment corresponding to one of the primary
* sections of the app.
*/
public static class AppSectionsPagerAdapter extends FragmentPagerAdapter {
public AppSectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
Log.i("AppSectionsPagerAdapter","Page ID : "+i);
// The other sections of the app are dummy placeholders.
Fragment fragment = new AstucesListFragment();
Bundle args = new Bundle();
args.putString(AstucesListFragment.ARG_PAGE_CAT, tabslist[i]);
fragment.setArguments(args);
return fragment;
}
#Override
public int getCount() {
return tabslist.length;
}
#Override
public CharSequence getPageTitle(int position) {
return tabslist[position];
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
}
}
/**
* A dummy fragment representing a section of the app, but that simply displays dummy text.
*/
public static class AstucesListFragment extends Fragment {
public static final String ARG_PAGE_CAT = "page_cat";
private List<Astuce> astuceList = new ArrayList<Astuce>();
private ListView listView;
private AstuceAdapter adapter;
private AstuceDAO astuceDAO;
public AstucesListFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_astuces_page, container, false);
Bundle args = getArguments();
Log.i("AstucesListFragment","onCreateView()");
String theme = "";
if (args.getString(ARG_PAGE_CAT) == getString(R.string.astuces_quotidien)) theme = "Q";
else if (args.getString(ARG_PAGE_CAT) == getString(R.string.astuces_resto)) theme = "R";
else if (args.getString(ARG_PAGE_CAT) == getString(R.string.astuces_loisirs)) theme = "L";
else if (args.getString(ARG_PAGE_CAT) == getString(R.string.astuces_transports)) theme = "T";
else theme = "";
astuceDAO = new AstuceDAO();
astuceList = astuceDAO.findAstuceByTheme(theme);
listView = (ListView) rootView.findViewById(R.id.astuces_list);
adapter = new AstuceAdapter(getActivity(), astuceList);
listView.setAdapter(adapter);
adapter.notifyDataSetChanged();
return rootView;
}
}
}
How can i fix this problem ?
If you want your fragments to maintain its state even after changing the tabs,
Try this,
mViewPager.setOffscreenPageLimit(5); //as you have 5 fragments
But this will make the activity to initialize all the fragments at the same time when the activity is invoked.
Another method is to use FragmentStatePagerAdapter instead of FragmentPagerAdapter. Refer,
http://developer.android.com/reference/android/support/v4/app/FragmentStatePagerAdapter.html
You are not comparing strings correctly. When comparing two strings you need to use equals() method instead of == operator. So in onCreateView() in AstucesListFragment replace
if (args.getString(ARG_PAGE_CAT) == getString(R.string.astuces_quotidien)) theme = "Q";
else if (args.getString(ARG_PAGE_CAT) == getString(R.string.astuces_resto)) theme = "R";
else if (args.getString(ARG_PAGE_CAT) == getString(R.string.astuces_loisirs)) theme = "L";
else if (args.getString(ARG_PAGE_CAT) == getString(R.string.astuces_transports)) theme = "T";
else theme = "";
with
if (args.getString(ARG_PAGE_CAT).equals(getString(R.string.astuces_quotidien))) theme = "Q";
else if (args.getString(ARG_PAGE_CAT).equals( getString(R.string.astuces_resto))) theme = "R";
else if (args.getString(ARG_PAGE_CAT).equals( getString(R.string.astuces_loisirs))) theme = "L";
else if (args.getString(ARG_PAGE_CAT).equals( getString(R.string.astuces_transports))) theme = "T";
else theme = "";
This may solve your problem as the results of == operators will be inconsistent as both the strings may or may not point to same object.

ActionBar Tabs are not displayed

I'm implementing ActionBar tabs according to official guide.
I have a fragment that is added to activity. In that fragment I'm creating tabs:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
actionBar.setDisplayShowTitleEnabled(false);
Tab tab = actionBar.newTab()
.setText("One")
.setTabListener(new TabListener<DemoFragment>(
this, "1", DemoFragment.class));
actionBar.addTab(tab);
tab = actionBar.newTab()
.setText("Two")
.setTabListener(new TabListener<DemoFragment>(
this, "2", DemoFragment.class));
actionBar.addTab(tab);
}
But these tabs are never displayed. Nor content of DemoFragment. Even though at runtime getActionBar().getTabCount() returns correct count of tabs. And I see that DemoFragment is initialized. All I see is ActionBar.
What am I doing wrong?
I'm not using any support libraries as I'm developing for minSdk=14.
Update
IF YOUR NOT USING ANY SUPPORT LIBRARY THIS SHOULD WORK
otherwise you will have to use the getSupportActionBar() and above mentioned dependencies.
Try something more like this:
// Get the Instance of the Action Bar, set Navigation Mode, remove title
ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
actionBar.setDisplayShowTitleEnabled(false);
// One tab
actionBar.addTab(actionBar.newTab() .setText("One")
.setTabListener(new TabListener<DemoFragment>(
this, "1", DemoFragment.class)));
// Two tab
actionBar.addTab(actionBar.newTab()
.setText("Two")
.setTabListener(new TabListener<DemoFragment>(
this, "2", DemoFragment.class)));
Edit to Post - Working Code that I have used for a demo
Here is code from a demo Application That i wrote using Android sdk 14 Just like you are.
public class MainActivity extends Activity {
// String Titles
static String [] titles = {"Fragment 1", "Fragment 2"};
static String [] fragmentClasses = {Fragment1.class.getName(), Fragment2.class.getName()};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SimpleTabListener.SetUpTabNavigation(this, fragmentClasses, titles);
}
And here is the SimpleTabListener Class
public class SimpleTabListener implements TabListener {
Context m_context;
String m_fragmentClassName ;
Fragment m_fragment = null;
public SimpleTabListener(Context context, String tabFragmentClassName)
{
m_context = context;
m_fragmentClassName = tabFragmentClassName;
}
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft)
{
// TODO Auto-generated method stub
}
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft)
{
if(m_fragment == null)
{
m_fragment = Fragment.instantiate(m_context, m_fragmentClassName);
ft.add(android.R.id.content, m_fragment);
}else
{
ft.attach(m_fragment);
}
}
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft)
{
// TODO Auto-generated method stub
if(m_fragment != null){
// TODO Auto-generated method stub
ft.detach(m_fragment);
}
}
public static void SetUpTabNavigation(Activity activity, String [] classNames, String [] tabTitles){
ActionBar actionBar = activity.getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.TabListener listener;
for(int i = 0; i < tabTitles.length; i++)
{
listener = new SimpleTabListener(activity, classNames[i]);
actionBar.addTab(actionBar.newTab().setText(tabTitles[i]).setTabListener(listener));
}
}
}
Frament1.class
public class Fragment1 extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
return inflater.inflate(R.layout.fragment_1, container, false);
}
}
Fragment 2.class
public class Fragment2 extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
return inflater.inflate(R.layout.fragment2, container, false);
}
}

How to make Title Bar & Tabs custom using Fragments

I am writing a program in which i am using Fragments to work with Tabs, but i need few changes in my UI
I need few changes in my UI, small 5 questions:
Question 1: How to Change Background color of TITLE BAR (I want RED)
Question 2: How to Change Background color of Tab (I want GRAY)
Question 3: How to Change color of Selected Tab (I want RED)
Question 4: How to show Icon above the Text in Tabs
Question 5: How to place share button over Title Bar at Right side
Manifest.xml:
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.example.test.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
MainActivity.java:
public class MainActivity extends FragmentActivity {
ViewPager ViewPager;
TabsAdapter TabsAdapter;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//create a new ViewPager and set to the pager we have created in Ids.xml
ViewPager = new ViewPager(this);
ViewPager.setId(R.id.pager);
setContentView(ViewPager);
//Create a new Action bar and set title to strings.xml
final ActionBar bar = getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setTitle(R.string.app_name);
//Attach the Tabs to the fragment classes and set the tab title.
TabsAdapter = new TabsAdapter(this, ViewPager);
TabsAdapter.addTab(bar.newTab().setText("About"),
FragAbout.class, null);
TabsAdapter.addTab(bar.newTab().setText("Location"),
FragLocation.class, null);
TabsAdapter.addTab(bar.newTab().setText("Menus"),
FragMenus.class, null);
TabsAdapter.addTab(bar.newTab().setText("Reservation"),
FragReservation.class, null);
TabsAdapter.addTab(bar.newTab().setText("Social"),
FragSocial.class, null);
if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
}
// create TabsAdapter to create tabs and behavior
public static class TabsAdapter extends FragmentPagerAdapter
implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
static final class TabInfo {
private final Class<?> clss;
private final Bundle args;
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}
public TabsAdapter(FragmentActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = activity.getActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
notifyDataSetChanged();
}
#Override
public void onPageScrollStateChanged(int state) {
// TODO Auto-generated method stub
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// TODO Auto-generated method stub
}
#Override
public void onPageSelected(int position) {
// TODO Auto-generated method stub
mActionBar.setSelectedNavigationItem(position);
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i=0; i<mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
#Override
public int getCount() {
return mTabs.size();
}
}
FragAbout.java:
public class FragAbout extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.frag_about, container, false);
return myFragmentView;
}
}
I think you already got the answer, that's why you developed this:
https://stackoverflow.com/questions/19000981/actionbarsherlock-swapping-tabs-using-viewpager
Anyways if you still looking for answer, So
I really recommend you to use ActionBarStyleGenerator:
http://jgilfelt.github.io/android-actionbarstylegenerator/
With that tool you can easily theme your graphic elements in your toolbar.
use this for QA:2,3,4
create xml(tab1) in drawble folder
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- When selected, use grey -->
<item android:drawable="#drawable/videos_gray"
android:state_selected="true" />
<!-- When not selected, use white-->
<item android:drawable="#drawable/videos_white" />
and use that in java file
// Create an actionbar
ActionBar actionBar = getActionBar();
// Hide Actionbar Icon
actionBar.setDisplayShowHomeEnabled(false);
// Hide Actionbar Title
actionBar.setDisplayShowTitleEnabled(false);
// Create Actionbar Tabs
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Create first Tab
tab = actionBar.newTab().setTabListener(new FragmentTab1());
// Create your own custom icon
tab.setIcon(R.drawable.tab1);
actionBar.addTab(tab);
// Create Second Tab
tab = actionBar.newTab().setTabListener(new FragmentTab2());
// Set Tab Title
tab.setText("Tab2");
actionBar.addTab(tab);
// Create Third Tab
tab = actionBar.newTab().setTabListener(new FragmentTab3());
// Set Tab Title
tab.setText("Tab3");
actionBar.addTab(tab);
Ans for Q.1 :
You can make a new layout and set its Height at desired "dp" and change the background of that layout to Red color (use resource for that - preferably define a color using color code OR bring in image with Red background). This does not involve using fragments.
Ans for Q.5:
If you use my option as above, use RelatieLayout for Title bar. Then position the button you want at the rightmost side.(Use gravity or manually drag or android:layout_alignParentRight="true" - whichever way you want)
Can't say anything about other questions. Hope this helps
Some other Links:
How do I change the background of an Android tab widget?

ListFragments inside ViewPager

I'm writing my first fragment-based app and running into some heavy problems which i couldn't solve with the API or Stackoverflow.
I am using a viewPager to swipe between two lists. Each list has a header button to create a new list element (similar to the native android alarm app). The button returns currently an error message for debugging.
The problem is:
FragmentList A returns the debug message for FragmentList B
FragmentList B returns no debug message
... // The main class
public class DemoApp extends FragmentActivity implements ActionBar.TabListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Set up the action bar.
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
PageAdapter mPageAdapter = new PageAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mPageAdapter);
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
for (int i = 0; i < mPageAdapter.getCount(); i++) {
actionBar.addTab(actionBar.newTab().setText(mPageAdapter.getPageTitle(i)).setTabListener(this));
}
}
...
My custom PageAdapter will create two list framgent objects:
public class PageAdapter extends FragmentStatePagerAdapter {
private final int NUMBER_PAGES = 2;
public PageAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
if (position == 0) {
return new FoodListFragment();
} else if (position == 1){
return new LocationListFragment();
} else {
throw new IllegalArgumentException("Invalid page position: " + position);
}
}
#Override
public int getCount() {
return NUMBER_PAGES;
}
...
}
FoodListFragment snipped (The other list looks similar except the debug output) :
public class FoodListFragment extends ListFragment implements LoaderCallbacks<Cursor> {
/*
* (non-Javadoc)
*
* #see android.support.v4.app.Fragment#onActivityCreated(android.os.Bundle)
*/
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// add a list header with the button to create a new list item
View v = getActivity().getLayoutInflater().inflate(R.layout.list_header, null);
getListView().addHeaderView(v);
...
setListAdapter(getSomeAdapter());
// get the list header button
ImageButton createItem = (ImageButton) getActivity().findViewById(R.id.create_new_entry);
createItem.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.e(LOG_TAG, "onclick FoodListFragment");
}
});
}
main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/wrapper"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<android.support.v4.view.ViewPager
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/pager"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context=".DemoApp" />
</LinearLayout>
I've found the bug. In each list i was calling the same header view and same header button. The onClick method could not be clearly assigned

(ActionBar) Tabs + Pager + detail Fragments inside ViewPager container

For ActionBarSherlock I would like to have (Action Bar) Tabs + Pager. I use Fragments inside that pager container. I already got the examples of http://actionbarsherlock.com/ working, but I can't manage to get a details fragment inside that pager container when I would click on let's say a listitem in the first fragment.
Is it impossible to have something like this:
Activity with Tabs and pager container
Fragment A inside pager container under Tab1
Click on something in Fragment A and show Fragment B in same pager container under Tab1.
Fragment A is then not visible, only Fragment B is visible, but also all the Tabs.
At the moment I think only a new activity (which would hold Fragment B inside it) can be started after clicking something in Fragment A.
Here is my solution for the (Tabs + Fragment + ViewPager) it is works for me as i wanted,
hope that works for you as well
here is the xml file
<LinearLayout
android:id="#+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="5" />
<FrameLayout
android:id="#+id/fragment_details"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="4.3" />
</LinearLayout>
here is the code for MainActivity.java I'll post relevant code only so you'll have to manage it
public class MainActivity extends FragmentActivity implements
DialogInterface.OnDismissListener, TabDataResponder {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
artistTab = getSupportActionBar().newTab().setText(
R.string.tab_name_artist);
albumTab = getSupportActionBar().newTab().setText(
R.string.tab_name_album);
songTab = getSupportActionBar().newTab().setText(
R.string.tab_name_songs);
map = new HashMap<String, Integer>();
mViewPager = (ViewPager) findViewById(R.id.pager);
FrameLayout deatil = (FrameLayout) findViewById(R.id.fragment_details);
mDualPane = (deatil != null) && (deatil.getVisibility() == View.VISIBLE);
mTabsAdapter = new TabsAdapter(this, getSupportActionBar(), mViewPager);
if (savedInstanceState != null) {
flag = true;
index = savedInstanceState.getInt("index");
}
setUpTabView();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("index", getSupportActionBar()
.getSelectedNavigationIndex());
}
private void setUpTabView() {
mTabsAdapter.addTab(artistTab, ArtistFragment.class, null);
mTabsAdapter.addTab(albumTab, AlbumFragment.class, null);
mTabsAdapter.addTab(songTab, SongFragment.class, null);
getSupportActionBar().setSelectedNavigationItem(index);
}
public static class TabsAdapter extends FragmentPagerAdapter implements
ViewPager.OnPageChangeListener, ActionBar.TabListener {
private FragmentActivity mContext;
private ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<String> mTabs = new ArrayList<String>();
private TabDataResponder responder;
public TabsAdapter(FragmentActivity activity, ActionBar actionBar,
ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = actionBar;
mViewPager = pager;
// TabDataResponder is an interface which is implemented in MainActivity
// You can find implementation # the last
responder = (TabDataResponder) activity;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
//I have used map to save state of the fragment
map.put(SongFragment.TYPE_FRAGMENT.trim(), 0);
map.put(AlbumFragment.TYPE_FRAGMENT.trim(), 0);
map.put(ArtistFragment.TYPE_FRAGMENT.trim(), 0);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
mTabs.add(clss.getName());
// mArgs.add(args);
mActionBar.addTab(tab.setTabListener(this));
notifyDataSetChanged();
}
#Override
public int getCount() {
return mTabs.size();
}
#Override
public Fragment getItem(int position) {
return Fragment
.instantiate(mContext, mTabs.get(position), /*
* mArgs.get(
* position)
*/null);
}
#Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
Log.i(TAG, "PageSelected....");
mActionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrollStateChanged(int state) {
Log.i(TAG, "ScrollSateChanged....");
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
mViewPager.setCurrentItem(tab.getPosition());
String a = null;
if (mDualPane) {
a = mTabs.get(tab.getPosition());
responder.loadData(a, map.get(a));
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
Log.i(TAG, "Tab is released now....");
}
}
#Override
public void onDismiss(DialogInterface dialog) {
setUpTabView();
}
//This interface must be call from fragment class
//# the time of event you want to show detail
// pass the class name in the type argument using class.getName() method
#Override
public void loadData(String type, int index) {
DetailFragment viewer = (DetailFragment) getSupportFragmentManager()
.findFragmentById(R.id.fragment_details);
if (mDualPane) {
if (viewer == null || viewer.getShownIndex() != index
|| viewer.getTypeFragment() != type) {
DetailFragment df = DetailFragment.newInstance(index, type);
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_details, df)
.setTransition(
FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.commit();
map.put(type.trim(), index);
}
} else {
Intent intent = new Intent();
intent.setClass(MainActivity.this, DetailActivity.class);
intent.putExtra("index", index);
intent.putExtra("type", type);
startActivity(intent);
}
}
}
and here is how i deal with detail fragment not very efficient but kind of working
public class DetailFragment extends Fragment{
public static DetailFragment newInstance(int index, String TYPE_FRAGMENT) {
DetailFragment f = new DetailFragment();
// Supply index input as an argument.
Bundle args = new Bundle();
args.putInt("index", index);
args.putString("type", TYPE_FRAGMENT);
f.setArguments(args);
return f;
}
public int getShownIndex() {
return getArguments().getInt("index", 0);
}
public String getTypeFragment(){
String a = getArguments().getString("type");
return a;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//template is blank layout
View view = inflater.inflate(R.layout.template, container, false);
if(getTypeFragment().equals(ArtistFragment.TYPE_FRAGMENT)){
view = null;
view = inflater.inflate(R.layout.artist_details, container, false);
//....
}
else if(getTypeFragment().equals(AlbumFragment.TYPE_FRAGMENT)){
//do's for album fragment
}
else if(getTypeFragment().equals(SongFragment.TYPE_FRAGMENT)){
//do's for song fragment
}
return view;
}
}
do not save the state of tab in their individual fragment it will conflict, we are already doing it here
EDIT:
Cheered too soon. Now the details_container is not a viewpager and I cannot use it to 'swipe tabs'.
Found it! Just had to define two FrameLayouts, with in the first one the ViewPager and in the second the details fragments can be 'loaded'. This is done by adding fragments dynamically and replace them.
First the two FrameLayouts:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fadingEdge="none" >
<FrameLayout
android:id="#+id/main_container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</FrameLayout>
<FrameLayout
android:id="#+id/details_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
Then replace a fragment dynamically:
// Create new fragment and transaction
Fragment detailsFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment container view with this fragment
// and add the transaction to the back stack
transaction.replace(R.id.details_container, detailsFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
Very simple and I don't understand why it took me hours to figure this out..
I still did not find a possibility to have a Pager container where fragments should be loaded in and also keep the (ActionBar) Tabs. I have however found a really dirty solution to acomplish this, with starting intens (Main Activity with the Tabs) and finishing the previous ones when the backbutton doesn't need it anymore.
I adapted the code from ABS: Support Demos - Tabs and Pager. But again it's really dirty:
LoaderCursorSupport.CursorLoaderListFragment under Tab2
#Override public void onListItemClick(ListView l, View v, int position, long id) {
Intent intent = new Intent();
intent.setClass(getActivity(), ActionBarTabsPager.class);
intent.putExtra("index", position);
intent.putExtra("fragment", "details");
intent.putExtra("tab", 1);
ActionBarTabsPager.mPreviousActivity = getActivity();
startActivity(intent);
ActionBarTabsPager (Main Activity with Tabs)
public class ActionBarTabsPager extends FragmentActivity {
ViewPager mViewPager;
TabsAdapter mTabsAdapter;
static Activity mPreviousActivity;
static Activity mActivity;
static int mTabPosition = -1;
static Boolean mTabRefreshed = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.actionbar_tabs_pager);
getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.Tab tab1 = getSupportActionBar().newTab().setText("Tab 1");
ActionBar.Tab tab2 = getSupportActionBar().newTab().setText("Tab 2");
ActionBar.Tab tab3 = getSupportActionBar().newTab().setText("Tab 3");
ActionBar.Tab tab4 = getSupportActionBar().newTab().setText("Tab 4");
String fragment = "";
try {
Bundle bundle = this.getIntent().getExtras();
fragment = bundle.getString("fragment");
mTabPosition = bundle.getInt("tab");
} catch (Exception ex) {
}
mViewPager = (ViewPager) findViewById(R.id.pager);
mTabsAdapter = new TabsAdapter(this, getSupportActionBar(), mViewPager);
mTabsAdapter.addTab(tab1, FragmentStackSupport.CountingFragment.class);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ECLAIR) {
mTabsAdapter.addTab(tab2, FragmentStackSupport.CountingFragment.class);
mTabsAdapter.addTab(tab3, FragmentStackSupport.CountingFragment.class);
mTabsAdapter.addTab(tab4, FragmentStackSupport.CountingFragment.class);
} else {
if (!fragment.contains("details")) {
mTabsAdapter.addTab(tab2, LoaderCursorSupport.CursorLoaderListFragment.class);
} else {
mTabsAdapter.addTab(tab2, ExampleFragment.class);
}
mTabsAdapter.addTab(tab3, LoaderCustomSupport.AppListFragment.class);
mTabsAdapter.addTab(tab4, LoaderThrottleSupport.ThrottledLoaderListFragment.class);
}
if (savedInstanceState != null) {
getSupportActionBar().setSelectedNavigationItem(savedInstanceState.getInt("index"));
}
if (mTabPosition > -1) {
mTabsAdapter.setPrimaryItem(mTabPosition);
mActivity = this;
}
}
Inside this Class there's a TabsAdapter
public static class TabsAdapter extends FragmentPagerAdapter implements ViewPager.OnPageChangeListener, ActionBar.TabListener {
private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<String> mTabs = new ArrayList<String>();
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if (mTabPosition > -1 && mTabRefreshed) {
int tabPosition = tab.getPosition();
if (mTabPosition != tabPosition) {
if (mPreviousActivity != null) {
mPreviousActivity.finish();
mTabRefreshed = false;
mPreviousActivity = null;
mTabPosition = -1;
Intent intent = new Intent();
intent.setClass(mContext, ActionBarTabsPager.class);
intent.putExtra("fragment", "home");
intent.putExtra("tab", tabPosition);
mActivity.startActivity(intent);
mActivity.finish();
}
}
}
mViewPager.setCurrentItem(tab.getPosition());
}
Can this be done simpler? Or should I just give up on having Tabs together with fragment history? This was done before Android 3.0 with ActivityGroups and Activities, but it seems this can't be done with fragments.
I found the other good example of the same implementation in hear... https://github.com/UweTrottmann/SeriesGuide
In this example under package com.battlelancer.seriesguide.ui
you can find UpcomingRecentActivity.java, and UpcomingFragment.java
and layout upcoming_multipan.xml
this example works for me...
I got one problem while adding different content for detail-fragment the different tabs, it gives me class-cast-exception
so i implemented a common detalFragment class and created separate layout in onCreateView method
but the only one problem i found is layout is not changing on tab switched, may be need to do it by implementing some listener
I'll tell you when i found the answer.

Categories

Resources