I am having a fragment that contains for example one button, I want to allow the Activity containing the fragment to change this button view like for example color and title or src Image.
What's the best way to do that ?
Update : sorry If I wasn't clear enough but I want the activity to change the whole view as it's likes , like setting the padding, the color or anything.
It will create the view programmatically and the fragment should replace the old view by the new one and change the view's ID so that the fragment code isn't affected. And If i created methods in the fragment that takes these views when should the Main activity call them ? since the activity has to wait for the layout of the fragment to be created.
1. You must get you fragment from your activity
val fragment = supportFragmentManager.findFragmentByTag("tag")
or
val fragment = supportFragmentManager.findFragmentById(R.id.fragment)
2. Create a method that will do what you wants in you fragment and call this method from the activity
fragment.hideButton()
or you can use interface
Try this way according to your requirement
public abstract class BaseFragment extends Fragment {
BaseActivity yourActivity;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
yourActivity = (BaseActivity) context;
}
#Override
public void onDetach() {
yourActivity = null;
super.onDetach();
}
public void refreshview(){}
public void setDada(Data data){}
#override
publicn void onStart(){
yourActivity.setCurrentOpenedFragment(this);
}
}
Create the BaseActivity class
public abstract class BaseActivity extends AppCompatActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void setCurrentOpenedFragment(BaseFragment currentFragment){}
}
Extends the BaseFragment in your fragment i.e.
public class YourFragment extends BaseFragment{
View view;
Button button;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment, container, false);
button = (Button)view.findViewById(R.id.button);
return view;
}
#override
publicn void onStart(){
super.onStart();
//yourActivity.setCurrentOpenedFragment(this);
}
Data data;
#override
public void setDada(Data data){
this.data = data;
}
#Override
public void refreshview() {
button.setcolor(data.getcolor());
}
}
Write the below line of code in your Activity class
public class YourActivity extends BaseActivity{
public static final byte NONE = -1;
public static final byte HOME = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_activity);
changeFragment(new YourFragment(), HOME);
initview();
}
public void initview(){
Button b = (Button)findViewById(R.id.button);
b.setOnClickListener(new OnClickListener(){
if(currentFragmentOnDrawer != null){
Data data = new Data();
data.setColor(getResource().getcolor(R.color.red));
currentFragmentOnDrawer.setDada(data);
currentFragmentOnDrawer.refreshview()
}
});
}
BaseFragment currentFragmentOnDrawer;
#Override
public void setCurrentOpenedFragment(BaseFragment currentFragment) {
super.setCurrentOpenedFragment(currentFragment);
this.currentFragmentOnDrawer = currentFragment;
}
public void changeFragment(Fragment targetFragment, byte state) {
FragmentTransaction ft = getSupportFragmentManager()
.beginTransaction();
ft.replace(R.id.main_fragment, targetFragment, "" + state);
ft.addToBackStack("" + state);
ft.commit();
}
}
Hope it will help for you
Related
So basically, i have an activity called (Profile Activity) and two fragments connected to it (Profile view and profile edit fragment). Since im completely new with android studio, java language and fragments, im trying to place both fragments into activity but in a way that only profile view fragment is shown. Edit profile fragment needs to be hidden. Im using next part of the code:
getSupportFragmentManager().beginTransaction().add(R.id.profile_fragment, profileViewFragment).commit();
getSupportFragmentManager().beginTransaction().add(R.id.profile_fragment, profileEditFragment).commit();
I already tried something with "hide" and "show", but with no success. I have imported "android.support.v4.app.FragmentManager;" Thank you.
EDIT:
Profile activity after implementing new code:
public class ProfileActivity extends AppCompatActivity implements ProfileViewFragment.ProfileViewListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
//ovo ispod je za proslijedivanje iz activita u fragment
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
ProfileViewFragment profileViewFragment = new ProfileViewFragment();
ProfileEditFragment profileEditFragment=new ProfileEditFragment();
profileViewFragment.setArguments(getIntent().getExtras());
profileEditFragment.setArguments(getIntent().getExtras());
//getSupportFragmentManager().beginTransaction().add(R.id.profile_fragment, profileEditFragment).commit();
getSupportFragmentManager().beginTransaction().add(R.id.profile_fragment, profileViewFragment).commit();
//getSupportFragmentManager().beginTransaction().replace(R.id.profile_fragment, profileViewFragment).commit();
//FragmentManager fm=getSupportFragmentManager();
//fm.beginTransaction().setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out).show(new ProfileViewFragment()).commit();
//fm.beginTransaction().setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out).show(new ProfileEditFragment()).commit();
//-----------------------------------
}
#Override
public void onOpenProfileEditor() {
ProfileEditFragment profileEditFragment=new ProfileEditFragment();
profileEditFragment.setArguments(getIntent().getExtras());
getSupportFragmentManager().beginTransaction().replace(R.id.profile_fragment, profileEditFragment).commit();
}
#Override
public void onAttachFragment(Fragment fragment) {
if (fragment instanceof ProfileViewFragment) {
ProfileViewFragment profileFragment = (ProfileViewFragment) fragment;
profileFragment.setListener(this::onOpenProfileEditor);
}
}
}
Profile view fragment with new code:
public class ProfileViewFragment extends Fragment {
private Unbinder unbinder;
//novi kod sa stacka
private ProfileViewListener listener;
//-------------
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
FragmentProfileViewBinding viewBinding=DataBindingUtil.inflate(inflater, R.layout.fragment_profile_view, container, false);
View view=viewBinding.getRoot();
unbinder = ButterKnife.bind(this, view);
UserModel user = (UserModel) getArguments().get(ModelEnum.UserModel.name());
//viewBinding povezuje fragment i xml (proslijeduje user)
viewBinding.setUser(user);
//viewBinding.setUserGender(user);
return view;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
// #OnClick(R.id.btn_change_settings)
// public void changeSettings(){
//getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.profile_fragment, new ProfileEditFragment()).commit();
// }
#Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
//ISPOD JE NOVI KOD SA STACK OVERFLOWA
public interface ProfileViewListener{
void onProfileEditor();
}
public void setListener(ProfileViewListener listener) {
this.listener = listener;
}
#OnClick(R.id.btn_change_settings)
public void onEdit(View view){
if(listener!=null){
onOpenProfileEditor();
}
}
}
Instead of
getSupportFragmentManager().beginTransaction().add(R.id.profile_fragment, profileEditFragment).commit();
It must be
getSupportFragmentManager().beginTransaction().replace(R.id.profile_fragment, profileEditFragment).commit();
This will replace your fragment, instead of adding it.
Please, also note that you must call "add" for the first time and use "replace" afterwards.
You may find more about fragments here: https://developer.android.com/training/basics/fragments/fragment-ui
EDIT
For the new issue you have outlined, the solution is to "report" you activity that an event had happened, so it can take action. Here is how to do that.
First, we need an interface (you can add it inside you Profile fragment) and to link the activity to our fragment, if it implements that interface.
public class ProfileViewFragment extends Fragment {
...
...
private ProfileViewListener listener;
...
...
#OnClick(R.id.btn_change_settings)
public onEdit(View view) {
// If there is anyone listening, report that we need to open editor
if (listener != null) {
listener .onOpenProfileEditor();
}
}
public void setListener(ProfileViewListener listener) {
this.listener = listener;
}
// The interface
public interface ProfileViewListener {
void onOpenProfileEditor();
}
}
And in the class, we need to implement the interface and subscribe as a listener.
public class ProfileActivity extends AppCompatActivity implements ProfileViewFragment.ProfileViewListener {
...
...
#Override
public void onOpenProfileEditor() {
ProfileEditFragment profileEditFragment=new ProfileEditFragment();
profileEditFragment.setArguments(getIntent().getExtras());
getSupportFragmentManager()
.beginTransaction
.replace(R.id.profile_fragment, profileEditFragment)
.commit();
}
#Override
public void onAttachFragment(Fragment fragment) {
if (fragment instanceof ProfileViewFragment) {
ProfileViewFragment profileFragment = (ProfileViewFragment) fragment;
profileFragment.setListener(this);
}
}
}
You may find more detail on Activity-Fragment communication here - https://developer.android.com/training/basics/fragments/communicating
I'm going from a Fragment -> Activity. In the activity I make an interface and when the user clicks a button I pass in a string to an interface object I create and call finish(). In the fragment I implement that interface and want to get that string. But in the activity I get a crash saying the listener is null.
public class SampleActivity extends AppCompatActivity
{
private Button button;
private MatchActivity.OnMatchCompleteListener onMatchCompleteListener;
public interface OnMatchCompleteListener
{
public void matchComplete(String matchID);
}
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.someButton);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onMatchCompleteListener.matchComplete("finished");
finish();
}
});
}
}
Fragment
public class SampleFragment extends Fragment implements SampleActivity.OnMatchCompleteListener{
private View rootView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_login , container, false);
return rootView;
}
#Override
public void matchComplete(String matchID) {
Log.d("TEST",matchID);
}
}
if you have your fragment in the R.layout.activity_main and your fragment id is R.id.fragment use this:
onMatchCompleteListener =
((SampleFragment)getFragmentManager().findFragmentById(R.id.fragment))
otherwise use this solution:
SampleFragment fragment = new SampleFragment();
onMatchCompleteListener = fragment;
getFragmentManager().beginTransaction().add(R.layout.activity_main, fragment, "TAG_SIMPLE").commit();
I have a Fragment that displays a list using my class ListRecyclerViewAdapter that extends RecyclerView.Adapter:
public class ListFragment extends Fragment {
private ListRecyclerViewAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
adapter = new ListRecyclerViewAdapter(context, itemsToDisplay);
...
}
public ListRecyclerViewAdapter getListAdapter() {
return adapter;
}
}
When I try to get the Adapter from an Activity that has the above Fragment, I get null:
public class DataActivity extends FragmentActivity {
#Override
protected void onResume() {
super.onResume();
listFragment = new ListFragment(itemsToDisplay);
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_list_container, listFragment).commit();
ListRecyclerViewAdapter wantedAdapter = listFragment.getAdapter();
}
}
Why is that? It looks to me like the Fragment's method onCreateView() was not called at the point when I call listFragment.getAdapter().
Fragment is not created when you are trying to call the method.So check is the fragment is attached before accessing the adapter.
public ListRecyclerViewAdapter getListAdapter() {
if(this.isAdded() && adapter!=null){
return adapter;
}
return null;
}
Also load the fragment in oncreate of activity and call the adpter reference method in onresume
public class DataActivity extends FragmentActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listFragment = new ListFragment(itemsToDisplay);
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_list_container, listFragment).commit();
}
#Override
protected void onResume() {
super.onResume();
ListRecyclerViewAdapter wantedAdapter = listFragment.getAdapter();
}
}
As soon as it created, it called listfragment adapter. so, the UI creation will take some time , but the flow flowed to that line. so it return null. you can acheive this in following way.
public class ListFragment extends Fragment {
LoadAdapter loadAdapter;
private ListRecyclerViewAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
adapter = new ListRecyclerViewAdapter(context, itemsToDisplay);
...
}
public ListRecyclerViewAdapter getListAdapter() {
return adapter;
}
interface LoadAdapter {
public void onAdapterLoaded();
}
public void setOnAdapterLoad(LoadAdapter loadAdapter){
this.loadAdapter = loadAdapter;
}
#Override
public void onResume(){
loadAdapter.onAdapterLoaded();
}
}
Now the activity code as follows:
public class DataActivity extends FragmentActivity {
#Override
protected void onResume() {
super.onResume();
listFragment = new ListFragment(itemsToDisplay);
listFragment.setOnAdapterLoad(new LoadAdapter(){
#Override
public void onAdapterLoaded(){
ListRecyclerViewAdapter wantedAdapter = listFragment.getAdapter();
}
});
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_list_container, listFragment).commit();
}
}
Hope this helps.
I was able to create a single event callback from a fragment to the activity. However, I have problem with creating two event callbacks from the same fragment.
Basically, I have a button on the fragment1 layout, when click on it, it will execute something in mainactivity, and then, it changes hide the Button at fragment1 layout, and then I need to send a Boolean from the fragment to activity, then initiate fragment2.
How can I implement the 2nd callback interface in the mainacativity.
Here is my code:
at Fragment1:
public class Fragment1 extends Fragment{
private static final String TAG = "Fragment1";
Boolean in1, in2;
Button btn1;
ListenerA mListenerA;
public interface ListenerA{
public void methodA(Boolean in1);
};
ListenerB mListenerB;
public interface ListenerB{
public void methodB(Boolean in2);
};
#Override
public void onAttach(Context context) {
super.onAttach(context);
if(context instanceof ListenerA)
mListenerA = (ListenerA)context;
if(context instanceof ListenerB)
mListenerB = (ListenerB)context;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View myView = inflater.inflate(R.layout.fragment1, container, false);
btn1 = (Button) myView.findViewById(R.id.btn1_ID);
btn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mListenerA.methodA(true);
}
});
return myView;
}
public void showBtnMethod (Boolean showBtn){
if (showBtn==false) {
btn1.setVisibility(View.INVISIBLE);
mListenerB.methodB(true); //***** problematic line
}
}
}
and the code in the main activity is below. please note that on the first line I was able only to implement one method from the fragment.
public class MainActivity extends AppCompatActivity implements Fragment1.ListenerA {
private static final String TAG = "MainActivity";
public Fragment1 mFragment1;
public Fragment2 mFragment2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
FragmentTransaction transaction1 = getSupportFragmentManager().beginTransaction();
mFragment1 = new Fragment1();
transaction1.replace(R.id.content_fragment_ID, mFragment1);
transaction1.commit();
}
}
// this gets called by ListenerA when click on the button
public void methodA(Boolean in){
if (in==true){
Toast.makeText(MainActivity.this, "mMethodA Executed", Toast.LENGTH_SHORT).show();
triggerShowMethod();
}
};
private void triggerShowMethod(){
mFragment1.showBtnMethod(false);
};
// Problematic section is below
public void methodB(Boolean in){
if (in==true){
FragmentTransaction transaction2 = getSupportFragmentManager().beginTransaction();
mFragment2 = new Fragment2();
transaction2.replace(R.id.content_fragment_ID, mFragment2);
transaction2.commit();
Toast.makeText(MainActivity.this, "mMethodB Executed", Toast.LENGTH_LONG).show();
}
};
}
You can simply consolidate both interfaces into one:
public interface Listener{
public void methodA(Boolean in1);
public void methodB(Boolean in2);
};
and in your MainActivity:
public class MainActivity extends AppCompatActivity implements Fragment1.Listener
Your activity doesn't implement ListenerB.
public class MainActivity extends AppCompatActivity implements Fragment1.ListenerA, Fragment1.ListenerB {
}
I have an Activity that starts a Fragment. Inside that fragment i have an EditText. And when i get the text that the user types there, i want to get that from my Activity with the help of an interface. I'm using this guide
On my MainActivity i'm implementing the commentListener interface and i've managed to get the result inside the onCommentEntered method. But on doneListener, which is triggered when the user presses a button finishing the activity, i'm getting null.
Obviously onCommentEntered runs after doneListener.
Any suggestions on how to get the result on doneListener?
class MainActivity implements fragment.commentListener{
static String comment;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.addtransaction);
done=(TextView)findViewById(R.id.done_button);
}
// called when user presses a button and MainActivity finishes.
public void doneListener(View v){
// Here i get NULL
System.out.println(comment);
finish();
}
#Override
public void onCommentEntered(String data) {
comment=data;
// Here i get what the user typed
System.out.println(comment);
}
}
My fragment
public class thefragment extends Fragment {
commentListener cListener;
static TextView note;
EditText comment;
public interface commentListener{
void onCommentEntered(String data);
}
public static thefragment newInstance(){
return new thefragment ();
}
public thefragment (){
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
cListener=(commentListener) context;
}
#Override
public void onDetach() {
super.onDetach();
cListener=null;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v;
v=inflater.inflate(R.layout.fragment, container, false);
comment=(EditText)v.findViewById(R.id.comment_picker);
comment.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
cListener.onCommentEntered(comment.getText().toString());
}
}
});
return v;
}
}
Create a new Interface, as well as implement the same in Fragment. create a method in the interface and override the same in Fragments. While calling the fragment from Activity create an Interface type fragment and call the interface method.
eg:
public class thefragment extends Fragment implement fragmentNofyInterface {
...
#Override
protected void notify(String txt){
mTvTxt.setText(txt);
}
.....
}
Interface Format
public interface fragmentNofyInterface {
protected void notify(String txt);
}
Activity format
class MainActivity implements fragment.commentListener{
.....
private fragmentNofyInterface mFragmentNotifier;
.........
thefragment mFragment = new thefragment();
mFragmentNotifier = (fragmentNofyInterface ) mFragment;
FragmentTransaction transaction = mFragmentMngr.beginTransaction().
add(R.id.rl_fragment_navigation_container,
mFragment);
transaction .commit();
......
//Notify the fragment when you required
mFragmentNotifier.notify("hello world");
}
Switching to addTextChangedListener and TextWatcher for my EditText, like this here,
seems to fix my problem.Now onCommentEntered method is called before doneListener and thus String commentgets whatever was typed in the EditText.Thanks everyone for helping.