I use the Sliding Menu library in my app.
The sliding menu is a fragment.
The blue part is the sliding menu when opened.
The red part is static, it doesn't change, it's the main activity btw.
The yellow part is the fragment that change when the user clicks on an item of the sliding menu.
Here's what's wrong when I implement it :
In the sliding menu fragment, I listen for the OnItemClick event, and I create a new fragment depending on the position of the item clicked.
After that, I replace the yellow frame id, with the fragment.
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
Fragment frag = null;
switch (arg2) {
case 1:
frag = new ExpFragment();
break;
case 2:
frag = new FormFragment();
break;
case 3:
frag = new CompFragment();
break;
default:
frag = new ContactFragment();
break;
}
transaction.replace(R.id.fragment, frag);
transaction.commit();
}
Looks good huh? Well, no. Here's the logcat exception I got.
06-13 09:28:29.739: E/AndroidRuntime(15422): java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
So, if anyone has a clue, or can tell me what to look at, that'd be awesome!
TL;DR : Have 2 fragments (bleu and yellow), the blue has to change the yellow. Gives me an exception.
Thanks,
EDIT: The layouts file:
The activity_main : https://gist.github.com/dommerq/5771887
One fragment item example : https://gist.github.com/dommerq/5771892
The answer was in my fragment java code.
I had :
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(com.quentindommerc.flatme.R.layout.f_contact, container);
return v;
}
And I should have :
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(com.quentindommerc.flatme.R.layout.f_contact, container, false);
return v;
}
So basically, in the inflate method, put "false" as third parameter.
Edit : Corrected spelling mistake.
Related
I'm using ViewPager and TabLayout. And ViewPager is consisted with 4 fragments(for example, I'll call the fragments' name 1, 2, 3, 4). My 2(second fragment) has a ListView, and if I click a list-item, the 2(second fragment) will be changed another view. At that time, another view is not 1, 3 or 4. That is a new view.
It is purpose to make board's category(like, sports-soccer-midfielder). So when I select sport item, the view will show another list-item(like, soccer, baseball, basketball an so on). The category will be consisted with 3 step. So i will prepare second and third view of 2(second fragment).
But I don't know how to change view or fragment. I found some clue to solve this problem in google.
That is
FragmentManager fm = getFragmentManager();
FragmentTransaction fmt = fm.beginTransaction();
View2 v2 = new View2(); // View2 is another view
fmt.replace(R.id.view1, v2);
fmt.commit();
I used that code and it succeed to change view. But only a part of view is changed. What is the problem? How can I solve that?
Here is Pic of second fragment
and this is a view when I click list-item. only a part of view is changed.
(I can't attach picture directly, so someone help please ^^ )
And this is my code of second fragment.
public class MatchingFragment extends Fragment {
View2 v2;
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.matching_fragment, container, false);
final MatchingListViewAdapter adapter = new MatchingListViewAdapter();
ListView listView = (ListView) view.findViewById(R.id.matching_list1);
listView.setAdapter(adapter);
adapter.addItem(ContextCompat.getDrawable(getActivity(), R.drawable.lock), "LOCK", "This is lock icon");
adapter.addItem(ContextCompat.getDrawable(getActivity(), R.drawable.setup), "SETUP", "This is setup icon");
adapter.addItem(ContextCompat.getDrawable(getActivity(), R.drawable.user), "USER", "This is user icon");
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
FragmentManager fm = getFragmentManager();
FragmentTransaction fmt = fm.beginTransaction();
v2 = new View2();
fmt.replace(R.id.view1, v2);
fmt.commit();
adapter.notifyDataSetChanged();
}
});
return view;
}
}
Thanks.
I think you need to start a activity when you click item on listview. because if you replace new fragment with viewpager how can you go back to previous fragment. and why you create View2() object, what is the purpose of that?
if you want to replace fragment with viewpager use this code for it, don't replace viewpager by viewpager
Fragment fragment = new FragmentOne();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.view, fragment);
ft.commit();
I am trying to develop an application which has 3 tabs and one of the tab has a listview. I can handle the onclick events for listview items. What I need to know is how to open new activity/fragment in the same tab(without losing Tab bar)
You can use Android.Support.V4.App.Fragment and SupportFragmentManager to achieve this. First add by Nuget Support.V4 package. In your Activity layout add
RelativeLayout, this layout will be keep your fragments. Add new fragments and by using fragment manager you can changing it. Using function ChangeFragment(), You will be only change view in RealitiveLayout. Try follow this sample.
main.axml
<!-- The Main Content View -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:id="#+id/SetFragment" />
main_activity.cs
protected void ChangeFragment(int pos)
{
Fragment fragment = null;
switch (pos)
{
case 0:
fragment = new NotificationFragment();
break;
case 1:
fragment = new SampleFragment();
break;
}
SupportFragmentManager.BeginTransaction()
.Replace(Resource.Id.SetFragment, fragment, LoadFragment)
.Commit();
}
sample_fragment.cs
public class SampleFragment : Fragment
{
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View = inflater.Inflate(Resource.Layout.sampleView, container, false);
return View;
}
}
I have a view that shows a List of Properties, at the bottom of the screen there's a button that opens a fragment containing a MapView.
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.find_property_btn_map:
PropertyMapFragment fragment = PropertyMapFragment.newInstance(false, null);
getActivity().getSupportFragmentManager().beginTransaction()
.addToBackStack(null)
.replace(((ViewGroup) getView().getParent()).getId(), fragment, PropertyMapFragment.class.getSimpleName())
.commit();
break;
}
}
The onCreateView method for my Properties fragments is as follows
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
mRootView = inflater.inflate(R.layout.fragment_properties_list, container, false);
getmBtnMap().setOnClickListener(this);
getmBtnSaveSearch().setOnClickListener(this);
getmBtnSort().setOnClickListener(this);
getmListView().setAdapter(getPropertyAdapter());
getmListView().setOnItemClickListener(this);
getmListView().setOnScrollListener(this);
getmListView().setScrollingCacheEnabled(false);
searchProperties();
return mRootView;
}
searchProperties(); takes care of calling a Web Service and filling the ArrayAdapter.
The thing is that, when I open the MapFragment and then press the back button, my Property fragment is blank and the buttons do not respond to onClick events.
I tried debugging and saw that onCreateView() is being called when coming back to Property fragment, but the buttons are no longer working and the listview is nowhere to be seen.
What am I doing wrong?
If you are trying to launch that web view from a fragment, then try to use add fragment instead of replace.
For example :
getActivity().getSupportFragmentManager().beginTransaction()
.addToBackStack(null)
.replace(YOUR_CONTAINER_ID, fragment, PropertyMapFragment.class.getSimpleName())
.commit();
The code above is replace that fragment container with the new one and not adding that fragment on top of that. So when you do a replace fragment with that ID, it just replaces that view with new one.
Now,
Same code but with add:
getActivity().getSupportFragmentManager().beginTransaction()
.addToBackStack(null)
.add(YOUR_CONTAINER_ID, fragment, PropertyMapFragment.class.getSimpleName())
.commit();
Now, that web view fragment that you have will be added to the view/fragment and now when you press back from that web view, you previous fragment will be visible.
Just make sure that that the ID you are replacing is the same as the one in which you have all the other properties.
Maybe i misinterpreted the question so please correct me in that context.
Hope this helps.
addToBackStack() <--dont include this for your first fragment.-->
if(getSupportFragmentManager().getBackStackEntryCount() !=1){
fragmentTransaction.addToBackStack(null);
}
i am learning fragments and i am stuck in how to dynamically change layout in the main activity where i want to call different fragments according to the list text i choose from a listview.
This is the Fragment extension class. Do i have to do any if else here so that i can return my desired layout?Lets say i click another option in listview and i want Layout.arts instead of Layout.sports to be shown in the main activity, how can it be done?
public class MenuFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.sports, container, false);
}
}
here is the onclick listener for the listview
private class DrawerItemClickListener implements ListView.OnItemClickListener {
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Log.d("Hello","Clicked");
// update the main content by replacing fragments
MenuFragment frag = new MenuFragment();
android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
MenuFragment fragment = new MenuFragment();
fragmentTransaction.replace(R.id.drawer_layout, fragment, String.valueOf(position));
fragmentTransaction.commit();
mDrawerLayout.closeDrawer(mDrawerList);
}
}
If the business logic is same other than only layout, you can write the if - else condition in the onCreateView() of Fragment
If the business logic is different for sports and arts then create two different fragments for sports and arts and onItemClick() method replace the appropriate fragment.
I think you can do it with Layout Inflater:
public void changeView(int layoutId){
container.removeAllViewsInLayout();
inflater.inflate(layoutId, container, true);
}
container and inflater are from onCreateView.
In order to create a Navigation Drawer, and because it seemed confusing, I used Eclipse's automatically created template. However, this template creates code so that it displays the content of a String array adapter, and at the selection of an item a Fragment is instantiated in the attached Activity like this:
#Override
public void onNavigationDrawerItemSelected(int position)
{
// update the main content by replacing fragments
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment fragment = null;
switch (position)
{
case 0:
fragment = new FragmentType0();
break;
case 1:
fragment = new FragmentType1();
break;
case 2:
fragment = new FragmentType2();
break;
default:
Log.w(this.getClass().getSimpleName(), "Reached Default in onNavigationDrawerItemSelected!");
break;
}
if (fragment != null)
{
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(R.id.container, fragment);
ft.addToBackStack(null);
ft.commit();
mTitle = getString(((GetActionBarTitle) fragment).getActionBarTitleId());
restoreActionBar();
}
}
Because the generated template is the following:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
mDrawerListView = (ListView) inflater.inflate(R.layout.fragment_navigation_drawer, container, false);
mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
selectItem(position);
}
});
String[] drawerTitles = new String[] { getString(R.string.drawer_string_0), getString(R.string.drawer_string_1), getString(R.string.drawer_string_2)};
mDrawerListView.setAdapter(new ArrayAdapter<String> (getActionBar().getThemedContext(), android.R.layout.simple_list_item_1,
android.R.id.text1, drawerTitles));
mDrawerListView.setItemChecked(mCurrentSelectedPosition, true);
return mDrawerListView;
}
So as you can see, the titles are given in the navigation drawer, displayed and specified as a String, and when you select an item, the callback is called on the Activity, at which based on position of selected item, the 'proper' Fragment is instantiated based on an if-else structure. This seems like a fairly fragile solution, but I can't seem to figure out how to make it better.
My hunch is something like using a FragmentStatePagerAdapter, but I'm at a loss, as I've never used one before, especially not in this particular context (I'm REALLY new to the navigation drawer, and I don't know how I would integrate it with the navigation drawer, so that it displays strings that correspond to each Fragment). Can anyone please provide advice on what to do here? It works, but it doesn't seem like the "proper" solution.
I'd reccomend that you stay away from the auto-generated code. A lot of the time, it isn't at all what you want.
I recommend you take a look at this tutorial. It explains the basics of the navigation drawer pretty well.