I have the following problem:
I have an exisiting ListFragment, but I would like to display this as a dialog.
My first approach was to create a DialogFragment which has to ListFragment inside of it, but appearently it is currently not possible to put fragments in fragments.
Extending DialogFragment instead of ListFragment is also not possible, because of the heavy use of ListFragment methods.
Is there an easy way to do this?
What works for me is
1) in xml layout for your DialogFragment called, let's say, DialogFragmentwWithListFragment specify ListFragment class
E.g. dialog_fragment_with_list_fragment.xml :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="#+id/flContent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding = "10dp"
class="com.xxx.yyy.DialogFragmentwWithListFragment " />
</LinearLayout>
2) in DialogFragmentwWithListFragment inflate dialog_fragment_with_list_fragment.xml
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.dialog_fragment_with_list_fragment, null);
}
3) invoke DialogFragmentwWithListFragment as regular DialogFragment:
DialogFragmentwWithListFragment dialogFragment = DialogFragmentwWithListFragment .newInstance();
dialogFragment.setRetainInstance(true);
dialogFragment.show(getFragmentManager(), "tag");
Hope, it helps.
I would either put the ListView inside a DialogFragment or try to put the ListFragment inside a Dialog. I am not sure if the second one is possible though.
You can show a list through a DialogFragment this way:(using the support v4 library)
public class MyListDialogFragment extends DialogFragment {
onDlgListClick mCallback;
private String[] lista;//the list you want to show with the dialog
public static MyListDialogFragment newInstance(Bundle fB){
MyListDialogFragment lstFrag = new MyListDialogFragment();
Bundle args = new Bundle();
args.putStringArray("lista", fB.getStringArray("lista"));//the list
args.putString("titulo", fB.getString("titulo"));//the title of the list
lstFrag.setArguments(args);
return lstFrag;
}
public interface onDlgListClick{
public void onLstItemSelected(String selection);
}
#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 = (onDlgListClick) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement onLstItemSelected");
}
this.setCancelable(false);
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
lista = getArguments().getStringArray("lista");
return new AlertDialog.Builder(getActivity())
.setTitle(getArguments().getString("titulo"))
.setCancelable(false)
.setItems(lista, new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int item){
mCallback.onLstItemSelected(lista[item]);
getDialog().dismiss(); //maybe you dont need these two lines
MyListDialogFragment.this.dismiss();
}
}).create();
}
}
On the main activity you extend FragmentActivity and implements the interface MyListDialogFragment.onDlgListClick
//the interface
#Override
public void onLstItemSelected(String selection) {//list dialog fragment interface
//do whatever you want
}
//calling the dialog
public void showFrags(int id){
Bundle fB = new Bundle();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment prev = getSupportFragmentManager().findFragmentByTag("listdialog");
if (prev != null) {
ft.remove(prev);
}
ft.commit();
switch(id){
case 0:
fB.putStringArray("lista", list); fB.putString("titulo",title);
MyListDialogFragment newListDlg = MyListDialogFragment.newInstance(fB);
newListDlg.show(ft, "listdialog");
break;
}
}
When adding a fragment inside another fragment, the documentation says you should do it dynamically (i.e., rather than hardcoding a <fragment> tag into your layout XML.
So here is how to do it dynamically. In this case, I add MyListFragment to MyDialogFragment:
MyDialogFragment.java
import android.app.Dialog;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
public class MyDialogFragment extends DialogFragment {
public static final String TAG = MyDialogFragment.class.getSimpleName();
private static final String ARG_TITLE = "ARG_TITLE";
private EditText mEditText;
public MyDialogFragment() {
// Empty constructor required for DialogFragment
}
public static MyDialogFragment newInstance(String title) {
MyDialogFragment myDialogFragment = new MyDialogFragment();
Bundle args = new Bundle();
args.putString(ARG_TITLE, title);
myDialogFragment.setArguments(args);
return myDialogFragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = super.onCreateDialog(savedInstanceState);
Bundle args = getArguments();
if (args != null) {
dialog.setTitle(args.getString(ARG_TITLE));
}
return dialog;
}
public void setTitle(String title) {
Dialog dialog = getDialog();
dialog.setTitle(title);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dialog_fragment_selected_products, container, false);
//addInnerFragment();
Button okButton = (Button)view.findViewById(R.id.okButton);
okButton.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View view) {
dismiss();
//dismissAllowingStateLoss();
}
}
);
return view;
}
#Override
public void onStart() {
super.onStart();
//addInnerFragment();
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
addInnerFragment();
}
public void addInnerFragment() {
FragmentManager childFragmentManager = getChildFragmentManager();
FragmentTransaction transaction = childFragmentManager.beginTransaction();
//transaction.add(R.id.fragmentContainer, new MyListFragment());
transaction.add(R.id.fragmentContainer, MyListFragment.newInstance(MyListFragment.MODE_SELL));
//transaction.commit();
transaction.commitAllowingStateLoss();
childFragmentManager.executePendingTransactions();
}
}
(As you will see, it also contains some functionality to set the title of the dialog.)
dialog_fragment_selected_products.xml
<?xml version="1.0" encoding="utf-8"?>
<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=".MyDialogFragment"
android:orientation="vertical">
<LinearLayout
android:id="#+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_alignParentTop="true"
android:layout_above="#+id/okButton" />
<Button
android:id="#+id/okButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="#string/ok" />
</RelativeLayout>
Another advantage of doing it this way is that you can create an instance of the inner fragment in order to pass any arguments to it.
For completeness, here is the code that I use in my activity to show the DialogFragment:
MyActivity.java
private void showCurrentItemsDialog() {
MyDialogFragment myDialogFragment = MyDialogFragment.newInstance("cpuk.org");
//myDialogFragment.setRetainInstance(true);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.add(myDialogFragment, MyDialogFragment.TAG);
transaction.commitAllowingStateLoss();
fragmentManager.executePendingTransactions();
}
Related
I want to pass arguments to my PopularMoviesFragment using newInstance() method. I have MainActivity where inside onOptionsItemSelected() I create a fragment using PopularMoviesFragment.newInstance("popularity.desc") and then make a transaction.
Inside the PopularMoviesFragment: I set arguments newInstance(String sortBy) using setArguments(), but when I want to retrieve them inside onCreate(), getArguments() returns null.
Here is the code, PopularMoviesFragment:
public class PopularMoviesFragment extends Fragment {
public static PopularMoviesFragment newInstance(String sortBy) {
PopularMoviesFragment fragment = new PopularMoviesFragment();
Bundle args = new Bundle();
args.putString("sortBy", sortBy);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String sortBy = getArguments().getString("sortBy", "");
// java.lang.NullPointerException in the previous line
// Attempt to invoke virtual method 'java.lang.String
// android.os.Bundle.getString(java.lang.String, java.lang.String)'
// on a null object reference
}
}
And inside MainActivity:
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.action_popular_movies:
PopularMoviesFragment fragment = PopularMoviesFragment.newInstance("popularity.desc");
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment)
.commit();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
I tried the pasted code. It's weird that I didn't get the NullPointerException at all.
TestActivity.java :
package com.example.myapplication;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class TestActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
Button btn_test = findViewById(R.id.btn_test);
btn_test.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
testFragment();
}
});
}
private void testFragment() {
PopularMoviesFragment fragment = PopularMoviesFragment.newInstance("popularity.desc");
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, fragment)
.commit();
}
}
activity_test.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:text="test"
android:textSize="32sp"
android:textColor="#000"
android:id="#+id/btn_test"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="wrap_content"></FrameLayout>
</LinearLayout>
PopularMoviesFragment.java:
package com.example.myapplication;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.View;
public class PopularMoviesFragment extends Fragment {
public static PopularMoviesFragment newInstance(String sortBy) {
PopularMoviesFragment fragment = new PopularMoviesFragment();
Bundle args = new Bundle();
args.putString("sortBy", sortBy);
fragment.setArguments(args);
return fragment;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String sortBy = getArguments().getString("sortBy", "");
Log.i("test", "sortBy=" + sortBy);
}
}
Override onActivityCreated() method in your Fragment and retrieve the value of sortBy in this method using this line - String sortBy = getArguments().getString("sortBy", ""); instead of the onCreate() method.
I'm suffering through nested fragments. I have a mainactivity which calls a fragment 1 which in turns call a fragment via a button. The fragment frag2 is well instantiated but the screen is blank.
Is there something obvious with my code?
MainActivity
import android.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentManager fragmentManager;
Frag1 f1 = new Frag1();
fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame,
f1).commit();
}
}
mainactivity xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.narb.nestedfragments.MainActivity">
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
Fragment 1 and its xml layout:
import android.app.FragmentTransaction;
import android.content.Context;
import android.os.Bundle;
import android.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.RelativeLayout;
/**
* A simple {#link Fragment} subclass.
*/
public class Frag1 extends android.app.Fragment {
Context context;
private Button back1;
RelativeLayout rl1;
public Frag1() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootview = null;
rootview = inflater.inflate(R.layout.fragment_frag1, container, false);
return rootview;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
context = getActivity().getApplicationContext();
initFindView();
back1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Log.i("frag1","createdview");
//getActivity().getFragmentManager().popBackStackImmediate();
rl1.setVisibility(View.INVISIBLE);
FragmentTransaction ft = getFragmentManager().beginTransaction();
Frag2 f2 = new Frag2();
ft.replace(R.id.fl1, f2);
ft.addToBackStack(null);
ft.commit();
}
});
}
private void initFindView(){
back1 = (Button) getActivity().findViewById(R.id.btn1);
rl1 = (RelativeLayout) getActivity().findViewById(R.id.rl1);
}
}
Is it normal that I need to make my layout frag 1 invisible before calling frag2?
and finally my fragment 2 and its layout. I see the log for frag 2 but the screen is empty:
import android.app.Fragment;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
public class Frag2 extends Fragment {
Context context;
private Button btn2;
public Frag2() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootview;
rootview = inflater.inflate(R.layout.fragment_frag2, container, false);
Log.i("frag2","createdview");
return rootview;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
context = getActivity().getApplicationContext();
Log.i("frag2","onactivitycreated");
btn2 = (Button) getActivity().findViewById(R.id.btn2);
btn2.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Log.i("frag2","onactivitycreated");
}
});
}
}
<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"
tools:context="com.narb.nestedfragments.Frag2">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Test 2" />
<Button
android:id="#+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="60dp"
android:text="back"
/>
</RelativeLayout>
if your fragment 1 is having another FrameLayout where you are replacing fragment 2, then instead of getFragmentManager(), use getChildFragmentManager() in fragment 1
otherwise you are passing wrong container id in replace() method R.id.fl1 inside fragment1. you should pass R.id.content_frame there.
You have not posted the fragment1 XML Code. lets assume RelativeLayout (rl1) is your parent layout and you have FrameLayout (fl1) inside the rl1. You are making the parent layout invisible. So the fragment2 can't be visible.
If you don't want to show the fragment1 while showing there is no need for the nested fragment.
You should call like this to load second fragment.
getFragmentManager().beginTransaction()
.replace(R.id.content_frame ,new Frag2());
.addToBackStack(null);
.commit();
use content_frame id of activity_main in Frag1 class
back1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Log.i("frag1", "createdview");
//getActivity().getFragmentManager().popBackStackImmediate();
rl1.setVisibility(View.INVISIBLE);
FragmentTransaction ft = getFragmentManager().beginTransaction();
Frag2 f2 = new Frag2();
ft.replace(R.id.content_frame, f2);
ft.addToBackStack(null);
ft.commit();
}
});
In my application, I have an instance of a fragment, ActivityFragment, which is added dynamically when a button, addActivity, is pressed. There is a delete_button in each ActivityFragment, and I have set an onClickListener for this button within the ActivityFragment class. When the delete_button is pressed, I want to remove the fragment from inside the onClick method. How would I go about doing this when I create the ActivityFragment object and add it to the activity in a method outside of the fragment class? And what field should I use for .remove()?
Note that delete_button should only remove the instance of the fragment it is in.
Here is my MainActivity.java with the ActivityFragment class. The addActivity button is at the bottom:
import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public static class ActivityFragment extends Fragment {
// #Nullable is used because the method may return a null value
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
final View fragment1 = inflater.inflate(R.layout.activity_fragment, container, false);
Button edit_button = (Button) fragment1.findViewById(R.id.edit_button);
Button delete_button = (Button) fragment1.findViewById(R.id.delete_button);
edit_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
TextView activityText = (TextView) getView().findViewById(R.id.activity_text);
activityText.setText("success");
}
});
delete_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getFragmentManager().beginTransaction()
.remove().commit();
}
});
return fragment1;
}
}
public void addActivity(View view) {
ActivityFragment myFragment = new ActivityFragment();
getFragmentManager().beginTransaction()
.add(R.id.fragment_container, myFragment).commit();
}
}
You can remove the fragment instance like this
delete_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getFragmentManager().beginTransaction()
.remove(ActivityFragment.this).commit();
}
});
A fragment can be removed by doing this:
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
MyFragment myFragment = new MyFragment();
fragmentTransaction.remove(myFragment).commit();
Here myFragment is your "FRAGMENT" that you want to remove from the current context or current activity.
i'm trying to add tabs for main activity which should pointing to several fragments.
Is it possible from Android Studio designer?
I added into my activity layout tabhost like on image below, but on real device is not displayed.
How can i solve it?
Thanks for any advice.
I will reduce my example on one Button, you should be able to multiply it. I also cut out unneccessarry stuff like margins etc... If you have problems, just tell me and I will gladly help you out:
MainActivity.java - openHome method is interesting
public class MainActivity extends Activity implements HomeFragment.OnFragmentInteractionListener
{
FragmentManager fragmentManager = getFragmentManager();
HomeFragment homeFragment;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
homeFragment = new HomeFragment();
fragmentManager.beginTransaction().add(R.id.mainFrame, homeFragment).commit();
}
public void openHome(View view)
{
homeFragment = new HomeFragment();
fragmentManager.beginTransaction().replace(R.id.mainFrame, homeFragment).commit();
}
#Override
public void onFragmentInteractionHome(Uri uri)
{
Toast.makeText(this, "Success", Toast.LENGTH_SHORT).show();//only to check, can be removed (the content, the method must be implemented!!!!!!!!!!!!!!!)
}
}
activity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
tools:ignore="MergeRootFrame" >
<FrameLayout
android:id = "#+id/mainFrame"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
android:layout_marginBottom = "#dimen/bottom_Main_Tabs">
</FrameLayout>
<LinearLayout
android:layout_width = "match_parent"
android:layout_height = "#dimen/bottom_Main_Tabs"
android:layout_gravity = "bottom"
>
<ImageButton
android:id = "#+id/bottomButton_home"
android:layout_height = "match_parent"
android:layout_width = "0dp"
android:layout_weight = "1.0"
android:background = "#drawable/ic_home_white"
android:onClick = "openHome"
/>
</LinearLayout>
</FrameLayout>
HomeFragment.java - if you create a fragment, all this will be autogenerated plus comments, which I cut out.!!! Interesting is only the inner interface at the bottom!!!:
import android.app.Activity;
import android.app.Fragment;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
public class HomeFragment extends Fragment
{
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
public static HomeFragment newInstance(String param1, String param2)
{
HomeFragment fragment = new HomeFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
public HomeFragment()
{
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if (getArguments() != null)
{
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_home, container, false);
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri)
{
if (mListener != null)
{
mListener.onFragmentInteractionHome(uri);
}
}
#Override
public void onAttach(Activity activity)
{
super.onAttach(activity);
try
{
mListener = (OnFragmentInteractionListener) activity;
}
catch (ClassCastException e)
{
throw new ClassCastException(activity.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach()
{
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener
{
// TODO: Update argument type and name
public void onFragmentInteractionHome(Uri uri);
}
}
fragment_home.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/home_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/blue"
tools:context="com.domain.app.HomeFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:textSize="100sp"
android:text="Home" />
</FrameLayout>
I tthink that is all. If not, just tell me :)
I have a Fragment with a method setName() that changes an EditText text, by means of the setText function.
What is the best way to call that method from the activity that hosts that fragment by means of a ViewPager?
In other words, how can I access a Fragment's methods (which change that fragment's layout, for example) from the Activity that hosts that fragment by means of a ViewPager?
I am asking this because I have tried several ways, but always with errors.
Best way to do this, just call
CallingFragmentName fragment = (CallingFragmentName) viewPager
.getAdapter()
.instantiateItem(viewPager, viewPager.getCurrentItem());
It will re-instantiate your calling Fragment, so that it will not throw null pointer exception.
I know this is a little late, but I ran into the same problem and maybe it will help others if you already solved it.
The first problem I found with ViewPager is that it is almost impossible to get a reference to a fragment. The fragments are created dynamically in getItem() and therefore you can't set an ID and they are automatically re-taged by the swicher, so you can't find it by tag either. There are some ways out there to do it, but they are all workarounds. (Update data in ListFragment as part of ViewPager)
The way I solved it was using essentially a double Callback. Fragment A has an interface implemented by the Main Activity, the Main Activity has a interface implemented by Fragment B. On e.g. a button clink in Fragment A the callback function in Main Activity is called, which than in turn calls the callback in Fragment B. Look at the code below. I hope I posted everything and it will help. btw, I have only tried this with a ViewPager, but I assume it would work with any sort of Fragment communication.
Main Avtivity java:
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
public class MainActivity extends FragmentActivity implements FragmentA.Caller {
SectionsPagerAdapter mSectionsPagerAdapter;
ViewPager mViewPager;
PassCallToB passOnToB = null;
FragmentManager myManager = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
MyManager = fm;
}
#Override
public Fragment getItem(int position) {
Fragment fragment = null;
if(position == 0) {
fragment = new FragmentA();
} else if (position == 1) {
fragment = new FragmentB();
passOnToB = (PassCallToB)fragment;
}
return fragment;
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "Frag A";
case 1:
return "Frag B";
}
return null;
}
public void setCallback() {
List<Fragment> frags = myManager.getFragments();
for(Fragment fragment : frags) {
if(fragment instanceof FragmentB){
passOnToB = (PassCallToB)fragment;
}
}
}
}
public interface PassCallToB {
public void passItOn();
}
#Override
public void CallB() {
if(passOnToB instanceof Fragment)
passOnToB.passItOn();
else {
mSectionsPagerAdapter.setCallback();
passOnToB.passItOn();
}
}
}
Main Activity xml:
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<android.support.v4.view.PagerTitleStrip
android:id="#+id/pager_title_strip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:background="#33b5e5"
android:paddingBottom="4dp"
android:paddingTop="4dp"
android:textColor="#fff" />
</android.support.v4.view.ViewPager>
Fragment A java:
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
public class FragmentA extends Fragment {
Button btnCallB = null;
Caller listener = null;
public FragmentA() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle inState) {
View rootView = inflater.inflate(R.layout.fragment_a, container, false);
btnCallB = (Button)rootView.findViewById(R.id.btnCallB);
btnCallB.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
listener.CallB();
}
});
return rootView;
}
public interface Caller {
public void CallB();
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof FragmentActivity) {
listener = (Caller) activity;
} else {
throw new ClassCastException(activity.toString() + " must implemenet listener");
}
}
#Override
public void onDetach() {
super.onDetach();
listener = null;
}
}
Fragment A xml:
<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" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="This is Fragment A" />
<Button
android:id="#+id/btnCallB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="#+id/textView1"
android:text="Call Fragment B" />
</RelativeLayout>
Fragment B Java:
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
public class FragmentB extends Fragment implements MainActivity.PassCallToB {
public FragmentB() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle inState) {
View rootView = inflater.inflate(R.layout.fragment_b, container, false);
return rootView;
}
#Override
public void passItOn() {
Toast.makeText(getActivity(), "Hello from B", Toast.LENGTH_SHORT).show();
}
}
Fragment B xml:
<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" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="This is Fragment B" />
</RelativeLayout>
You can access public methods within the fragments held by your ViewPager. You need to either (1) store a reference to the Fragment when you create it and add it to the list that will back your pager adapter or (2) you need to get a reference to the fragment from the pager adapter itself. For example:
Fragment fragmentA = null; //instance variable
fragmenA = new Fragment(); //whereever you instantiate your fragment
If your method is
public void setName(String args){
//do something
}
all you would do is call that method from the reference to the fragment held by your ViewPager
fragmentA.setName(args);
You pass whatever arguments you need just like calling a regular method. Note this ONLY works if you are calling a method within a fragment from its containing ViewPager or FragmentActivity. If you want to do the reverse, fragment to activity, you need to use an inerface.
Fragment
private static FragmentName instance;
public static synchronized FragmentName getInstance()
{
return instance;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
instance=this;
....
}
public void methodName()
{...}
Activity
FragmentName.getInstance().methodName();