Set an ItemClickListener on FragmentStatePagerAdapter - android

I have implemented a ViewPager with FragmentStatePagerAdapter and i want an ItemClickListener so that i can open the detail screen when the user clicks on each fragment of the viewpager. I am not able to find any such methods which are available.

You should implement a callback interface to communicate between your fragments and your containing activity. In each fragment, set your needed listeners, and then pass any information needed back to your activity to handle the click.
public class MyFragment extends Fragment {
public interface MyFragmentListener {
void onTheActivityICareAbout();
}
private MyFragmentListener mCallback;
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
mCallback = (MyFragmentListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
+ " must implement MyFragmentListener");
}
}
}
Then when you bind your view, set your listner to use the callback on whatever event you need and your activity has your centralized code to handle that. Any interface method can also be used to pass data back to the activity as well.
You can see this link for more details.

Your FragmentStatePageAdapter will have a method that looks like this:
override fun getItem(day: Int): Fragment = YourPageFrament.newInstance()
So, in the code for YourPageFragment, you can set on OnClickListener on the fragment itself.
You can set this listener by modifying the XML layout file for that fragment to include a Linear Layout or some kind of layout.
Then, in your YourPageFragment class, possibly in your onCreateView() method, you can set on OnClickListener on the fragment's layout.

Related

Fragment interface/listener works with Activity, but not with another Fragment

I have a fragment that also has two fragments inside. And I'm trying to implement the listeners within the two fragments to the parent fragment. However, I'm getting an error on
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof MyPostsUpdateListener) {
myPostsUpdateListener = (MyPostsUpdateListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement MyPostsUpdateListener");
}
}
I have implemented something similar to this in the same manner with just a different listener, and actually works, but in that case, it is being implemented to an activity, instead of a parent fragment.
Is there any work around to this? Because I'm sure that I have implemented it the same way to some other activity, with the only difference that it is being implemented by an activity, and in this case, which gives an error, by a fragment.
To pass data back to parent fragment, you can get instance of the parent fragment inside child fragment by calling getParentFragment method.
public class ChildFragment extends Fragment {
private void sendToParentFragment(String data) {
Fragment fragment = getParentFragment();
if (fragment instanceof MyPostsUpdateListener) {
myPostsUpdateListener = (MyPostsUpdateListener) fragment;
myPostsUpdateListener.onData(data);
}
}
}

ViewPage listener fired after fragment creation

Short Story:
How to detect a ViewPager page scrolling/changing before fragment lifecycle execution for the new page?
Long Story:
I have a ViewPager with assigned fragments to be displayed using ViewPagerAdapter, one of these fragments is meant to be displayed with different data according to current page selected in the pager.
for example, if current page selected is 2 it would display A data, and if the current page selected is 4 it would display B data.
the straight forward solution is to set the data according to the current page using OnPageChangeListener or SimpleOnPageChangeListener, but both are not applicable as the fragment WHOLE life cycle is being called before any of these listeners methods being called, so the data would be set after fragment creation here.
the second straight forward solution is to make the changes after receiving the call from the listeners which is so bad regarding user experience and design wise.
So would be the best way to set fragment credentials when changing the current page of the ViewPager before onResume() method of the fragment to be executed?
What I'm doing:
in MyFragment.java:
// it goes here first
#Override
public void onResume() {
super.onResume();
// check the Data Applied
if(dataA)
doSomething();
else
doSomethingElse();
}
in MainActivity.java:
pager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// then it goes here
// setting the Data of the fragment
if (position == 2)
setDataA();
else (position == 4)
setDataB();
}
});
Why don't you use callback Interface? If you set interface, you can even get the call back on the fragment onAttach() or where you want.
Example Implementation:
Activity:
public class MyActivity extends AppCompatActivity implements FragmentListener {
#Override
public void onFragmentSelected(String value) {
// set data here.
}
public interface FragmentListener {
void onFragmentSelected(String value);
}
}
In your viewPager Fragments:
public class MyFragment extends Fragment{
#Override
public void onAttach(Context context) {
super.onAttach(context);
if(context instanceof MyActivity){
((MyActivity)context).onFragmentSelected("Your_Identification");
}
}
}
Do this in all your viewPager fragments so you will get which fragment attached from the frgment onAttach() itself. Or choose when it should be called.
Hope it Helps:)

Adding a listener between two fragments

I have two fragments, A and B let's say, where B contains a list. I would like to add a listener on Fragment B that notifies Fragment A of the chosen list item. I couldn't figure out how to initialize the listener in Fragment B since it is bad practice to pass arguments in fragment's constructors.
NOTE: Fragment B is contained inside Fragment A. i.e. I have a FrameLayout in Fragment A; and Fragment B covers that FrameLayout.
Any idea how I could do that?
If you're saying that Fragment B is a child fragment of Fragment A (that is, you've added it to Fragment A using Fragment A's getChildFragmentManager()), then you can use the same approach that you use for Activity interfaces, but using getParentFragment() instead of getActivity().
For example:
Fragment B:
#Override
public void onAttach(Context context) {
MyInterface myInterface = (MyInterface) getParentFragment();
}
Assuming that Fragment A implements MyInterface.
One convenience method we've used to avoid having to know whether a Fragment is hosted by another Fragment or an Activity is something like:
public static <T> getInterface(Class<T> interfaceClass, Fragment thisFragment) {
final Fragment parent = thisFragment.getParentFragment();
if (parent != null && interfaceClass.isAssignableFrom(parent)) {
return interfaceClass.cast(parent);
}
final Activity activity = thisFragment.getActivity();
if (activity != null && interfaceClass.isAssignableFrom(activity)) {
return interfaceClass.cast(activity);
}
return null;
}
Then you can just use:
MyInterface myInterface = getInterface(MyInterface.class, this);
and it doesn't matter whether Fragment B is hosted as a child Fragment or in an Activity directly.
A better approach for this situation, since what you want to do is communication between fragments, is to use an interface. You want to notify A when B has changed. This should be done through the parent activity. Here is the android documentation on the topic: https://developer.android.com/training/basics/fragments/communicating.html.
The gist of it is that you want to define an interface with a method called OnItemSelected (you can name it whatever you want). In B, you want a reference to this interface. When an item is selected, call your new OnItemSelected method. Implement this interface in the parent activity of the two fragments. In the implementation, you can put whatever code you want to modify A.
An example
CommunicationInterface
public interface CommunicationInterface {
public void onItemSelected(int position);
}
FragmentB
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
CommunicationInterface myInterface = (CommunicationInterface) getActivity();
// What ever else you want here
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
// Send the event to the host activity
myInterface.onItemSelected(position);
}
MainActivity
public class MainActivity extends FragmentActivity implements CommunicationInterface {
// What ever other code you have
#Override
public void onItemSelected(int position) {
FragmentA fragA = (FragmentA)
getSupportFragmentManager().findFragmentById(R.id.fragment_a);
// Code to interact with Fragment A
}
Checkout the contract pattern https://gist.github.com/JakeWharton/2621173
If you are using multiple fragment, you dont have do it for every fragment, just add it to your BaseActivity if you have one.
This example shows the communication between activity and fragment. But for nested fragment you can replace the acitivy with getParentFragment();

How to update fragment in Swipe View with Tabs

the following: I'm using Swipe View with Tabs. Works quite smooth so far.
The thing is: I have two fragments/tabs. Each contains a ListView. I can remove an item from the left list. When I swipe to the right I want to update the list adapter so the left-deleted item is shown.
I tried onSwipeListerner, TabListener, onPageChangeListener (and on Resume() in the fragment itself). Nothing worked... Either the function is not called or I don't get the fragment object.
Does anybody know how I can call a function in my Fragment class when I swipe to this tab/fragment?
Thanks!
http://developer.android.com/training/basics/fragments/communicating.html#Deliver
I believe this is what you are looking to accomplish. But I don't think your plan of action is the best.
I would create an interface in my fragment where items will be deleted from such as
public class FragmentDeleteItemSharer extends Fragment{
// Interface in Fragment
public interface ShareDeletedItem{
// Interface method you will call from this fragment
public void shareItem(Object deletedItem);
}// end interface
// Instantiate the new Interface Callback
ShareDeletedItem mCallback = null;
// Override the onAttach Method
#Override
public void onAttach(Activity activity){
super.onAttach(activity);
try{
// Attaches the Interface to the Activity
// must add "implements ShareDeletedItem" in your
// Activity or this Exception is thrown
mCallback = (ShareDeletedItem) activity;
}catch(Exception ex){
ex.printStackTrace();
}
}// end onAttach()
// the method which you use to
// remove an item from the current fragment's listview
// where position is from yourlistViewAdapter.getSelectedItemPosition();
public void removeListItem(int position){
// using the item position, get the item in your object array
Object objectToDelete = myObjects[position];
// pass this information to removeItemFromArray
// a method that creates a new object array from the data
Object [] newObjectList = removeItemFromArray(myObjects, objectToDelete);
// Then use the interface callback to tell activity item was deleted
mCallback.shareItem(objectToDelete);
// Call to the method where you update the UI with the Objects
// Are you using an arrayList? Not sure but probably have
// an ArrayList<Objects> myObjects, as reference above
updateUiWithData(newObjectList);
}
}// end this fragment
Then in your activity create an interface
public class MyActivity extends FragmentActivity implements ShareDeletedItem{
// Interface Object , must attach this interface to Fragment2, when its created
UpdateFragment2 mCallback = null;
// You must attach this interface to your Fragment2, when its created
// you could do so with your view pager, create a method that adds each
// fragment to the view pager, then call a new method like
// addinterface(fragmentReference)
public interface UpdateFragment2{
// method to call in your Fragment that shows queue of deletes
public void addItemtoList(Object newObject);
}
// Interface Callback from the Fragment that deletes an item
public void shareItem(Object deletedItem){
// call the interface method to share the item with the Fragment2
mCallback.addItemToList(deletedItem);
}
}
Finally, Implement this interface in your Fragment2
public class Fragment2 extends Fragment implements UpdateFragment2{
// Interface Method in charge of giving this fragment the deleted item
public void addItemToList(Object deletedItem){
// TODO: Add the Item to the list you currently have
// If the mObjects array is an array list
mObjects.add(mObjects[mObjects.length + 1], deletedItem);
}
}
Depending on how you create your fragments with your view pager call
try{
// or however you hold reference to the fragment
mCallBack = (UpdateFragment2) Fragment2.class;
}catch(Exception ex){ex.printStackTrace();}
This is the Full of It. Hope this helps you understand that the interface way is the way to go. This is kind of difficult to help with no code from you but this is how it is done. The hardest part is adding the interface to the fragment when you create the fragments with you view pager. Good Luck

update TextView in fragment A when clicking button in fragment B

I have two fragments sitting side by side in the same activity. When I touch a button in the right fragment (fragment B), I need a TextView in the left fragment to update (fragment A). I have looked all over for the best way to do this, but nothing seems to work for my needs. Could someone possibly give me an example of how I would code this? Fragment A is set through the XML layout, and fragment B gets loaded programmatically into a container. I have tried accomplishing this by using a method in fragment A to update the text, and calling on that method from a method in the parent activity. I then call on the method in the parent activity from fragment B.
This is the code in fragment B that declares the interface and calls a method in the interface
AttackCards attackCards;
public interface AttackCards {
public void deckSize();
}
public void onAttach(DeckBuilder deckBuilder) {
super.onAttach(deckBuilder);
attackCards = (AttackCards) deckBuilder;
}
attackCards.deckSize(); //this is in my onclick methods
This is the code in the activity that implements the interface and calls the method in fragment A
public class DeckBuilder extends Activity implements AttackCards{
public void deckSize() {
DeckBuilderFragment deckBuilderFragment = (DeckBuilderFragment)getFragmentManager().
findFragmentById(R.id.deckbuilder_fragment);
deckBuilderFragment.deckSize();
}
This is the method in fragment A that appends the textview with the contents of a shared preferences value
public void deckSize() {
deckSize = (TextView) getView().findViewById(R.id.decksize);
final SharedPreferences defaultDeck = getActivity()
.getSharedPreferences("defaultDeck", Context.MODE_PRIVATE);
deckSize.setText(String.valueOf(defaultDeck.getInt("decksize", 0)));
}
Sadly this attempt simply brings me a nullpointer when touching a button. I am getting a null pointer at
attackCards.deckSize(); //this is in my onclick methods
Could someone please help me out with an example of how to do this correctly?
One fragment should not communicate to another fragment directly. It should do so through attached activity. The detail explanation with code example is available here
Android Developer site
Declare an interface in Fragment B, and implement the interface in the activity. Call the interface through callback in Fragment B when button is clicked. You can have a public function in Fragment A to update the TextView, so activity directly call the function to update the text.
You can define an interface in Fragment B and implement it on the MainActivity. Then on the callback method (onClickOnB in this case) set the text on the TextView. You should obtain a reference of the TextView in the Activity's onCreate() after setContentView(). This works because Fragment A is static. Otherwise, you can create a public method inside Fragment A so you can set the text from inside the callback by getting a reference of Fragment A and calling such method.
Fragment B
public class FragmentB extends Fragment implements onClickListener{
ClickOnB listener;
public void setOnFragmentBClickListener(ClickOnB listener){
this.listener = listener;
}
#Override
public void onClick(View v){
//stringMessage is a `String` you will pass to `Fragment` A to update its `TextView`
listener.onClickOnB(stringMessage);
}
interface ClickOnB{
public void onClickOnB(String message);
}
}
MainActivity
public class MainActivity extends Activity implements ClickOnB{
#Override
protected onCreate(Bundle savedInstanceState){
//Get a reference of `Fragment` B somewhere in your code after you added it dynamically and set the listener.
((FragmentB)getFragmentManager().findFragmentByTag("FragmentB")).setOnFragmentBClickListener(this);
}
#Override
public void onClickOnB(String message){
//Set the text to the `TextView` here (I am assuming you get a reference of the `TextView` in onCreate() after inflating your layout.
mTextView.setText(message);
}
}

Categories

Resources