onclick event in fragment activity not working - android

I have a activity A in which I have a fragment.
In this activity Fragment changes to fragment A(default when activity A is called) or fragment B based on user input in activity A.
In both fragments A & B I have a button with on click listener. but this button works only for the first time when activity A is started.
when user changes fragment the button in those fragments stop responding to on click.
Please suggest what I need to do in order to make buttons in fragment A & B work when fragments are changed by user.
I am replacing fragments based on user input by this code:
fr = new FragmentOneDice();
FragmentManager fm = getFragmentManager();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.replace(R.id.fragment_place, fr);
fragmentTransaction.commit();
In fragment activity code is like this for on click listener button.
import android.app.Fragment;
import android.app.FragmentManager;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import java.util.ArrayList;
import java.util.Collections;
public class FragmentOneDice extends Fragment implements View.OnClickListener {
Button button1;
View view;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//Inflate the layout for this fragment
view = inflater.inflate(R.layout.activity_fragment_one, container, false);
button1 = (Button) view.findViewById(R.id.button_one);
button1.setOnClickListener(this);
return view;
}
#Override
public void onClick(View v) {
//MY CODE HERE
}

The problem was in my activity_main.XML, where I had defined <Fragment> as a placeholder for all fragments and had set one fragment as default. So when other fragment was loaded it was getting overlapped resulting in on click event on the button not working, I changed the <Fragment> to <FrameLayout> as a placeholder. And my problem was solved.

First You remember one thing,
fragment to fragment direct transaction,or fragment to fragment direct replacement is not possible. it is possible only throw the Activity.
Define a interface in your first fragment and make container Activity to implement that interface, so you can send your data from Fragment to Activity .In another hand create Second Fragment and define a interface in it. In Content Activity inside implemented methods of First Fragment interface on that define a Second Fragment ,here we assign a data to the second Fragment through interface.

Related

Previous activity visible under the new fragment

When I call fragment from activity then fragment calling successfully but some part of previous activity is on the top of in fragment, anyone help to correct the code
package com.example.newproject;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import static android.view.View.GONE;
public class ThankYouPageActivity extends AppCompatActivity {
Button thank_continue_btn,thank_track_btn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_thank_you_page);
getSupportActionBar().setTitle("Confirmation");
thank_continue_btn = findViewById(R.id.thank_continue_btn);
thank_track_btn = findViewById(R.id.thank_track_btn);
findViewById(R.id.thank_continue_btn).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FragmentManager fm = getSupportFragmentManager();
HomeFragment fragment = new HomeFragment();
fm.beginTransaction().replace(R.id.thanku_container, fragment).addToBackStack(null).commit();
set background to white in the root tag of your fragment's xml
background = "#FFFFFF"
The container of your Fragment must be overlapped by your Activity layouts. Please attach the layouts of your Activity and Fragment so that I can help you find your issue.
I had same issues , i fixed it by removing previous fragment while setting new fragment in oncreateview
container.removeAllViews(); before replacing the fragment
R.id.thanku_container - I think it is FrameLayout?
Make it full match_parent. Or set background color like activity.

Should I use a nested fragment for tabs in a fragment?

I have a Main Activity which uses an AHBottomNavigationView for a menu at the bottom of the screen. When a different menu item is clicked, it creates a new fragment corresponding to that menu item with logic like so (condensed switch statement for the simplicity of this question):
fragmentManager.beginTransaction().replace(R.id.content_id, New TheFragmentForTheTabClicked).commit();
Where content_id is the ID of the Main Activity's ConstraintLayout.
Within the fragment for my first navigation menu item, there are two more tabs (using TabLayout), which replace the screen space with another fragment. This is done with a FragmentPagerAdapter, which is set onto a ViewPager, so tapping each tab changes the sub fragment. So at this point, there is a fragment nested in a fragment nested in a class. Here is what it generally is:
Main Activity
|
+-- Fragment 1 (selected from AHBottomNavigationView)
| |
| +-- Sub-Fragment 1 (selected by clicking the first tab in Fragment 1)
| |
| +-- Sub-Fragment 2 (selected by clicking the second tab in Fragment 1)
|
+-- Fragment 2 (selected from AHBottomNavigationView)
|
+-- Fragment 3 (selected from AHBottomNavigationView)
|
+-- Fragment 4 (selected from AHBottomNavigationView)
So my question is this:
Is the way I am doing this correct, and if not, what would a better way be?
Also, I'm finding that When I tab to Fragment 1 the first time, the swiping and tapping between the two tabs works fine, however if I tap a different bottom navigation menu item (i.e. Fragment 3) and then go back, I get the following 2 issues:
The content in either of the subfragments is not shown
Swiping between the two tabs no longer works. Instead of one motion moving to the different tab, I have to pull across the screen entirely because the indicator gets "stuck" part way between two tabs.
If there is any more information that I can provide, please let me know and I will.
Fragment1.java:
package com.mypackage.mypackage;
import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* A simple {#link Fragment} subclass.
*/
public class Fragment1 extends Fragment {
private FragmentActivity mContext;
public Fragment1() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_1, container, false);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
// Find the view pager that will allow the user to swipe between fragments
ViewPager viewPager = (ViewPager) getView().findViewById(R.id.viewpager);
// Create an adapter that knows which fragment should be shown on each page
// using getFragmentManager() will work too
Fragment1PagerAdapter adapter = new Fragment1PagerAdapter(mContext.getSupportFragmentManager(), mContext);
// Set the adapter onto the view pager
viewPager.setAdapter(adapter);
TabLayout tabLayout = (TabLayout) getView().findViewById(R.id.sliding_tabs);
tabLayout.setupWithViewPager(viewPager);
}
/**
* Override to set context. This context is used for getSupportFragmentManager in onCreateView
* #param activity
*/
#Override
public void onAttach(Activity activity) {
mContext=(FragmentActivity) activity;
super.onAttach(activity);
}
}
fragment_1.xml
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="#+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed"
app:tabBackground="#color/fragment1TabBackground"
app:tabIndicatorColor="#color/fragment1TabIndicatorColor"/>
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"/>
</LinearLayout>
</android.support.constraint.ConstraintLayout>
Fragment1PagerAdapter.java
package com.mypackage.mypackage;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.content.Context;
public class Fragment1PagerAdapter extends FragmentPagerAdapter {
private Context context;
public Fragment1PagerAdapter(FragmentManager fm, Context mContext){
super(fm);
context = mContext;
}
#Override
public Fragment getItem(int position){
if (position == 0){
return new SubFragment1();
}
else{
return new SubFragment2();
}
}
#Override
public int getCount() {return 2;}
#Override
public CharSequence getPageTitle(int position) {
switch(position){
case 0:
return context.getResources().getString(R.string.sub_fragment_1_page_title);
case 1:
return context.getResources().getString(R.string.sub_fragment_2_page_title);
default:
return null;
}
}
}
When nesting Fragments inside Fragment with ViewPager and swipe feature as FragmentManager which needs to be provided to Adapter recommended is to use: getChildFragmentManager() instead of getSupportFragmentManager() or getFragmentManager(). Because both are actually related to Activities instead of getChildFragmentManager(), as documentation says, is related to Fragment:
Return a private FragmentManager for placing and managing Fragments
inside of this Fragment.

OnListItemClick Shift from one ListFragement to Another using fragment Transactions

I have a list fragment from where when any list item is clicked, I want to move to another list fragement.
import java.util.Arrays;
import java.util.List;
import android.os.Bundle;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.ListFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
public class Schedule extends ListFragment{
....
....
public void onListItemClick(ListView l, View v, int position, long id) {
....
android.support.v4.app.FragmentManager fragmentManager = getFragmentManager();
android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
DailyList fragment = new DailyList();
fragmentTransaction.replace(R.id.list_fragment, fragment);
fragmentTransaction.commit();
}
This is the new class that I am trying to move to.
public class DailyList extends ListFragment {
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState){
final View theInflatedView = inflater.inflate(R.layout.day, container, false);
return theInflatedView;
}
....
....
....
}
I tried using v4 android support libraries. but the replace call is giving me this error "The method replace(int, Fragment) in the type FragmentTransaction is not applicable for the arguments (int, DailyList)".
I read few other answers that asked to use v4. That is what I am doing. But still getting error. Please help me out here. Thanks!
I think you are mixing newer fragment support types with support classes. Replace these lines:
import android.app.Fragment;
import android.app.FragmentManager;
with:
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
Then extend 
android.support.v4.app.FragmentActivity
 instead of 
Activity
 and change calls like 
getFragmentManager()
 with 
getSupportFragmentManager()
 and similarly for other methods that you might be using.

Adding extended fragment to Activity

I have been trying to build a Master-Detail f low in android but wanted to change one of the detail fragments to a different fragment. As this is one of my first Android applications, I was just trying to make a picture appear on this new fragment. For this, I built the following two classes
1) Fragment class ( displays the picture to be displayed )
package com.userName.miscapp;
import com.userName.miscapp.dummy.DummyContent;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class PictureFragment extends Fragment {
// Default Copy Constructor for the fragment
public PictureFragment() {
}
#Override
public void onCreate ( Bundle savedInstanceState )
{
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView ( LayoutInflater inflater , ViewGroup container , Bundle savedInstanceState )
{
View rootView = inflater.inflate(R.layout.fragment_simple_picture, container, false);
return rootView;
}
}
2) Activity to display the same
package com.userName.miscapp;
import android.os.Bundle;
import android.app.Activity;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.view.Menu;
public class SimplePicture extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActionBar().setDisplayHomeAsUpEnabled(true);
if (savedInstanceState == null) {
// Create the detail fragment and add it to the activity
// using a fragment transaction.
Bundle arguments = new Bundle();
arguments.putString(ItemDetailFragment.ARG_ITEM_ID,
getIntent().getStringExtra(ItemDetailFragment.ARG_ITEM_ID));
PictureFragment frag = new PictureFragment();
frag.setArguments(arguments);
android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.simple_picture_container,frag).commit();
//setContentView(R.layout.activity_simple_picture);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.simple_picture, menu);
return true;
}
}
On compilation, it does not recognize the PictureFragment to be an extension of Fragment class. This is inspite of it being clearly written in the first file. Searching for solutions on Stackoverflow said to extend FragmentActivity instead of Activity and trying to use getSupportFragmentManager() neither of which helped.
PS : Using 11 as the base for the current application.
Any help would be appreciated
Thanks
This is because you are using android.app.Fragment from new API in conjunction with android.support.v4.app.FragmentManager from support library, you should replace import in your PictureFragment from android.app.Fragment to android.support.v4.app.Fragment to make it work.

Fragments: Remove all fragments in a view

The scenario I am faced with, is in my application I have a single pane and dual pane style layout. Rather than individually handle every single navigation operation possible between the screens, for every different style of layout, I am using a function which sets up the layout correctly when given the desired screen.
It is basically a switch statement for each screen in the app, with a nested switch statement in each screen to handle each layout style. This is what I'm talking about in code:
protected void setupScreen() {
switch(currentScreen) {
case SCREEN_ONE:
switch(currentLayout) {
case SINGLE_PANE:
// Perform actions to setup the screen
break;
case DUAL_PANE:
// Perform actions to setup the screen
break;
}
break;
case SCREEN_TWO:
switch(currentLayout) {
case SINGLE_PANE:
// Perform actions to setup the screen
break;
case DUAL_PANE:
// Perform actions to setup the screen
break;
}
break
// ... etc ....
}
}
In the section where I want to perform the actions to setup the screen, this consists of the following basic three operations:
// Create the fragments if necessary
if (screenFragment == null) {
screenFragment = new myFragment();
}
// Remove the existing fragments from the layout views
// HOW???
// Add the fragments for this screen to the view
getSupportFragmentManager().beginTransaction().add(pane1.getId(), myFragment, "myFragment").commit();
As you can see, what I am struggling with is how to do the second step. How do you remove all Fragments from a given View without knowing exactly which ones you are wanting to remove? The closest I have found is FragmentTransaction.replace() which does successfully do this for every case but when it turns out you are replacing a Fragment with the same fragment. In this case, it does not remove all, then add (like the documentation suggests), it just seems to remove. Is this an issue with using the compatibility libraries or is it not the way FragmentTransaction.replace() should be used?
In any case, how should I go about doing this? Do I have to code a removeAllFragments() function to go through every fragment and detach it or is there a way to do the first half of what the 'two in one' FragmentTransaction.replace() function claims to do?
None of the other answers were really working for me. Here's what I did:
List<Fragment> al = getSupportFragmentManager().getFragments();
if (al == null) {
// code that handles no existing fragments
return;
}
for (Fragment frag : al)
{
// To save any of the fragments, add this check.
// A tag can be added as a third parameter to the fragment when you commit it
if (frag == null || frag.getTag().equals("<tag-name>")) {
continue;
}
getSupportFragmentManager().beginTransaction().remove(frag).commit();
}
or, if you're forced to use it (but not recommended):
.commitAllowingStateLoss();
Also, if you're removing all fragments from the view multiple times, you might consider checking if the current frag is null or isDetached() or isRemoving() or you might get NullPointerExceptions.
Update: The documentation for getSupportFragmentManger().getFragments() is apparently hidden now, but still works just fine in my code. Here's the screenshot of the documentation:
Having said that, since it is hidden, they no longer want this method used, so see my update below.
Update 8-4-15: If you're not using the support library for fragments, there is unfortunately no getFragments() available, but there are still a couple, more inconvenient, options.
Give each fragment a tag or id upon creation, and iterate through them to process each fragment as desired.
Create a listener using onAttachListener so each time a new fragment is attached to the activity, you can store that fragment, and then iterate through that data structure to process each fragment as desired.
When not using the getSupportFragmentManager(), to process a transaction you will need to use getFragmentManager() instead.
The typical mechanism is to use FragmentManager.findFragmentByTag() . You use this and add tags to your fragments (or the alternative for id's). This way you can determine what fragments are currently being managed. Then, once you have a handle to a present fragment (findFragmentByTag returns non-null), you can use FragmentManager.beginTransaction() to start a FragmentTransaction and remove / add the necessary fragments. Working in this way will allow you to avoid the 're-adding' process for the fragment you want to keep.
What I'd probably do is have code like so: (warning psuedo code)
Fragment pane1 = FragmentManager.findFragmentByTag("myFragmentPane1");
Fragment pane2 = FragmentManager.findFragmentByTag("myFragmentPane2");
setupScreen(pane1, pane2);
You should also consider sub-classes of your class instead of having 'everything in one class'. You have a fairly obvious case of Martin Fowler's Replace Conditional with Subclass. Otherwise, I fear this is going to be incredibly hard to manager when you add another screen.
If you use android.support.v4.app.Fragment you can do this:
List<Fragment> fragments = getSupportFragmentManager().getFragments();
if (fragments != null) {
for (Fragment fragment : fragments) {
getSupportFragmentManager().beginTransaction().remove(fragment).commit();
}
}
Turns out FragmentTransaction.replace() is the correct operation and should work correctly. It only does not work when using ActionBarSherlock and SherlockFragmentActivity so I can only assume it is a bug in this compatibility library.
I have confirmed this through using the code below to implement the desired behaviour through Android on API11+, the android compatibility library, and ActionBarSherlock. It only breaks in the last instance.
package com.test.test;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import android.os.Bundle;
import android.content.Context;
import android.graphics.Color;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;
public class MainActivity extends SherlockFragmentActivity {
// Consistent fragment instance
myFragment myFrag = null;
// Views
FrameLayout fl = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.VERTICAL);
Button b = new Button(this);
b.setText("Repeat");
b.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// Reattach the same fragment
getSupportFragmentManager().beginTransaction().replace(fl.getId(), myFrag).commit();
}
});
fl = new FrameLayout(this);
fl.setId(200);
fl.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
myFrag = new myFragment();
getSupportFragmentManager().beginTransaction().add(fl.getId(), myFrag).commit();
ll.addView(b);
ll.addView(fl);
setContentView(ll);
}
public static class myFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
TextView tv = new TextView(getActivity());
tv.setText("My fragment");
tv.setGravity(Gravity.CENTER);
tv.setBackgroundColor(Color.RED);
return tv;
}
}
}
This is more or less how I have handled this. Have all your fragments implement an interface something like:
public interface NamedFragment{
public FragmentName getFragmentName();
}
Make an enum corresponding to your fragments:
public enum FragmentName{
SOME_FRAGMENT,
SOME_OTHER_FRAGMENT;
}
Then in your fragment switching activity:
// Get the manager and transaction separately so you can use both:
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
// Get a reference to the fragment(s) currently in the container(s)
Fragment currentFragment = fragmentManager.findFragmentById(position);
FragmentName cFragmentName =
((NamedFragment) currentFragment).getFragmentName();
Fragment nextFragment =
Fragment.instantiate(this, some_new_fragment_string);
FragmentName nFragmentName =
((NamedFragment) nextFragment).getFragmentName();
// Compare the "names"
if(cFragmentName != nFragmentName){
ft.replace(position, nextFragment);
}
You'll have to change things around a little to fit your particulars.

Categories

Resources