I am having trouble opening a fragment from within another fragment on the click of a button. Everything seems to make sense (to me) and I have tried playing about with my code (changing the layouts, replacing fragments etc) but nothing is working.
Here is my RoleFragment.java (The fragment which contains the button)
public class RolesFragment extends Fragment implements View.OnClickListener {
GridView gridView;
ArrayList<Players> playersList;
MyAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater,ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_viewroles, container, false);
gridView = (GridView) view.findViewById(R.id.gv_players);
Button nightround = (Button) view.findViewById(R.id.buttonNightRound);
nightround.setOnClickListener(this);
DatabaseHelper databaseHelper = new DatabaseHelper(getActivity());
playersList = new ArrayList<Players>();
playersList = databaseHelper.getPlayers();
adapter = new MyAdapter(getActivity(), playersList);
gridView.setAdapter(adapter);
return view;
}
#Override
public void onClick(View v) {
Fragment fragment = null;
switch (v.getId()) {
case R.id.buttonNightRound:
fragment = new NightRound();
replaceFragment(fragment);
break;
}
}
public void replaceFragment(Fragment someFragment) {
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, someFragment);
transaction.addToBackStack(null);
transaction.commit();
}
}
And this is my fragment_viewroles.xml file.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.example.tuss.mafia.GameActivity" >
<Button
android:id="#+id/buttonNightRound"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Night Round"
android:onClick="FragmentNightRoundClick"
android:clickable="true"
android:layout_weight="2"/>
<GridView
android:id="#+id/gv_players"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="auto_fit"
android:stretchMode="columnWidth"
android:columnWidth="150dp"
android:horizontalSpacing="10dp"
android:verticalSpacing="10dp"
android:gravity="center"
android:layout_below="#id/buttonNightRound">
</GridView>
</RelativeLayout>
The trouble is, when I click the button nothing happens.
There some problems here.
First, you have to add a container with the id R.id.fragment_container inside your fragment like FrameLayout
which will store your new fragment.
If your want to open a fragment as a new screen, you have to put it inside a new activity. Fragments are piece of screens and should not be used without activities or view pagers.
Have a look at the Android deverlopers page: http://developer.android.com/training/basics/fragments/communicating.html#DefineInterface
Basically, you define an interface in your Fragment A, and let your Activity implement that Interface. Now you can call the interface method in your Fragment, and your Activity will receive the event. Now in your activity, you can call your second Fragment to update the textview with the received value
// You Activity implements your interface
public class YourActivity implements FragmentA.TextClicked{
#Override
public void sendText(String text){
// Get Fragment B
FraB frag = (FragB)
getSupportFragmentManager().findFragmentById(R.id.fragment_b);
frag.updateText(text);
}
}
// Fragment A defines an Interface, and calls the method when needed
public class FragA extends Fragment{
TextClicked mCallback;
public interface TextClicked{
public void sendText(String text);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
mCallback = (TextClicked) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement TextClicked");
}
}
public void someMethod(){
mCallback.sendText("YOUR TEXT");
}
#Override
public void onDetach() {
mCallback = null; // => avoid leaking, thanks #Deepscorn
super.onDetach();
}
}
// Fragment B has a public method to do something with the text
public class FragB extends Fragment{
public void updateText(String text){
// Here you have it
}
}
Try something like the following:
Fragment fragment = OtherFragment.newInstance();
android.support.v4.app.FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.container_layout, fragment, "OtherFragment");// give your fragment container id in first parameter
transaction.addToBackStack(null); // if written, this transaction will be added to backstack
transaction.commit();
Related
I have an activity (MainActivity) which extends AppCompatActivity because I am using some of the material design elements in my app.
I then have an array adapter with a few fields and a button. This adapter has a separate view and is injected into my MainActivity layout.
When I click the button on the adapter view, I want to open a new fragment which displays a bunch of text, however, I can't seem to do this and I think it is because I am not extending FragmentActivity in my MainActivity? I read on another post that I should be able to extend AppCompatActivity and still be able to reference the fragment manager...here is my code to open the fragment:
In my custom array adapter, onClick() of a button:
holder.desc.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
JobDescFragment fragment= new JobDescFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
});
The error I get is that it cannot resolve getSupportFragmentManager(). What am I doing wrong?
I am importing android.support.v4.app.Fragment and .FragmentManager in my adapter.
Thanks in advance for the help!
EDIT:
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<com.lorentzos.flingswipe.SwipeFlingAdapterView
android:id="#+id/frame"
android:background="#color/laborswipe_lightgray"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:context=".MainActivity"
android:layout_gravity="top" />
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</merge>
you can try this
FragmentTransaction ft = ((AppCompatActivity) mContext).getSupportFragmentManager()
.beginTransaction();
In kotlin it will be like this for example. I have tried it and it work perfectly
val dialog = IntervAddFragment()//The fragment that u want to open for example
val ft = (context as AppCompatActivity).supportFragmentManager.beginTransaction()
dialog.show(ft, ContentValues.TAG)
Hi this is simple just pass the reference of YourParent Activity
Just use the snippet like this below in Your Adapter class to open fragment
Fragment fragment = new YourFragment();
FragmentManager fm = ((MainActivity) mContext).getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.frame_container, fragment);
ft.commit();
in adapter use
appCompatActivity object instead of context
it will work
pass context in adapter and use
context.getSupportFragmentManager().beginTransaction();
avoid unwanted codes
public class AdapterRecyclerViewDoc extends RecyclerView.Adapter<AdapterRecyclerViewDoc.ShareDocViewHolder> {
ArrayList<ModelDoc> arrayList;
AppCompatActivity appCompatActivity;
public AdapterRecyclerViewDoc(ArrayList<ModelDoc> arrayList, AppCompatActivity appCompatActivity) {
this.arrayList=arrayList;
this.appCompatActivity=appCompatActivity;
}
#Override
public ShareDocViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate
(R.layout.recyclerview_item_doc, parent, false);
ShareDocViewHolder eventViewHolder = new ShareDocViewHolder(v);
this.appCompatActivity.getSupportFragmentManager();
return eventViewHolder;
}
To make the code more flexible and separate logic you should understand responsibilities of your components. It is clear that your Adapter should not know about the Fragment and what is base class of Activity. So what should you do?
In your Activity you should set a listener to item clicked event inside adapter:
public class YourActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_your);
//... some findViewById, etc.
YourAdapter adapter = new YourAdapter(this, data, new OnDetailsRequestListener(){
public void onDetailsRequested(int itemId){
DetailsFragment fragment = DetailsFragment.newInstance(itemId);
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment)
.addToBackStack(null)
.commit();
});
//... recyclerView.setAdapter ... etc.
}
public interface onDetailsRequestListener{
void onDetailsRequestLister(int itemId);//here could be whatever you want, itemId, details, whatever...
}
}
And inside your adapter you would have:
//...
public AdapterConstructor(Context context, ArrayList data, YourActivity.OnDetailsRequestListener detailsRequestListener) {
this.data = data;
this.context = context;
this.detailsRequestListener = detailsRequestListener;
//...
}
//Inside bindView
holder.desc.setTag(position);
holder.desc.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int position = (int)view.getTag();
int itemId = data.get(position).getId();
detailsRequestListener.onDetailsRequested(itemId);
}
});
From your class
YourAdapter=new YourAdapter(context, list, YourClass.this.getSupportFragmentManager)
Adapter
public Adapter(context, list, FragmentManager manager){
this.manager=manager;
Action
FragmentTransaction ft = fragmentcontext.beginTransaction();
SlideshowDialogFragment newFragment = SlideshowDialogFragment.newInstance();
newFragment.setArguments(bundle);
newFragment.show(ft, "slideshow");
FragmentTransaction trans =((FragmentActivity)context).getSupportFragmentManager()
.beginTransaction();
If you try this, you will see it work.
I have read this manual and also i'm reading this book. developer.android.com says i should implement communication through activity. But the book says i can use setTargetFragment() and call onActivityResult() by hand for target fragment from other fragment. Each approach works but which is right? What is setTargetFrament() for, if i can't use it for communication with other fragment?
setTargetFrament() and getTargetFrament() can be used in the context of one fragment that starts another fragment. The first fragment can pass its self as a reference to the second fragment:
MyFragment newFrag = new MyFragment();
newFrag.setTargetFragment(this, 0);
getFragmentManager().beginTransaction().replace(R.id.frag_one, newFrag).commit();
Now newFrag can use getTargetFrament() to retrieve the oldFrag and access methods from oldFrag directly.
This is not however something that is recommanded to be used on an usual basis.
The recommanded way of communication between fragments is to be done through the parent activity, as the docs mention:
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.
Here is a example of that:
the layout for the main activity:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout
android:id="#+id/frag_one"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<FrameLayout
android:id="#+id/frag_two"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
the Activity:
public class MainActivity extends Activity
{
private MyFragment f1;
private MyFragment f2;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Bundle b1 = new Bundle();
b1.putString("name", "Fragment One");
f1 = MyFragment.createNew(b1);//we create a new fragment instance
f1.setOnReceiveListener(new MyFragment.ReceiveListener()//we create a new ReceiveListener and pass it to the fragment
{
#Override
public void recv(String str)
{
//f1 has sent data to the activity, the activity passes forward to f2
f2.send(str);
}
});
//we attach the fragment to the activity
getFragmentManager().beginTransaction().add(R.id.frag_one, f1, "frag_one").commit();
//we repeat the above process for the second fragment
Bundle b2 = new Bundle();
b2.putString("name", "Fragment Two");
f2 = MyFragment.createNew(b2);
f2.setOnReceiveListener(new MyFragment.ReceiveListener()
{
#Override
public void recv(String str)
{
f1.send(str);
}
});
getFragmentManager().beginTransaction().add(R.id.frag_two, f2, "frag_two").commit();
}
}
The fragment layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="#+id/frag_btn"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_alignParentTop="true"/>
<TextView
android:id="#+id/frag_txt"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_below="#+id/frag_btn"
android:textSize="10sp"/>
</RelativeLayout>
The fragment class:
public class MyFragment extends Fragment
{
private ReceiveListener recv_list;
private Button btn;
private TextView txt;
//static factory function that creates new fragments
public static MyFragment createNew(Bundle b)
{
MyFragment f = new MyFragment();
f.setArguments(b);
return f;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
btn = (Button) view.findViewById(R.id.frag_btn);
txt = (TextView) view.findViewById(R.id.frag_txt);
//we retrieve the passed arguments (in this case the name)
Bundle b = getArguments();
final String name = b.getString("name");
btn.setText(name);
btn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
if(null != recv_list)
{
//now we pass the data to the parent activity
recv_list.recv(name + " says hello!");
}
}
});
}
//the activity passes data to the fragment using this method
public void send(String s)
{
txt.append(s + "\n");
}
//helper method that will set the listener
public void setOnReceiveListener(ReceiveListener l)
{
recv_list = l;
}
//the declaration of the listener
public interface ReceiveListener
{
public void recv(String str);
}
}
I'm trying to start a fragment from my main activity, but somehow the fragment is not showing up. Can someone help me with this?
Here is my code:
public class Main extends Activity implements OnClickListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button b = (Button) findViewById(R.id.action_menu);
b.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if(v.getId()==R.id.action_menu){
Log.d("--", "menu clicked");
MenuFragment newFragment = new MenuFragment();
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(android.R.id.content, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}
}
main activity layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/main_rl" >
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="#+id/action_menu" android:text="Menu"/>
</RelativeLayout>
and my fragment Class:
public class MenuFragment extends Fragment{
final String TAG=this.getClass().getSimpleName();
private GridView grid;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View mView;
Log.d(TAG, "Hello from Fragment");
mView=inflater.inflate(R.layout.menu_fullscreen, null);
initWidgets(mView);
return mView;
}
private void initWidgets(View mView) {
grid=(GridView) mView.findViewById(R.id.menu_fullscreen_grid);
}
}
you cannot replace what you put in setContentView(R.layout.main); if main.xml is hardCoded...(xml file). with
transaction.replace...
You may use fragmentActivity without setContentView(R.layout.main)
I am using fragments,I have an edittext in fragment and I want to get value in main activity.
This is my fragment layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#878787" >
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="dfgdfgdf"
android:textSize="20dp"
android:layout_centerInParent="true"
android:id="#+id/user_name"/>
<EditText
android:id="#+id/message"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<Button
android:text="Gönder"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="getFromUser"
android:layout_marginTop="40dp"
/>
</RelativeLayout>
I am loading fragment with this function:
public void startChat(JsonObject user) {
FrameLayout layout = (FrameLayout)findViewById(R.id.container);
layout.setVisibility(View.VISIBLE);
Bundle bundle = new Bundle();
bundle.putString("name", user.get("name").getAsString());
sendTo=user.get("username").getAsString();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ConversationFragment conv = new ConversationFragment();
conv.setArguments(bundle);
fragmentTransaction.add(R.id.container, conv);
fragmentTransaction.commit();
viewPager.setVisibility(View.GONE);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setDisplayHomeAsUpEnabled(true);
}
And this is my fragment class
public class ConversationFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
String name = getArguments().getString("name");
View rootView = inflater.inflate(R.layout.fragment_conversation, container, false);
TextView username=(TextView)rootView.findViewById(R.id.user_name);
username.setText(name);
return rootView;
}
}
As you can see when press the button main activity runs "getFromUser" function.I want to get edittext value in this function.How can I do this ?
It's always the same procedure for these things. You can't access a fragment's views just like that. You need a callback method.
Add this code to ConversationFragment:
private OnGetFromUserClickListener mListener;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnGetFromUserClickListener ) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnGetFromUserClickListener");
}
}
public void getFromUser(View v) {
if (mListener != null) {
EditText edit = (EditText)findViewById(R.id.message);
mListener.getFromUser(edit.getText().toString());
}
}
public interface OnGetFromUserClickListener {
void getFromUser(String message);
}
Make your MainActivity implement this interface. Replace getFromUser() inside MainActivity with:
public void getFromUser(String message) {
sendMessage(message);
}
Done.
Edit:
Actually, using the XML-onClick attribute is currently bugged (see onClick inside fragment called on Activity): It links to the activity instead of the fragment. You have to set the click listener programmatically to make sure the code won't break at some point in the future. So give the button an ID inside the XML (e.g. get_from_user) and add this code to onCreateView inside ConversationFragment:
v.findViewById(R.id.get_from_user).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (v.getId() == R.id.get_from_user) {
getFromUser(v);
}
}
});
Using this code vastly decouples the activity and the fragment from each other.
I resolved this problem.
public void getFromUser(View view) {
ConversationFragment fragment1 = (ConversationFragment)getSupportFragmentManager().findFragmentById(R.id.container);
View frag=fragment1.getView();
EditText editText1 =(EditText) frag.findViewById(R.id.message);
String message=editText1.getText().toString();
sendMessage(message);
}
Now I can get edittext value from fragment.
I am working on Fragment-ListView and having output showing in image.
every Click changes TextView of fragment2.till now ok.
fragmetn1 is for listView and fragment2 is for DifferentView.
now i want to change layout in fragment2 with click. e.g. as item2 is clicked,a layout with textView sets in fragment2. now with selection of item3, diferent layout with Button should be set to fragment2.
my getView code is here.
public void onListItemClick(ListView l, View v, int position, long id) {
DetailFrag frag = (DetailFrag) getFragmentManager().findFragmentById(R.id.frag_detail);
if (frag != null && frag.isInLayout()) {
frag.setText("item "+position+" selected");
}
}
is there other way to do this,plz also help that way.
any suggestion would be strongly appreciated.thanks in advance.
Try the following method
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
then you need to add your fragment to this fragmentTransaction with the following syntax.
fragmentTransaction.replace(R.id.detailFragment, layout1);
And finally you MUST commit your transaction. Otherwise changes will not persist.
fragmentTransaction.commit();
In my opinion you should use different fragments with different layout and using FragmentTransaction to replace the existing one.
Your approach likely works fine, but it is probably better to use a more loosely coupled approach where the ListFragment informs the hosting activity that an item has been clicked, and then the activity tells the "other" fragment to update.
No need to worry about constructing and replacing new fragments.
Sample activity
public class TestActivity extends Activity implements TestFragmentBListener {
private TestFragmentA mOtherFragment;
private TestFragmentB mListFrag;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
mListFrag = (TestFragmentB) getFragmentManager().findFragmentById(R.id.fragment_b_list);
mOtherFragment = (TestFragmentA) getFragmentManager().findFragmentById(R.id.fragment_a_text);
}
#Override
public void onTestFragmentBItemCLicked(int position) {
// Implemented from TestFragmentB.TestFragmentBListener
mOtherFragment.setText("item " + position + " selected.");
}
}
Sample FragmentA (contains text.. this is not functional, only an example)
public class TestFragmentA extends Fragment {
public void setText(String text) {
}
}
Sample ListFragment that defines an interface for the sample activity to implement
public class TestFragmentB extends ListFragment {
private TestFragmentBListener mListener = null;
public interface TestFragmentBListener {
void onTestFragmentBItemCLicked(int position);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (TestFragmentBListener) activity;
} catch (ClassCastException ccex) {
// activity does not implement our listener
}
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
if (mListener != null) {
mListener.onTestFragmentBItemCLicked(position);
}
}
}
and for the sake of completeness, here was my layout for the sample activity:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".TestActivity" >
<fragment
android:id="#+id/fragment_a_text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<fragment
android:id="#+id/fragment_b_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/fragment_a_text" />
</RelativeLayout>