Move Tabs Using Fragment- Nested Tabs - c#

I am new in android, especially in Xamarin Android C#. I have bottom navigation tabs and fragments. They are fragment_picture (tab_picture), fragment home (tab_home), fragment notifications (tab_notifications), fragment_profile (tab_profile). Inside fragment_picture (tab_picture), I have 2 tabs. They are fragment_camera(tab_camera), and fragment_gallery(tab_gallery). I want to move the tabs of fragment_picture such as when I click the tab_camera, it shows the XML of the tab_camera and when I click the tab_gallery, It shows the XML of the tab_gallery.
I don't use viewpager. I am just using fragments. The tab won't change the position to its XML. I've searched a lot in Google But, I still confused. Please help me
using System;
using Android.OS;
using Android.Support.Design.Widget;
using Android.Views;
using Android.Support.V4.App;
using Android.Widget;
namespace MyPhotographicMemory.Droid.Fragments
{
public class Fragment_Picture : Fragment
{
TabLayout tabLayout;
private TabLayout.Tab tabGallery, tabCamera;
Fragment fragment = null;
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
}
public static Fragment_Picture NewInstance()
{
var frag2 = new Fragment_Picture { Arguments = new Bundle() };
return frag2;
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var ignored = base.OnCreateView(inflater, container, savedInstanceState);
var v = inflater.Inflate(Resource.Layout.FragmentPicture, null);
tabLayout = v.FindViewById<TabLayout>(Resource.Id.pictureTabLayout);
tabLayout.TabSelected += (object sender, TabLayout.TabSelectedEventArgs e) =>
{
switch (e.Tab.Position)
{
case Resource.Layout.FragmentCamera: //Resource.Id.tabItem1
fragment = new Fragment_Camera();
TabLayout.Tab tab = tabLayout.GetTabAt(0);
tab.Select();
break;
case Resource.Layout.FragmentGallery: //Resource.Id.tabItem1
fragment = new Fragment_Gallery();
TabLayout.Tab tab1 = tabLayout.GetTabAt(1);
tab1.Select();
break;
}
};
return v;
}
}
}

Do you want to achieve the result like this GIF?
If so, you should achieve the nested tabs with fragment.
Here is my code when in my first fragment.
public class Fragment1 : Fragment
{
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your fragment here
}
public static Fragment1 NewInstance()
{
var frag1 = new Fragment1 { Arguments = new Bundle() };
return frag1;
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var ignored = base.OnCreateView(inflater, container, savedInstanceState);
var view = inflater.Inflate(Resource.Layout.fragment1, null);
BottomNavigationView bottomNavigationView= view.FindViewById<BottomNavigationView>(Resource.Id.mynested_bottom_navi);
bottomNavigationView.NavigationItemSelected += BottomNavigationView_NavigationItemSelected;
LoadFragment(Resource.Id.tab_camera);
return view;
}
private void BottomNavigationView_NavigationItemSelected(object sender, BottomNavigationView.NavigationItemSelectedEventArgs e)
{
LoadFragment(e.Item.ItemId);
}
//switch fragment by tab id.
void LoadFragment(int id)
{
Fragment fragment = null;
switch (id)
{
case Resource.Id.tab_gallery:
fragment = Fragment_Gallery.NewInstance();
break;
case Resource.Id.tab_camera:
fragment = Fragment_Camera.NewInstance();
break;
}
if (fragment == null)
return;
FragmentManager.BeginTransaction()
.Replace(Resource.Id.mynest_content_frame, fragment)
.Commit();
}
}
Here is my demo, you can refer to it.
https://drive.google.com/file/d/1XZE6YopdsvDHY8-DwXBxRpHz3oFlJbOR/view

Related

Send data from one fragment to another fragment in xamarin.android

I am trying to do an application with Xamarin.android. It is "ToDoList" and I have two tabs, one of them is to create and edit the chores(it is called "undone"). The other one is for the chores that are marked as done(it is called done). I have used Fragments for the tabs and what I am trying to accomplish is when I mark one task as done I want to delete it from the list in the "undone" tab and add one to the list in "done" tab.
MainActivity.cs
public class MainActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
this.ActionBar.NavigationMode = ActionBarNavigationMode.Tabs;
var tab1 = ActionBar.NewTab();
tab1.SetText("Undone");
var tabFirst = new UndoneListFragment();
tab1.TabSelected += (sender, e) =>
{
var fragment = this.FragmentManager.FindFragmentById(Resource.Id.tabsContainer);
if (fragment != null)
e.FragmentTransaction.Remove(fragment);
e.FragmentTransaction.Add(Resource.Id.tabsContainer, tabFirst);
};
tab1.TabUnselected += (sender, e) =>
{
e.FragmentTransaction.Remove(tabFirst);
};
var tab2 = ActionBar.NewTab();
tab2.SetText("Done");
var tabSecond = new DoneListFragment();
tab2.TabSelected += (sender, e) =>
{
var fragment = this.FragmentManager.FindFragmentById(Resource.Id.tabsContainer);
if (fragment != null)
e.FragmentTransaction.Remove(fragment);
e.FragmentTransaction.Add(Resource.Id.tabsContainer, tabSecond);
};
tab2.TabUnselected += (sender, e) =>
{
e.FragmentTransaction.Remove(tabSecond);
};
ActionBar.AddTab(tab1);
ActionBar.AddTab(tab2);
}
}
UndoneListFragment.cs
public class UndoneListFragment : Fragment
{
List<Task> tasks = new List<Task>();
ListView lView;
TasksViewAdapter adapter;
View view;
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Use this to return your custom view for this Fragment
// return inflater.Inflate(Resource.Layout.YourFragment, container, false);
base.OnCreateView(inflater, container, savedInstanceState);
view = inflater.Inflate(Resource.Layout.undoneListView, container, false);
Button addBtn = view.FindViewById<Button>(Resource.Id.AddBtn);
lView = view.FindViewById<ListView>(Resource.Id.TasksViewList);
adapter = new TasksViewAdapter(view.Context, tasks);
lView.Adapter = adapter;
lView.ItemClick += Edit;
addBtn.Click += AddTask;
return view;
}
}
public override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
switch (requestCode)
{
case 10:
if (resultCode == Result.Ok) //Edit an already existing task
{
var replacedTaskName = data.GetStringExtra("new_name" ?? "Name not found");
var position = data.GetIntExtra("listPos", 0);
bool done = data.GetBooleanExtra("done", false);
Task t = new Task(replacedTaskName);
if (done == true)
{
t.TaskStatus = Status.Done;
//here I want to implement the code to somehow
//send the replacesTaskName to the second fragment
//Your suggestion is here
DoneListFragment frag = new DoneListFragment();
Bundle b = new Bundle();
b.PutString("MyKey",replacedTaskName);
frag.Arguments = b;
}
tasks[position] = t;
adapter.NotifyDataSetChanged();
string newName = tasks[position].TaskName;
break;
}
}
}
DoneListFragment.cs
public class DoneListFragment : Fragment
{
List<Task> doneTasks = new List<Task>();
ListView lView;
TasksViewAdapter adapter;
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView(inflater, container, savedInstanceState);
var view = inflater.Inflate(Resource.Layout.doneListView, container, false);
Button deleteBtn = view.FindViewById<Button>(Resource.Id.DeleteAllBtn);
lView = view.FindViewById<ListView>(Resource.Id.doneList);
adapter = new TasksViewAdapter(view.Context, doneTasks);
lView.Adapter = adapter;
if(Arguments != null)
{
string value= Arguments.GetString("MyKey");
}
//click to delete done tasks
deleteBtn.Click += DeleteAll;
return view;
}
}
For Sending data from one fragment another one simple step is creating constructor while replacing
the fragment or calling fragment.
For Example:
Suppose I have two fragments ,
ActionFragment
ActionDetailsFragment
Now I want to send data from “ActionFragment” to “ActionDetailsFragment”:
In ActionFragment :
fragmentManager = getChildFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frameLayoutActionDetails, new ActionDetailsFragment(Data x, Data y)).commitAllowingStateLoss( );
Now below code will be in “ActionDetailsFragment”
public class ActionDetailsFragment extends AppFragment {
Data x;
Data y;
public ActionDetailsFragment(Data x, Data y) {
super();
this.x = x;
this.y = y;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
—————————————
////———Here is your code———————
—————————————————
}
Now you can use “Data x, Data y” in ActionDetailsFragment…
Thats it…
Note: Data x and Data y both are imaginary variables..
Activity’s cannot use in TabLayout or ViewPager you must have to use Fragments .
You can use “Bundle” instead,
Fragment fragment = new Fragment();
Bundle bundle = new Bundle();
bundle.putInt(key, value);
fragment.setArguments(bundle);
Then in your Fragment, retrieve the data (e.g. in onCreate() method) with:
Bundle bundle = this.getArguments();
if (bundle != null) {
int myInt = bundle.getInt(key, defaultValue);
}
Well if you are looking for Fragment to Fragment data transfer the smart way of doing it would be using fragment arguments, Something like this:
When you initialize the fragment object in your case:
var frag= new DoneListFragment();
Bundle bundle= new Bundle();
bundle.PutString("YourKey", "YourValue");
frag.Arguments=bundle;
Then to retrieve this data you do something like this in DoneListFragment in the OnCreateView method:
if(Arguments!=null)
{
String value = Arguments.GetString("YourKey");
}

Adding activities to inflators

I am very new to Xamarin so i don't have the clearest idea on how inflators work.
How can i add functionality to a page that uses inflators to scroll between tabs? I.E. Where do i put the code for a button click event, when the button can be found in
var root = inflater.Inflate(Resource.Layout.Fragment, container, false); ?
This is my fragment page:
namespace OfficialApp{
public class ContentFragment: Fragment{
private int position;
public static ContentFragment NewInstance(int position)
{
var f = new ContentFragment();
var b = new Bundle();
b.PutInt("position", position);
f.Arguments = b;
return f;
}
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
position = Arguments.GetInt("position");
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var root = inflater.Inflate(Resource.Layout.Fragment, container, false);
var editFile = inflater.Inflate(Resource.Layout.editFile, container, false);
if (position == 0)
{
return root;
}
else if (position == 1)
{
return editFile;
}
else
ViewCompat.SetElevation(root, 50);
return root ;
}
}
}
Sorry if this is a vague or silly question but i honestly have not been able to find the answer anywhere.
What i'm not sure about is how to give each fragment its own activity so that for example pushing a button runs an on click event.
To find a control in the view which is inflated by var root = inflater.Inflate(Resource.Layout.Fragment, container, false);, you can code for example like this:
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var view = inflater.Inflate(Resource.Layout.fragment1, container, false);
var btn = view.FindViewById<Button>(Resource.Id.btn);
return view;
}

OnCreateView Called twice

I'm trying to create an activity with two tabs, one holding FragmentA and one holding FragmentB. Here is how I add the fragments to the Activity:
[Activity(Label = "My App")]
public class MyActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.ConnectionMenu);
ActionBar.NavigationMode = ActionBarNavigationMode.Tabs;
AddTab("A", new FragmentA());
AddTab("B", new FragmentB());
}
private void AddTab(string tabText, Fragment fragment)
{
var tab = ActionBar.NewTab();
tab.SetText(tabText);
tab.TabSelected += (sender, e) =>
{
e.FragmentTransaction.Replace(
Resource.Id.fragmentContainer,
fragment);
};
ActionBar.AddTab(tab);
}
}
When I rotate the orientation I want to keep fields filled out in the fragments the same. I save my data in OnSaveInstanceState and restore the data in OnActivityCreated. However, I'm noticing that the OnCreateView and OnActivityCreated methods are being called twice per rotate. The first time containing my filled in Bundle and the second time with bundle being null.
I assume that my error is in the MyActivity class but if you need more information let me know!
Given you create the fragment in your Activity.OnCreate(), you will always have 2 calls due to creating new ones in the method, and maintaining the old ones in the base.OnCreate(). What you should probably do is instead of always creating these fragments, you can search via a tag or ID for an existing fragment and use those in the Tabs instead.
i.e.
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.ConnectionMenu);
ActionBar.NavigationMode = ActionBarNavigationMode.Tabs;
if(savedInstanceState == null)
{
AddTab("A", new FragmentA());
AddTab("B", new FragmentB());
}
else
{
Fragment a = (FragmentA)SupportFragmentManager.FindFragmentByTag("my_tag_a");
Fragment b = (FragmentB)SupportFragmentManager.FindFragmentByTag("my_tag_b");
AddTab("A", a);
AddTab("B", b);
}
}
I ended up solving the issue. as #JonDouglas said you need to make sure the tab wasn't already loaded before creating a new fragment. To do this the fragment can be loaded from the FragmentManager class using a tag. During the TabSelected event if the fragment was not previously create, a new fragment is created and added to the event FragmentTransaction using the tag. During the TabUnselected event, if the fragment was created then it is detached.
I also added in a Bundle value to hold onto the last active tab.
Here is the code I used to solve the issue.
[Activity(Label = "My App")]
public class MyActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.ConnectionMenu);
ActionBar.NavigationMode = ActionBarNavigationMode.Tabs;
AddTab("A", "a_fragment", () => new FragmentA());
AddTab("B", "b_fragment", () => new FragmentB());
if (savedInstanceState != null)
{
var selectedTab = savedInstanceState.GetInt(
"ActionBar.SelectedNavigationIndex", 0);
ActionBar.SetSelectedNavigationItem(selectedTab);
}
}
protected override void OnSaveInstanceState(Bundle savedInstanceState)
{
base.OnSaveInstanceState(savedInstanceState);
savedInstanceState.PutInt(
"ActionBar.SelectedNavigationIndex",
ActionBar.SelectedNavigationIndex);
}
private void AddTab<TFragment>(
string tabText,
string tag,
Func<TFragment> ctor) where TFragment : Fragment
{
var tab = ActionBar.NewTab();
tab.SetText(tabText);
tab.SetTag(tag);
var fragment = FragmentManager.FindFragmentByTag<TFragment>(tag);
tab.TabSelected += (sender, e) =>
{
if (fragment == null)
{
fragment = ctor.Invoke();
e.FragmentTransaction.Add(
Resource.Id.fragmentContainer,
fragment,
tag);
}
else
{
e.FragmentTransaction.Attach(fragment);
}
};
tab.TabUnselected += (sender, e) =>
{
if (fragment != null)
{
e.FragmentTransaction.Detach(fragment);
}
};
ActionBar.AddTab(tab);
}
}

How to pass data between tabs on Xamarin Android?

I have two tabs in viewpager. So in fragment1 I input a text and when in tab2 is selected and then fragment2 will get data from that text from fragment1.
ex: when I open tab1 -> I input a text is "abcd" -> I open tab2 -> I want to get a text is "abcd" from tab1(fragment1).
public class Fragment1 : Android.Support.V4.App.Fragment
{
Fragment2 frag2 = new Fragment2();
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your fragment here
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Use this to return your custom view for this Fragment
// return inflater.Inflate(Resource.Layout.YourFragment, container, false);
Singleton singleton = Singleton.GetInstance();;
singleton.SetSource("abcd");
}
}public class Singleton
{
private static Singleton singleton;
string a = null;
private Singleton()
{
}
public static Singleton GetInstance()
{
if (singleton == null)
singleton = new Singleton();
return singleton;
}
public void SetSource(string text)
{
this.a = text;
}
public string showMessage()
{
return a;
}
}
public class Fragment2 : Android.Support.V4.App.Fragment
{
public List<string> data = new List<string>();
public void add(string t)
{
data.Add(t);
}
TextView txt;
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your fragment here
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Use this to return your custom view for this Fragment
// return inflater.Inflate(Resource.Layout.YourFragment, container, false);
//return base.OnCreateView(inflater, container, savedInstanceState);
return inflater.Inflate(Resource.Layout.view2, container, false);
txt = View.FindViewById<TextView>(Resource.Id.txtgetdata);
if (data != null)
{
txt.Text = data[0];
}
else
Toast.MakeText(Application.Context, "no", ToastLength.Long).Show();
}
}
I have tried it but don't having the result.
After a few hours of research/test & debugging and solved, try this out.
In your Activity
add public string tabFragment { get; set; }
In your source fragment
ie on click or that navigate to other fragment
string tab = ((ActivityUser)Activity).tabFragmentAddUser;
FragmentAddUser fragment = (FragmentAddUser);
Activity.SupportFragmentManager.FindFragmentByTag(tab);
fragment.setValText("Hello");
viewPager.SetCurrentItem(1, true);
In your destination fragment (ie which elements will be modified)
add a method like this
public void setValText(string str) { txtUsrFirstName.Text = str; }
==================================================================
Fragment fragment = new Fragment();
Bundle bundle = new Bundle();
bundle.putInt(key, value);
fragment.SetArguments(bundle);
in on create of the other fragment
Bundle bundle = this.GetArguments();
int myInt = bundle.GetInt(key, defaultValue);
optionaly two fragments should never communicate directly and should communicate through activity
From Developers website:
Often you will want one Fragment to communicate with another, for
example to change the content based on a user event. All
Fragment-to-Fragment communication is done through the associated
Activity. Two Fragments should never communicate directly.
refer this and this

Cannot access a nonstatic member of outer type... via nested type

Why do I get this error?
Error CS0038: Cannot access a nonstatic member of outer type
JsonFeedParserTabs.MainActivity' via nested type
JsonFeedParserTabs.MainActivity.SampleTabFragment' (CS0038)
(JsonFeedParserTabs)
I'm trying to put a ListView with json data inside a tab.
This is my code:
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using System.Threading.Tasks;
using System.Net.Http;
using Newtonsoft.Json;
using System.Linq;
namespace JsonFeedParserTabs
{
[Activity (Label = "Feed Reader", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Activity
{
ListView listView;
// ProgressBar progressBar;
RootObject result;
string url = "http://javatechig.com/api/get_category_posts/?dev=1&slug=android";
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Set our view from the "main" layout resource.
SetContentView (Resource.Layout.Main);
this.ActionBar.NavigationMode = ActionBarNavigationMode.Tabs;
AddTab (" Tab 1", new SampleTabFragment ());
// AddTab (" Tab 2", new SampleTabFragment2 ());
if (bundle != null)
this.ActionBar.SelectTab(this.ActionBar.GetTabAt(bundle.GetInt("tab")));
}
protected override void OnSaveInstanceState(Bundle outState)
{
outState.PutInt("tab", this.ActionBar.SelectedNavigationIndex);
base.OnSaveInstanceState(outState);
}
void AddTab (string tabText, Fragment view)
{
var tab = this.ActionBar.NewTab ();
tab.SetText (tabText);
// Must set event handler before adding tab.
tab.TabSelected += delegate(object sender, ActionBar.TabEventArgs e) {
var fragment = this.FragmentManager.FindFragmentById(Resource.Id.fragmentContainer);
if (fragment != null)
e.FragmentTransaction.Remove(fragment);
e.FragmentTransaction.Add (Resource.Id.fragmentContainer, view);
};
tab.TabUnselected += delegate(object sender, ActionBar.TabEventArgs e) {
e.FragmentTransaction.Remove(view);
};
this.ActionBar.AddTab (tab);
}
class SampleTabFragment : Fragment
{
public override View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView (inflater, container, savedInstanceState);
var view = inflater.Inflate (Resource.Layout.Tab, container, false);
// Initializing listView.
listView = view.FindViewById<ListView> (Resource.Id.listView); // <-- Error!
listView.ItemClick += OnListItemClick; // <-- Error!
// progressBar = view.FindViewById<ProgressBar> (Resource.Id.progressBar);
//
// // Showing loading progressBar.
// progressBar.Visibility = ViewStates.Visible;
// Download and display data in url.
downloadJsonFeedAsync (url); // <-- Error!
return view;
}
}
// class SampleTabFragment2 : Fragment
// {
// public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
// {
// base.OnCreateView(inflater, container, savedInstanceState);
//
// var view = inflater.Inflate(Resource.Layout.Tab, container, false);
// var sampleTextView = view.FindViewById<TextView>(Resource.Id.sampleTextView);
//
// sampleTextView.Text = "Sample fragment text 2.";
//
// return view;
// }
// }
public async void downloadJsonFeedAsync(String url)
{
var httpClient = new HttpClient();
Task<string> contentsTask = httpClient.GetStringAsync(url);
// Await! control returns to the caller and the task continues to run on another thread.
string content = await contentsTask;
Console.Out.WriteLine("Response Body: \r\n {0}", content);
// Convert string to JSON object.
result = Newtonsoft.Json.JsonConvert.DeserializeObject<RootObject> (content);
// Update listview.
RunOnUiThread (() => {
listView.Adapter = new CustomListAdapter(this, result.posts);
// progressBar.Visibility = ViewStates.Gone;
});
}
void OnListItemClick(object sender, AdapterView.ItemClickEventArgs e)
{
Post item = result.posts.ElementAt (e.Position);
// Passing object form one activity to other.
Intent i = new Intent(Application.Context, typeof(FeedDetailsActivity));
i.PutExtra("item", JsonConvert.SerializeObject(item));
StartActivity(i);
}
}
}
I'm stuck and need help, any ideas what I have done wrong and what to do? Thank you!
Update
Alright it works now but i think there might be a better way to do this.
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using System.Threading.Tasks;
using System.Net.Http;
using Newtonsoft.Json;
using System.Linq;
namespace JsonFeedParserTabs
{
[Activity (Label = "Feed Reader", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Activity
{
ListView listView;
// ProgressBar progressBar;
RootObject result;
string url = "http://javatechig.com/api/get_category_posts/?dev=1&slug=android";
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Set our view from the "main" layout resource.
SetContentView (Resource.Layout.Main);
this.ActionBar.NavigationMode = ActionBarNavigationMode.Tabs;
AddTab (" Tab 1", new SampleTabFragment (this));
// AddTab (" Tab 2", new SampleTabFragment2 ());
if (bundle != null)
this.ActionBar.SelectTab(this.ActionBar.GetTabAt(bundle.GetInt("tab")));
}
protected override void OnSaveInstanceState(Bundle outState)
{
outState.PutInt("tab", this.ActionBar.SelectedNavigationIndex);
base.OnSaveInstanceState(outState);
}
void AddTab (string tabText, Fragment view)
{
var tab = this.ActionBar.NewTab ();
tab.SetText (tabText);
// Must set event handler before adding tab.
tab.TabSelected += delegate(object sender, ActionBar.TabEventArgs e) {
var fragment = this.FragmentManager.FindFragmentById(Resource.Id.fragmentContainer);
if (fragment != null)
e.FragmentTransaction.Remove(fragment);
e.FragmentTransaction.Add (Resource.Id.fragmentContainer, view);
};
tab.TabUnselected += delegate(object sender, ActionBar.TabEventArgs e) {
e.FragmentTransaction.Remove(view);
};
this.ActionBar.AddTab (tab);
}
class SampleTabFragment : Fragment
{
private MainActivity context;
public SampleTabFragment(MainActivity _context) : base()
{
this.context = _context;
}
public override View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView (inflater, container, savedInstanceState);
var view = inflater.Inflate (Resource.Layout.Tab, container, false);
// Initializing listView.
context.listView = view.FindViewById<ListView> (Resource.Id.listView);
context.listView.ItemClick += context.OnListItemClick;
// progressBar = view.FindViewById<ProgressBar> (Resource.Id.progressBar);
//
// // Showing loading progressBar.
// progressBar.Visibility = ViewStates.Visible;
// Download and display data in url.
context.downloadJsonFeedAsync (context.url);
return view;
}
}
// class SampleTabFragment2 : Fragment
// {
// public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
// {
// base.OnCreateView(inflater, container, savedInstanceState);
//
// var view = inflater.Inflate(Resource.Layout.Tab, container, false);
// var sampleTextView = view.FindViewById<TextView>(Resource.Id.sampleTextView);
//
// sampleTextView.Text = "Sample fragment text 2.";
//
// return view;
// }
// }
public async void downloadJsonFeedAsync(String url)
{
var httpClient = new HttpClient();
Task<string> contentsTask = httpClient.GetStringAsync(url);
// Await! control returns to the caller and the task continues to run on another thread.
string content = await contentsTask;
Console.Out.WriteLine("Response Body: \r\n {0}", content);
// Convert string to JSON object.
result = Newtonsoft.Json.JsonConvert.DeserializeObject<RootObject> (content);
// Update listview.
RunOnUiThread (() => {
listView.Adapter = new CustomListAdapter(this, result.posts);
// progressBar.Visibility = ViewStates.Gone;
});
}
void OnListItemClick(object sender, AdapterView.ItemClickEventArgs e)
{
Post item = result.posts.ElementAt (e.Position);
// Passing object form one activity to other.
Intent i = new Intent(Application.Context, typeof(FeedDetailsActivity));
i.PutExtra("item", JsonConvert.SerializeObject(item));
StartActivity(i);
}
}
}
It's telling you exactly what it can't do. The MainActivity members are not accessible from the fragment types declared within the MainActivity type. So when you try to call downloadJsonFeedAsync (url); it fails because it's not a static (class) method. The fragments (although declared within the type), do not exist within an instance of the MainActivity type.
Unless there's some compelling reason for them to remain within the MainActivity type, I'd move them out. They should also then have a reference to the MainActivity type so that you can call downloadJsonFeedAsync(string) on it.
On an unrelated note (and I appreciate this is very much uninvited commentary :) ), you may want to consider using a MVVM pattern. It looks like you're intermixing presentation, application control, and business data. If this app grows beyond the one or two pages, you will find much peace in segregating responsibilities.

Categories

Resources