Set a focus in Fragment - android

I have a below situation:
An activity, with a Fragment-A.
On user input, a new Fragment (lets call it Fragment-B)is added, by using below code:
ft.add(R.id.content_frame, fragmentB);
Now, when I press back, the fragment-B is destroyed as expected.
As fragment-B was added(and not replaced) there is no callback to onResume() of Fragment A.
I need to set focus of fragment-A as soon as fragment-B is destroyed.
I use below code to set the Focus:
getView().setFocusableInTouchMode(true);
getView().requestFocus();
Is there any way to achieve this?

For those developers who are struggling to get the "callback" in Fragment( when fragments are added and NOT Replaced ), can try below method:
Use addOnBackStackChangedListener which adds a new listener for changes to the fragment back stack.
I added this addOnBackStackChangedListener in onCreate() method of my Fragment-A, as below:
getFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if (getView()!=null){
getView().setFocusableInTouchMode(true);
getView().requestFocus();
}
}
});
Now As soon as Fragment-B is destroyed, onBackStackChanged is called and I was able to set the focus.
Of course, you can write whatever code you want to execute inside onBackStackChanged when Fragment is destroyed.

Create an interface:
public interface DestructionListener {
void onDestroyed();
}
Now in your FragmentB class put an implementation of Subject:
private DestructionListener listener;
public void setDestructionListener(DestructionListener listener) {
this.listener = listener;
}
Still in the same fragment, apply such change:
#Override
public void onDestroy() {
...
if(listener != null)
listener.onDestroyed();
super.onDestroy();
}
Now you have Listener pattern implemented - you can listen for an event which occurs when FragmentB is being destroyed. In your activity, just put:
fragmentB.setDestructionListener(new DestructionListener() {
void onDestroyed() {
// Request focus here
}
});
and you're good to go.

You can simply hide the fragment(in which you dont want focus) and show the one u want focus since you are adding fragments and not replacing.

Related

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:)

How to refresh a previous fragment on back press without disturbing the back stack

I am using one activity for tabactivity with viewpager and attached fragmentA.when i want to move fragmentB ,replaced fragmentB with present fragmentA.I need to find solution for onbackpress in FragmentB refresh fragmentA wihtout changing Backstack because i used nearly ten fragments in one tab.
Is there any method in fragment life cycle
When Fragment B over Fragment A, fragment A is onPause(). After backpress, fragment A is onResume(). So you can create a boolean to observe this change.
In Fragment A
private boolean isBackFromB;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
isBackFromB=false;
}
#Override
public void onPause() {
super.onPause();
isBackFromB = true;
}
#Override
public void onResume() {
super.onResume();
updateUI();
if (isBackFromB) //Do something
}
View pager does not always hold it's fragments in memory, so you have to handle 2 scenarios:
1 - fragment is recreated - just read data from wherever you hold them and show in ordinary way.
2 - fragment is modified from outside while still has been held by ViewPager, and as I understand this is what concerns you.
What you can do is to create this listener and then notify fragment that it was shown again and possibly should reload it's data.
More complex answer for communicating between different application's components is using some event bus like Otto.
override onBackPressed() method in Activity, add all fragment in backstack.
#Override
public void onBackPressed() {
FragmentManager manager =getFragmentManager();
int count = manager.getBackStackEntryCount();
if (count == 0) {
super.onBackPressed();
} else {
manager.popBackStack();
}
}

Callback when Fragment is replaced and when it is visible again

I've been researching this topic but so far no luck. Basically I'm replacing a fragment (A) with another one (B) using FragmentTransaction.replace. In this other fragment (B) I have a 'Cancel' button in the toolbar which when pressed pops back to the previous transaction (A) by calling getActivity().getSupportFragmentManager().popBackStackImmediate().
The problem is I need to update the Activity toolbar to display a different title when I'm showing fragment A and fragment B. I can't seem to find a method which gets called in fragment A whenever I go from A -> B -> A to inform me that it is visible again. The idea is to set the toolbar title in this callback which I cannot seem to find.
Can anyone point me in the right direction please?
Cheers.
Edit:
Method I call to replace the fragment with another one is as follows:
public static void replaceFragment(FragmentActivity parentActivity, int fragmentToReplaceId, Fragment withFragment, Integer enterAnim, Integer exitAnim)
{
FragmentManager fragmentManager;
FragmentTransaction transaction;
fragmentManager = parentActivity.getSupportFragmentManager();
transaction = fragmentManager.beginTransaction();
if ( (null != enterAnim) &&
(null != exitAnim) )
{
transaction.setCustomAnimations(enterAnim, exitAnim);
}
transaction.replace(fragmentToReplaceId, withFragment);
transaction.addToBackStack(null);
transaction.commit();
}
You can inform by overriding method onResume() in fragment and sending the message to activity or changing the Toolbar directly.
#Override
public void onResume() {
super.onResume();
((AppCompatActivity) getActivity()).getSupportActionBar().setTitle("Title");
}
In one activity, when replace A ---> B (A and B both are fragments), can use this call-back:
#Override
public void onAttachFragment(Fragment fragment) {
}
Solved by creating a simple static method in fragment A as follows:
public static void updateActivityTitle(FragmentActivity activity)
{
activity.setTitle(kActivityTitle);
}
Then I'm calling this method in fragment B as follows:
// cancel button has been pressed
private void cancel()
{
INV_CustomersFragment.updateActivityTitle(getActivity());
getActivity().getSupportFragmentManager().popBackStackImmediate();
}
Not ideal but it gets the job done. Any other solution involving a proper callback would be better
Update:
A better solution is the one described by #Rani at Fragment's onResume() not called when popped from backstack. This is more elegant and more maintainable, in fact I implemented this solution in my project. Compared to an equivalent solution for iOS this is still messy if you ask me, still seems the way to go.

update listview in fragment when returning to it

I have a Activity that transitions between fragments. Fragment 1 to fragment 2. Fragment 1 has a listview. When the user goes to fragment 2 the user has the option to make changes to the data that fills the listview. When the user presses the back button it takes them back to the first fragment. When the user returns the listview has to be updated to show the changes that were made in fragment 2. How can i do this?
Frag2 pfrag = new Frag2();
pfrag.setArguments(bundle);
ft=fm.beginTransaction();
ft.add(R.id.fragment_swap, pfrag,"Profile");
ft.show(pfrag);
ft.addToBackStack("pfrag");
ft.commit();
You would do this by calling notifyDataSetChanged(); on the ListView's adapter.
For more info
You could use Robins answer or if you want to pass the data in fragment 2 to fragment 1 you could call a method in fragment 1 class:
YourFragmentClass.refreshList( your data)
and in Fragment 2 the method:
puplic void refreshList(your data) {
// set the adapter with your data
}
In you fragment, include the code as like below.
(isPaused)boolean variable is used to track current fragment is paused while navigating to next activity.
While resuming back call the webservice (or) call the method to refresh the list by calling notifydatasetchanged() from adapter.
#Override
public void onResume() {
super.onResume();
if(isPaused) {
isPaused=true;
fetchDirectories();
// call the adapter method to notify the data set.
}
}
#Override
public void onPause() {
super.onPause();
isPaused=true;
}
private boolean isPaused=false;
I think the best way to achieve this, is to load the list in the fragment's onResume()-Method. So, the code looks something like this:
#Override
public void onResume() {
super.onResume();
initializeList();
}
...
private void initializeList() {
adapter = new MessageTemplateAdapter(getActivity(), datasource.getTemplateList());
setListAdapter(adapter);
}

Detect a fragment in the screen

I have a pager that contains three fragments
adapter.addFragment (new PlainColorFragment (Color.red));
adapter.addFragment (new PlainColorFragment (Color.green));
adapter.addFragment (new PlainColorFragment (Color.blue));
My question is whether it is possible to detect that fragmentation has focus or is being displayed to the user.
For example, when the green fragment is the one on screen or has focus, show a "toast" on the screen
I hope I have explained my question correctly.
thanks
Simple:
greenFragment.isVisible();
If you're looking for some kind of event, you would have to manage that manually wherever your fragment switching happens, or in your fragment class, you could execute your code in the fragment's OnHiddenChanged event (double checking, of course, that it is currently visible)
You could set an OnPageChangedListener to your ViewPager and show a different toast depending on the position.
You can create an Interface, implementing it in your Fragment and then, on parent activity, you can implement BackStackChangedListener as in example below:
public interface MyFragmentOnScreen {
public void onActiveFragment();
}
public class MyFragment extends Fragment implements MyFragmentOnScreen{
[...]
#Override
public void onActiveFragment() {
//Things you should do when your fragment becomes active
}
}
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
[...]
getSupportFragmentManager().addOnBackStackChangedListener(
new FragmentManager.OnBackStackChangedListener() {
public void onBackStackChanged() {
// Update your UI here.
Log.v(MainActivity.TAG, "Backstack changed");
if (getSupportFragmentManager().findFragmentById(R.id.frMain) instanceof MyFragmentOnScreen) {
((MyFragmentOnScreen) getSupportFragmentManager().findFragmentById(R.id.frMain)).onActiveFragment();
}
}
}
});
}
}
where frMain is the holder in MainActivity layout for your Fragment.

Categories

Resources