I'm working on an app that uses a navigation drawer, with each menu items intended to launch a particular fragment. And each fragment must be in a list view form. Is there a way to launch the listfragments as normal fragment can be launched?
For instance:
new MyListFragment();
Is there a similar way to launch listfragments from the main activity?
Fragments are never "launched," they are added to Activities. Either add the fragment to the current activity using a FragmentTransaction (perhaps by replacing the content area), or start another activity with that fragment in it.
private void goToRadar(FragmentManager fm){
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.flMain, new ChildRadarFragment());
ft.addToBackStack("radar");
ft.commit();
}
You must have a FrameLayout inside the xml-layout of your Activity (here the id = flMain).
You should do the FragmentTransactions when a menu listitem is clicked (=drawer ListView).
mDrawerList.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View v, int index,
long arg3) {
// Here the FragmentTransaction
}
});
Related
This question already has an answer here:
Android: Opening a Fragment from another
(1 answer)
Closed 6 years ago.
I am working inside a Fragment that has a ListView. When the user clicks on a list row, I want to open another fragment that should show another ListView.
This is the method I have for now:
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String topic = String.valueOf(parent.getItemAtPosition(position));
Log.d("Comunidad",topic);
//PASA VALOR SELECCIONADO AL SIGUIENTE FRAGMENT
}
});
What is the best way to open the new Fragment from inside this method?
Thank you.
Add a FrameLayout to your preferred activity's layout to call FragmentA (the fragment to be opened onClick):
<FrameLayout
android:layout_width="match_parent"
android:id="#+id/outer_frame"
android:layout_height="wrap_content">
</FrameLayout>
and then replace outer_frame (FrameLayout) with your FragmentA by doing this:
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String topic = String.valueOf(parent.getItemAtPosition(position));
Log.d("Comunidad",topic);
getSupportFragmentManager().beginTransaction()
.replace(R.id.outer_frame, new FragmentA())
.commit();
}
});
inside onClick of listview
Fragment2 new_frag = new Fragment2();
return new_frag;
// Inside your onClick method
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.container, new MyFragment());
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
I might be wrong but i think what you want to do is not possible, because fragments are not intended to be open inside an already opened activity...
What you could do is prepare the activity with the fragment and then change it's content when you want to...
Might be wrong tho...
I would like to make a Fragment pop-up like an AlertDialog but with a transparent background.
My fragment looks like this:
At the moment I am doing the following:
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Player player = (Player)adapterView.getItemAtPosition(i);
FragmentTransaction fragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(PlayerProfileFragment.newInstance(null), null);
fragmentTransaction.commit();
}
The fragment doesn't show at all. I guess in order to make it work, I should use the overload add(layoutId, fragment) but that would just place the Fragment in a specific area and not display the Fragment as a "popup".
Any ideas?
The Fragment probably doesn't show because you are not specifying to which layout you want to add it to. The version of add() that you are using, adds the Fragment to a container whose id is 0 as the docs say.
I fixed this issue by creating an interface with the method:
public void addFragment(int viewId, Fragment fragment);
I then implemented that listener in my Activity by having a FragmentTransaction inside it:
public void addFragment(int viewId, Fragment fragment){
FragmentTransaction fragmentTransaction = getSupportFragmentTransaction().beginTran....;
fragmentTransaction.add(viewId, fragment);
fragmentTransaction.commit();
}
I ran into this problem where my ListFragment is empty after having popBackStackImmediate
I have a main activity which extends FragmentActivity and I have a Navigation drawer attached with my main activity. The first navigation calls a Fragment which has a custom adapter which implements FragmentStatePagerAdapter showing three tabs. each of the tabs are ListFragments them selves. when i click on any row of the list it goes to another fragment, till this everything works fine, now I want to implement the backstack so that when user presses back button from the detail page they can come back to the FragmentList page again. when I press back button it takes me back to the FragmentList page that is fine but the page is empty, for some reason the list does not shows up. I've checked the log and found the data is there and it goes till last bit of the code with out any error but the page is empty, can any one help me with that?
When I select any item from the List of any tab I add the transaction into the backstack and move on to detail fragment:
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
Fragment fragment = new LiveMatchDetailMainFragment();
android.support.v4.app.FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.content_frame, fragment);
fragmentTransaction.addToBackStack("LiveFragment");
fragmentTransaction.commit();
}
In my main activity I have this:
#Override
public void onBackPressed(){
Log.d("stack","back pressed");
FragmentManager fm = getSupportFragmentManager();
if (fm.getBackStackEntryCount() > 0)
{
//fm.popBackStack();
boolean done = fm.popBackStackImmediate();
Log.i("stack", String.valueOf(done));
} else
{
Log.i("stack", "nothing on backstack, calling super");
super.onBackPressed();
}
}
which takes me to exact tab where I clicked the item from the list, but only problem is the fragment is empty.
In the FragmentList page I have:
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
LiveMatchList = new ArrayList<HashMap<String, Object>>();
//Log.d("LiveMatchList setUserVisibleHint","setUserVisibleHint");
new LoadUpcomingMatchList().execute();
}
}
which creates a list using custom adapter, and it works fine for the first time, when I pop the backstack this method gets call and loads all the data comes down till onPostExecute but the list is never showed, sorry guys I am not new to stackoverflow but this is my second question post so I might not follow the convention correctly...
Apparently with some help I fixed the issue...
I added the fragment transactions within the FragmentActivity and used my onListItemClick() callback method to call a FragmentActivity method, which should run the transaction.
In EventFragment replaced:
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
viewpager.setAdapter(new MyAdapter(fragmentManager));
with:
viewpager.setAdapter(new MyAdapter(getChildFragmentManager()));
it was the getChildFragmentManager() that solved my problem mainly.
I'm working with Fragments for the first time and running into a weird behavior. I have an activity with a Fragment covering the entire view. It contains a ListView. When I tap on an item in the ListView, I want to show a details fragment which contains information about that item.
This is how I'm presenting the new fragment view:
FragmentManager fragmentManager = this.getActivity().getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
DetailsFragment fragment = new DetailsFragment();
transaction.add(R.id.viewRoot, fragment).setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.addToBackStack("Details").commit();
R.id.viewRoot is the id of the root layout in the first Fragment's layout xml, so the new Fragment fills the entire screen.
My Problem: When the new fragment is visible and covering the entire screen, any clicks or taps which land on the background (i.e. not hitting a button or textfield on the new fragment) appear to be going through the view and landing on the first fragment. So, I tap on a ListView item, which causes the DetailsFragment to get added to the screen. Then when I tap on the background of the DetailsFragment, that tap falls through and lands on the ListView causing another DetailsFragment to be added for whatever item I happened to hit behind the scenes.
Am I adding my new fragment incorrectly? Why are my clicks/taps falling through?
EDIT for caiuspb:
public class BaseFragment extends Fragment {
public void pushNewFragment(Fragment fragment, String description) {
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.remove(this);
transaction.add(R.id.viewRoot, fragment).setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.addToBackStack(description).commit();
}
}
All of my fragments extend my BaseFragment class.
I experimented with the suggestions I received, but none of them worked. In the end, my solution was to add an OnTouchListener to the root view of my subfragments which discarded all touches.
View view = inflater.inflate(R.layout.mylayout, container, false);
view.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
There is another post here on StackOverflow about that strange Fragment behaviour. Try to remove your Fragment before you add it because the replace Method seems to be buggy
edit:
Move the Fragment logic into your Activity because your activity contains your Fragments. Today I tried to use the FragmentActivity and Fragments from the Android Support Library. Now I can use the replace method withouht any bugs. This is my approach and this works:
public class DashActivity extends FragmentActivity{
...
private void changeRightFragment(Fragment fragment) {
Log.i(TAG, "Loading Fragment into container: " + fragment.getClass().toString());
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.rightfrag, fragment);
// Add a transition effect
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
// Add the Fragment to the BackStack so it can be restored by
// pressing the Back button
ft.addToBackStack(null);
ft.commit();
}
...
public void setUserFragment(User user) {
UserFragment fragment = new UserFragment(user);
changeRightFragment(fragment);
}
So if you want to invoke a changeFragment method from inside your Fragment use a callback mechanism to the Activity
I have an app with three tabs (ActionBar Tabs), each one with one fragment at a time.
TabListener
TabsActivity
Tab1 -> ListFragment1 -> ListFragment2 -> Fragment3
Tab2 -> Tab2Fragment
Tab3 -> Tab3Fragment
The problem is when I create the FragmentTransaction (inside OnListItemClicked) from ListFragment1 to ListFragment2, the fragments inside the other tabs also change to ListFragment2.
In the end, I want to change fragments only inside on tab and preserve the state of the other tabs.
I'm already saving the state (OnSavedInstance()).
Do you know what I'm missing here?
Some of the code:
public class TabsActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tabs);
// setup Action Bar for tabs
ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// instantiate fragment for the tab
Fragment networksFragment = new NetworksFragment();
// add a new tab and set its title text and tab listener
actionBar.addTab(actionBar.newTab().setText("Tab1")
.setTabListener(new TabsListener(ListFragment1)));
// instantiate fragment for the tab
Fragment historyFragment = new HistoryFragment();
// add a new tab and set its title text and tab listener
actionBar.addTab(actionBar.newTab().setText("Tab2")
.setTabListener(new TabsListener(Tab2Fragment)));
// instantiate fragment for the tab
Fragment settingsFragment = new SettingsFragment();
// add a new tab and set its title text and tab listener
actionBar.addTab(actionBar.newTab().setText("Tab3")
.setTabListener(new TabsListener(Tab3Fragment)));
}
}
public class TabsListener implements ActionBar.TabListener {
private Fragment frag;
// Called to create an instance of the listener when adding a new tab
public TabsListener(Fragment networksFragment) {
frag = networksFragment;
}
#Override
public void onTabReselected(Tab arg0, FragmentTransaction arg1) {
// TODO Auto-generated method stub
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
ft.add(R.id.fragment_container, frag, null);
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
ft.remove(frag);
}
}
public class ListFragment1 extends ListFragment {
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
getListView().setItemChecked(position, true);
ListFragment2 fragment2 = ListFragment2.newInstance(position);
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container, fragment2);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(null);
ft.commit();
}
}
You're not missing anything (or I'm missing it too).
I searched long and hard for a way to do this "properly" but I couldn't find anything. What I ended up doing is writing my own backstack logic.
Unfortunately my employer owns my code so I can't share any of that verbatim, but here was my approach:
Create an enum with one entry for each of your tabs. Let's call it TabType.
Now create an instance variable tabStacks of type HashMap<TabType, Stack<String>>. Now you can instantiate one stack for each tab - each stack is a list of tags, as specified by Fragment.getTag(). This way you don't have to worry about storing references to Fragments and whether they're going to disappear on you when you rotate the device. Any time you need a reference to a Fragment, grab the right tag off the stack and use FragmentManager.findFragmentByTag().
Now whenever you want to push a Fragment onto a tab, generate a new tag (I used UUID.randomUUID().toString()) and use it in your call to FragmentTransaction.add(). Then push the tag on top of the stack for the currently displayed tab.
Be careful: when you want to push a new fragment on top of an old one, don't remove() the old one, since the FragmentManager will consider it gone and it will be cleaned up. Be sure to detach() it, and then attach() it later. Only use remove() when you're permanently popping a Fragment, and only use add() the first time you want to show it.
Then, you'll have to add some relatively simple logic to your TabListener. When a tab is unselected, simply peek() at its stack and detatch() the associated Fragment. When a tab is selected, peek() at the top of that stack and attach() that fragment.
Lastly, you'll have to deal with Activity lifecycle quirks (like orientation changes). Persist your Map of Stacks as well as the currently selected tab, and unpack it again in your onCreate(). (You don't get this packing and unpacking for free, but it's pretty easy to do.) Luckily your TabType enum is Serializable so it should be trivial to put into a Bundle.