In my application I use ViewPager for show two fragments into activity.
In one of this fragments I use NavigationDrawer, I want when click on onBackPress close this NavigationDrawer.
I write below code for open this Drawer :
reviewSerialFrag_DrawerLayout.openDrawer(Gravity.END);
I want when click on onBackPress close this drawer with below code :
reviewSerialFrag_DrawerLayout.closeDrawer(Gravity.END);
How can I it? Please help me
/Try to use below code snipet/
#Override
public void onBackPressed()
{
int count = getFragmentManager().getBackStackEntryCount();
// count --> Is your current fragment
if (count == 0)
{
if(reviewSerialFrag_DrawerLayout.isDrawerVisible(GravityCompat.END))
{
reviewSerialFrag_DrawerLayout.closeDrawer(GravityCompat.END);
}
}
}
In your Activity onBackPressed() write below code
#Overrdie
public void onBackPressed(){
Fragment currentFragment = getActivity().getFragmentManager().findFragmentById(R.id.fragment_container);
if(currentFragment instanceof YourDrawerFragment && reviewSerialFrag_DrawerLayout.isDrawerVisible(GravityCompat.END))
{
reviewSerialFrag_DrawerLayout.closeDrawer(GravityCompat.END);
return;
}
super.onBackPresses():
}
You can do this to close your drawer on back press
#Overrdie
public void onBackPressed(){
super.onBackPresses():
if(reviewSerialFrag_DrawerLayout.isDrawerVisible(GravityCompat.END)){
reviewSerialFrag_DrawerLayout.closeDrawer(GravityCompat.END);
}
}
In general, I find it easiest to use the Observer pattern and delegate the back pressed event down to the fragment. This will allow you to keep the activity and fragment concerns separated.
interface OnBackPressedListener {
public void onBackPressed();
}
Then, in your fragment, implement this OnBackPressedListener
class MyFragment extends Fragment implements OnBackPressedListener{
public void onBackPressed(){...}
}
And finally, in your activity, you can do the following:
class MyActivity extends Activity {
#Override
public void onBackPressed(){
// Grab all the fragments that are 'observing' the back press event
Fragment currentFragment =
getFragmentManager().findFragmentById(R.id.fragment_container);
if(currentFragment != null && currentFragment instanceof OnBackPressedListener) {
// delegate this back press event down to the fragment
OnBackPressedListener backFragment = (OnBackPressedListener) currentFragment;
backFragment.onBackPressed();
}
super.onBackPressed():
}
In Jon's solution, the super.onBackPressed will always be called. This may not necessarily be the case.
To do this, it is enough that the implementation returns a boolean and act according to the result.
My solution almost identical here
public interface IOnBackPressed {
/**
* Si vous retouné true le back press ne sera pas pris en compte, sinon l'activité agira naturellement
* #return true si votre traitement est prioritaire sinon false
*/
boolean onBackPressed();
}
see link for more details
Related
In my application I use ViewPager for show two fragments in an activity.
In one of the fragments I use NavigationDrawer. I want when click on onBackPress close this NavigationDrawer.
I wrote below code for open this Drawer :
reviewSerialFrag_DrawerLayout.openDrawer(Gravity.END);
I want that when I click on onBackPress it will close this drawer with below code:
reviewSerialFrag_DrawerLayout.closeDrawer(Gravity.END);
questioner, put in what the current problem is, please
onBackpress() only called in fragment if you need back press event in fragment you have to implement interface to get onBackPress() callback.
In Activity:
public MyActivity extends AppCompatActivity{
private BackPressListener backPressListener;
#Override
public void onBackPressed() {
if (backPressListener != null) {
backPressListener.onActivityBackPress();
} else {
super.onBackPressed();
}
}
public void setBackPressListener(BackPressListener backPressListener) {
this.backPressListener = backPressListener;
}
public interface BackPressListener{
void onActivityBackPress();
}
}
In Fragment:
public class MyFragment extends Fragment implements BackPressListener{
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
((MyActivity)getActivity()).setBackPressListener(this);
}
#Override
public void onActivityBackPress() {
// handle your back press here.
reviewSerialFrag_DrawerLayout.closeDrawer(Gravity.END);
getActivity().onBackPressed();
}
#Override
public void onDestroy() {
super.onDestroy();
((MyActivity)getActivity()).setBackPressListener(null);
}
}
My solution:
Create BaseFragment.java:
public class BaseFragment extends Fragment
{
public boolean onBackPressed()
{
return false;
}
}
then extend your fragment by this BaseFragment, and in activity:
#Override
public void onBackPressed()
{
if (!yourFragment.onBackPressed())
super.onBackPressed();
}
In yourFragment:
public class YourFragment extends BaseFragmnet
{
...
.
.
#Override
public boolean onBackPressed()
{
// do something...
return true; // you should return true;
}
}
According to the AndroidX release notes, androidx.activity 1.0.0-alpha01 is released and introduces ComponentActivity, a new base class of the existing FragmentActivity and AppCompatActivity. And this release brings us a new feature:
You can now register an OnBackPressedCallback via addOnBackPressedCallback to receive onBackPressed() callbacks without needing to override the method in your activity.
The best solution is create your interface, and implement in Fragment.
Solution here : implement onBackpress in Fragment
public interface IOnBackPressed {
/**
* Si vous retouné true le back press ne sera pas pris en compte, sinon l'activité agira naturellement
* #return true si votre traitement est prioritaire sinon false
*/
boolean onBackPressed();
}
see link for more details ... easy sample
You can keep the flag that drawer was opened. And when you override the onBackPressed(), check this flag and if it's true, call
reviewSerialFrag_DrawerLayout.closeDrawer(Gravity.END);
otherwise, call super.onBackPressed() or any other logic you need.
I have a Activity A, a ListFragment L and 2 Fragments F1 and F2.
When the app is launched, A is created, which loads L. Based on what user clicks, it is replaced by F1 or F2
I have implemented a Navigation Drawer which shows certain items to the user. However, since I have implemented the Navigation Drawer in the Activity, it shows for all the Fragments. but i want show A is visible
(Very much similar to Googles Gmail app. When the user is on the main screen - the drawer is present. When user taps to open an email, the drawer changes to back button)
I am not sure how to translate the above code. thanks in advance
In your inner fragment(like view mail)
#Override
public void onPause()
{
super.onPause();
((MyActivity) getActivity()).enableToggle();
}
#Override
public void onResume()
{
super.onResume();
((MyActivity) getActivity()).disableToggle();
}
I hope there will be 'NavigationDrawerFragment'in your activity, add this methods:
public void disableToggle()
{
if (mNavigationDrawerFragment != null)
mNavigationDrawerFragment.disableToggle();
}
public void enableToggle()
{
if (mNavigationDrawerFragment != null)
mNavigationDrawerFragment.enableToggle();
}
In NavigationDrawerFragment add this methods:
Also check that you are using android.support.v7.app.ActionBarDrawerToggle;
public void disableToggle()
{
if (mDrawerToggle != null)
mDrawerToggle.setDrawerIndicatorEnabled(false);
}
public void enableToggle()
{
if (mDrawerToggle != null)
mDrawerToggle.setDrawerIndicatorEnabled(true);
}
Edit: see snapshots for above code
MainFragment
DetailFragment
My app works with a long form which I decided to divide in multiple Fragments in a ViewPager. When you press the "save" option, the validation process starts.
Basically the validation is that some EditTexts are not empty. I'm looping through all Fragments in the ViewPager check if all fields has valid values.
// Inside Fragment
public boolean areFieldsValid() {
return !mEditText.getText().toString().isEmpty()
}
public void showErrors() {
mEditText.setError("cannot be blank");
}
If a field inside a Fragment is not valid, then viewPager.setCurrentItem(position, true); and fragment.showErrors() are called to go to that Fragment and show the user the error.
The problem comes when onCreateView() hasn't been called on the Fragment that has the error.
This happens either because you haven't navigated to that Fragment yet (supposing the user's on fragment1, error is on fragment7 and the user pressed "save" while on fragment1) or because the user rotated the device and all views are destroyed on every Fragment.
This problem/issue is not only that mEditText would be null, but also that the Fragment saved its state, so it might not even been blank. In other words, the following code is not an option, because even if the pointer is null, it might not be empty.
// Inside Fragment
public boolean areFieldsValid() {
return mEditText != null && !mEditText.getText().toString()isEmpty();
}
At this point I'm wondering if my architecture is wrong. I decided to go with ViewPager cause the form is really long, and I've been passing data from Fragment to Activity through callbacks.
Given the above settings, how can I validate fields and show the user which field is the one with the error?
You can't just assume that UI components will be there anytime you want. That fragment might be gone, killed or worse, destroyed without saving it's instance state.
What I offer is to save data on database and check if everything is set on save button click event. This can be done using ContentProviders and SQLiteDatabase. As Virgil Said in here "Persist more, persist often."
I have implemented a similar thing, but my approach is to go fragment by fragment. Hope this helps.
I add an interface,
public interface AddActionInterface {
public void onAddButtonClicked();
}
I created a base fragment which implements this interface as,
public abstract class BaseFragment extends Fragment implements AddActionInterface {
#Override
public void onAddButtonClicked() {
if (isAdded() && isVisible()) {
executeAction();
}
}
protected abstract void executeAction();
}
Then we will call our Interface object like this in the activity. Create a List like below,
List<AddActionInterface> listeners = new ArrayList<AddActionInterface>();
and add your fragment to the list inside the view pager as,
listeners.add(fragment);
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, fragment, tag).commit();
Simply call the below in the onOptionsItemSelected method.
if (item.getItemId() == R.id.action_add) {
for (AddActionInterface listener : listeners) {
listener.onAddButtonClicked();
}
}
What the above method does is calls the onAddButtonClicked() method which is implemented in the BaseFragment.
Trick here is that every time the button in the action bar is clicked it will pass the control to the BaseFragment which checks if the current fragment is still attached then will call the executeAction() method of the respective fragment which being abstract every fragment can have their own implementation.
So say for FragmentA you will simply have to extend it from BaseFragment and override executeAction() method. You can write fragment specific implementations.
This process is called dependency inversion principle. See if you can put all these pieces in right place else let me know. :) Wow this is huge. :)
On the viewpager class:
public void validate() {
for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
Fragment fragment = mSectionsPagerAdapter.getItem(i);
if(!(fragment instanceof Validetable)) {
return;
}
Validetable validetable = (Validetable) mSectionsPagerAdapter.getItem(i);
Fragment invalidFragment = validetable.validate();
if (invalidFragment == null) {
Toast.makeText(getActivity(), "valido", Toast.LENGTH_LONG).show();
}
else {
mViewPager.setCurrentItem(i);
break;
}
}
On each fragment you do:
public static boolean isValid = true;
#Override
public Fragment validate() {
if ( StringUtils.isBlank(ColetaLocal.getInstance().getNivel())) {
isValid = false;
return this;
}
isValid = true;
return null;
}
#Override
public void onResume () {
super.onResume();
treatErrorsShowing();
}
private void treatErrorsShowing() {
if (!isValid) {
showErrors();
}
else {
clearErrors();
}
}
I ended up validating each Fragment before moving to the next one.
Reason:
The initial idea was to validate on save, and if there was an Fragment with invalid data, move to that fragment and show the errors. But since there is no way to determine the state of Views inside a Fragment if it is not visible, you cannot validate input.
How to define a Backpress Action in
class thats extends Fragment implements ActionBar.TabListener, how to define a backpressed action?
Fragments don't have an onBackPressed() callback like Activities do. You can try making your Activity maintain (or obtain) a reference to the fragment and have it call the fragment from within onBackPressed().
Fragment code:
public boolean onBackPressed() {
// your special behavior here
// return true if you have consumed the back press
}
Activity code:
public void onBackPressed() {
MyFragment fragment = getFragmentManager().findFragmentById(/* some unique id*/);
// could alternatively use findFragmentByTag() using a unique String
if (fragment != null) {
if (fragment.onBackPressed()) return;
}
// back press not consumed; allow usual behavior
super.onBackPressed();
}
I've got 2 Fragments, Fragment A and Fragment B. I added Fragment B over Fragment A, by using FragmentTransaction().add, which means Fragment A is underlying Fragment B. Is there a way to change the data in Fragment A after I did something on Fragment B and pressed the Back button from Fragment B? I wish to have a generic way to notify the Fragment A. Because it may be another Fragment being overlaid. I tried using FragmentTransaction.replace() - it works fine for refreshing the previous page.
Just overwrite onBackPressed() in your activity and your fragment and do your required calls there.
More to callbacks / communication with other fragments can be found here:
Communicating with Other Fragments
public class FragmentA extends Fragment {
public void updateMyself(String updateValue){
Log.v("update", "weeee Fragment B updated me with" + updateValue);
}
}
public class FragmentB extends Fragment {
public Interface FragmentBCallBackInterface {
public void update(String updateValue);
}
private FragmentBCallBackInterface mCallback;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mCallback = (FragmentBCallBackInterface) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement FragmentBCallBackInterface");
}
//As an example we do an update here - normally you wouln't call the method until your user performs an onclick or something
letsUpateTheOtherFragment();
}
private void letsUpateTheOtherFragment(){
mCallback.update("This is an update!);
}
}
public class MyActivity extends Activity implements FragmentInterfaceB {
#Override
public void update(String updateValue){
FragmentA fragmentA = (FragmentA) getSupportFragmentManager().findFragmentById(R.id.article_fragment);
if (fragmentA != null) {
fragmentA.updateMyself(updateValue);
} else {
//replace the fragment... bla bla check example for this code
}
}
}