I am trying to use Bundle to send data from an activity to a fragment. The activity is receiving the input from a dialogbox when the user clicks on the actionbar add icon. The button also opens the dialogbox but it sends the data straight to the fragment (I'm trying to learn the difference between activity and fragment and to interact with the dialogfragment). None of the solutions on the internet have worked for me, and I was hoping someone can help
I have provided a visualization to aid in my explanation of the issue. So initially, I click the action add icon that opens the dialogbox (2nd pic), when I enter an input, it doesn't alter the data on the fragment. Only when I press the action add icon for a second time, does the first input get updated (3rd pic). Also you may notice that it says "Bundle{[Dialog Input = First Input]}" where First Input is the user input. How do I change this to just, First Input. I tried clearing the textview before setting the value, but that doesn't work. Now lastly when I press the button, it opens the dialogbox and when I enter in data, the data from the action add icon (handled in activity then data sent to fragment) overlaps with the data from the button (data sent straight to fragment). Any help would be appreciated. Thanks in advance.
MainActivity:
public class MainActivity extends AppCompatActivity implements
MyCustomDialog.OnInputSelected{
public String dialogInput;
FragmentManager fragmentManager;
#Override
public void sendInput(String input) {
dialogInput = input;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragmentManager = getSupportFragmentManager();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
//Inflate the menu, this adds items to the action bar if it is present
getMenuInflater().inflate(R.menu.menu, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
//Handle action bar clicks here. The action bar will automatically handle clicks on the home/up button
//so long as you specify a parent activity in AndroidManifest.xml
switch(item.getItemId()){
case R.id.action_add:
MyCustomDialog dialog = new MyCustomDialog();
dialog.show(getSupportFragmentManager(), "MyCustomDialog");
//Trying Bundle to pass data, dialog input between activity and fragment
Bundle bundle = new Bundle();
bundle.putString("Dialog Input", dialogInput);
//Set Fragment class arguments
MainFragment fragment = new MainFragment();
fragment.setArguments(bundle); //set argument bundle to fragment
fragmentManager.beginTransaction().replace(R.id.MainFragment,fragment).commit(); //now replace Mainfragment
Toast.makeText(this, "Action_Add Clicked Successfully", Toast.LENGTH_SHORT).show();
}
return super.onOptionsItemSelected(item);
}
}
MainFragment:
public class MainFragment extends Fragment implements MyCustomDialog.OnInputSelected{
TextView InputDisplay;
Button OpenDialog;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
InputDisplay = view.findViewById(R.id.InputDisplay);
OpenDialog = view.findViewById(R.id.Open_Dialog);
//Getting Main Activity dialog information with Bundle, that was received from toolbar add
Bundle bundle = getArguments();
if(bundle != null){
String dialogInput = bundle.toString();
//Clearing since Fragment call and activity call overlap each other.
InputDisplay.setText("");
InputDisplay.clearComposingText();
InputDisplay.setText(dialogInput);
}
//String dialogInput = this.getArguments().getString("Dialog Input");
OpenDialog.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.d("MainFragment", "onClick: opening dialog");
MyCustomDialog customDialog = new MyCustomDialog();
customDialog.setTargetFragment(MainFragment.this, 1);
customDialog.show(getFragmentManager(), "MyCustomDialog");
}
});
return view;
}
#Override
public void sendInput(String input) {
InputDisplay.setText("");
InputDisplay.setText(input);
}
}
My Custom Dialog:
public class MyCustomDialog extends DialogFragment {
private EditText Input;
private TextView ActionOK, ActionCANCEL;
private OnInputSelected onInputSelected;
public interface OnInputSelected{
void sendInput(String input);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try{
Fragment onInputSelected_fragment = getTargetFragment();
Activity onInputSelected_activity = getActivity();
if(onInputSelected_fragment != null){
onInputSelected = (OnInputSelected) onInputSelected_fragment;
}else{
onInputSelected = (OnInputSelected) onInputSelected_activity;
}
//throw new RuntimeException("Custom Dialog onAttach Listener was NULL");
}catch(ClassCastException e){
Log.e("Custom Dialog", "onAttach: ClassCastException: " + e.getMessage());
}
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dialog_my_custom, container, false);
Input = view.findViewById(R.id.Input);
ActionOK = view.findViewById(R.id.Action_OK);
ActionCANCEL = view.findViewById(R.id.Action_CANCEL);
ActionCANCEL.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
getDialog().dismiss();
}
});
ActionOK.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onInputSelected.sendInput(Input.getText().toString());
getDialog().dismiss();
}
});
return view;
}
}
How do I change this to just, First Input.
your output is printed like this "Bundle{[Dialog Input = First Input]}" because you are directly doing bundle.toString(); instead of getting the value you have stored in the bundle.
change the above to this
String dialogInput = bundle.getString("Dialog Input")
InputDisplay.setText(dialogInput);
the data from the action add icon overlaps with the data from the button
Clear the existing text in the text view before setting the new value like this
String dialogInput = bundle.getString("Dialog Input")
InputDisplay.setText(");
InputDisplay.setText(dialogInput);
Also, I noticed that all the variable names that you have used are not following camel case I suggest you correct that as well.
Related
I don't understand DialogFragment at all. How to create one, how to get the user input out of it, and set it into a TextView.
I would like for the TITLE button, when clicked, to bring up a DialogFragment asking the user to enter the title of their Mood Board. The user enters a title. When they click the PostiveButton "Done", the user's title is set into the top left frame of the mood board, which has a TextView with a hint.
Please! Ask questions, because I don't really understand the dialog setup.
Here is a picture of my main_layout, in my MainActivity. Every element has an "#+id/".
The solution you are looking for is a callback:
Create an interface with a method to use as a callback
Implements the interface on the activity
Create the dialog fragment and in onAttach get the interface
Show the dialog fragment on the activity
On dismiss the dialog fragment pass the text using the instance of the interface
interface Callback {
updateText(String text)
}
class CoolActivity... implements Callback
onCreate {
//find your views
showDialogBtn.setOnClickListener(...
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment prev = getSupportFragmentManager().findFragmentByTag("yourTag");
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);
DialogFragment dialogFragment = ExampleDialogFragment.newInstance();
dialogFragment.show(ft, "yourTag");
)
}
#Override
updateText(String text) {
youtView.setText(text)
}
class CoolDialogFragment extend DialogFragment {
private Callback callback;
#Override
void onAttach(Context context) {
callback = (Callback) context
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = new Dialog(getActivity());
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
return dialog;
}
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.dialog_fragment_example, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//find the views in the dialog fragment
closeBtn.clickListener(...
callback.updateText(edittext.getText().toString())
dismiss()
)
}
}
Here is a gist of a dialog fragment
https://gist.github.com/cutiko/7e307efcf7492ea52ef05cd90f9e3203
The problem is you want to connect a dialog fragment with a another component, and you want to do it straigth forward. This is not considered a good practice because yiu create 2 componentes higly attached, so the best would be to use data persistence and some form of react programming
You can make your mood board title textview static then call it to the alertdialog with edittext to set it text (setText)
like this.
final EditText edittext = new EditText(MainActivity.this);
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setMessage("Input Title")
.setView(edittext)
.setCancelable(false)
.setPositiveButton("Confirm", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
YourCustomDialog.your_title_textviewMoodboard.setText(edittext.getText().toString());
}
})
.setNegativeButton("Back", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
}
});
AlertDialog alert = builder.create();
alert.show();
in your custom dialog. declare your textview static globally
public static TextView your_title_textviewMoodboard;
I'm currently trying to make a fragment come into view over everything else in the activity. Then, on a button press, the fragment should disappear and reveal everything that was there previously.
Here is my current attempt:
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction()
.replace(currentFragment.getId(), fragment);
transaction.addToBackStack(null);
transaction.commit();
and on the button press, I do:
getFragmentManager().popBackStack();
But the issue I'm having it the fragment doesn't totally inflate overtop all the other views, and the button press is not having the desired affect. Any suggestions?
EDIT: It's a bottomNavigationView that's still showing, I'd like to inflate overtop of that.
You can use Dialog fragment like:
public class PopUpDialogFragment extends DialogFragment {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Context context = getActivity();
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Your title")
.setMessage("Your message")
.setPositiveButton("Button name", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//Do your stuff here
dismiss();
}
});
return builder.create();
}
}
Then you call it from your activity like:
PopUpDialogFragment fragment = new PopUpDialogFragment();
fragment.show(getFragmentManager(), "popUp");
If you want a Fragment with your own custom view then you create one with onCreateView method.
public class PopUpDialogFragment extends DialogFragment {
private Button button;
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup
container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.your_layout,
container, false);
button = view.findViewById(R.id.your_button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Do your stuff here
getDialog().dismiss();
}
});
return view;
}
}
I have a couple of fragments. But all the fragments lead to PeriodFragment when they press a button. My question is how do I implement so that when the user presses the BACK button on his mobile phone, the PeriodFragment will switch back to the fragment it was entered from.
This is the java code from PeriodFragment.java:
public class PeriodFragment extends Fragment {
Button btnPretrazi;
public PeriodFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_period, container, false);
//buttonPretraziPeriod
btnPretrazi = (Button) view.findViewById(R.id.buttonPretraziPeriod);
btnPretrazi.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getContext(),"test", Toast.LENGTH_SHORT).show();
}
});
return view;
}
}
This is my TvrdjavaFragment.java (one of the fragments that have the button to switch to PeriodFragment.java) :
package com.example.ivanp.msnis;
public class TvrdjavaFragment extends Fragment {
Button btnIdinaperiod;
public TvrdjavaFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_tvrdjava, container, false);
// Inflate the layout for this fragment
//show date
TextView datumprikaz = (TextView) view.findViewById(R.id.datumprikaz);
Date danas = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy");
String novDatum = sdf.format(danas);
datumprikaz.setText(novDatum);
//End of show date
btnIdinaperiod = (Button) view.findViewById(R.id.buttonIdinaperiod);
btnIdinaperiod.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
PeriodFragment periodFragment = new PeriodFragment();
FragmentTransaction periodFragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
periodFragmentTransaction.replace(R.id.frame, periodFragment);
periodFragmentTransaction.commit();
}
});
return view;
}
}
I'm new to android studio, so please tell the details.
According to android docs When using fragments in your app, individual FragmentTransaction objects may represent context changes that should be added to the back stack. For example, if you are implementing a master/detail flow on a handset by swapping out fragments, you should ensure that pressing the Back button on a detail screen returns the user to the master screen. To do so, call addToBackStack() before you commit the transaction:
// Works with either the framework FragmentManager or the
// support package FragmentManager (getSupportFragmentManager).
getSupportFragmentManager().beginTransaction()
.add(detailFragment, "detail")
// Add this transaction to the back stack
.addToBackStack()
.commit();
Adding to backstack will solve the problem:
periodFragmentTransaction.replace(R.id.frame, periodFragment);
periodFragmentTransaction.addToBackStack(null);
periodFragmentTransaction.commit();
I have a main Activity in which I created a ViewPager that instantiate 3 other Fragments. One of these is a GridView which makes a popup appear when the user click on one item. Then, in this popup, I have a simple button.
What I want to do is: when the user click on this button, I would like to access a method in my main Activity (that should change the current item of my ViewPager) and then dismiss the popup.
I tried everything I could, but I cannot achieve this... I can set up the click event on my popup and dismiss it easily, but I didn't find out how I can access a method (or even a variable) from my popup to my main Activity.
I will put my most relevant code in here so you can understand the structure of my classes (hopefully...).
My main Activity:
public class MainActivity extends FirstActivity{
private ViewPager mViewPager;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager = (ViewPager) findViewById(R.id.viewpager);
// Set an Adapter on the ViewPager
mViewPager.setAdapter(new MainActivity_Adapter(getSupportFragmentManager()));
public void onSaveInstanceState(Bundle savedInstanceState)
{
menuBar.onSaveInstanceState(savedInstanceState);
}}
My ViewPager activity:
public class MainActivity_Adapter extends FragmentPagerAdapter{
public MainActivity_Adapter(FragmentManager fm)
{
super(fm);
}
#Override
public Fragment getItem(int position)
{
// Set the color background for each page
switch (position)
{
case 0:
return MainActivity_Inventory.newInstance();
case 1:
return MainActivity_Map.newInstance();
default:
return MainActivity_AR.newInstance();
}
}
// The number of Splash Screens to display
#Override
public int getCount()
{
return 3;
}}
My "Inventory" Fragment
public class MainActivity_Inventory extends Fragment implements View.OnClickListener{
public static MainActivity_Inventory newInstance()
{
MainActivity_Inventory frag = new MainActivity_Inventory();
Bundle b = new Bundle();
frag.setArguments(b);
return frag;
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Select the layout
int layout;
layout = R.layout.activity_inventory_01;
// Inflate the layout resource file
View view = getActivity().getLayoutInflater().inflate(layout, container, false);
// Set the grid view
GridView gridview = (GridView) view.findViewById(R.id.inventory_gridView);
gridview.setAdapter(new InventoryImageAdapter(super.getActivity()));
gridview.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
public void onItemClick(AdapterView parent, View v, int position, long id)
{
// Create a popup to show item details
createPopup();
}
});
return view;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
}
public void createPopup()
{
DialogFragment newFragment = new PopupActivity_Inventory();
newFragment.show(getFragmentManager(), "itemDetails");
}
#Override
public void onClick(View v)
{
}}
And my popup dialog fragment:
public class PopupActivity_Inventory extends DialogFragment{
#Override
public Dialog onCreateDialog(final Bundle savedInstanceState)
{
// Build the alert dialog
final Dialog dialog = new Dialog(this.getActivity());
// Get the layout inflater
final LayoutInflater inflater = getActivity().getLayoutInflater();
// Set up the dialog box
dialog.setContentView(inflater.inflate(R.layout.activity_inventory_popup_01, null));
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
dialog.getWindow().setGravity(Gravity.TOP);
//dialog.getWindow().getAttributes().y = 100;
(dialog.findViewById(R.id.brick_button_01)).setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
// When button is clicked, ACCESS MAIN ACTIVITY!
dialog.dismiss();
}
});
return dialog;
}}
I really hope you can help me with this... I really need to get it working. Thank you very much!
If you need further details or explanation, please just tell me.
The best thing to do is use EventBus library. I have a demo app in which you can add items to RecyclerView from anywhere within the app using EventBus. You can use it as a reference to simply do something else instead of current task. Here is the link to the repo:
https://github.com/code-crusher/android-demos/tree/master/EventBusDemo
And if you want to understand how it works you can refer to my article, it explains how to make communications like this easy:
https://medium.com/#code_crusher/eventbus-for-android
Hope it helps. Happy coding :)
Read this https://developer.android.com/training/basics/fragments/communicating.html
Look for "To allow a Fragment to communicate up to its Activity, you can define an interface in the Fragment class and implement it within the Activity...."
Another way to achieve it is using an EventBus and post events by Fragments to be caught by Activities.
I'm using FragmentActivity for switching between Fragment. But I would like to have a Admin Button on a fragment, and when I click on it, a new fragment or activity appears like a child (with the back button in action bar).
How can I make it ?
Here is my code, that works, but the back button doesn't appear in action bar :
Fragment :
public class Reports extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (container == null) {
return null;
}
public void onClick(View v) {
Intent intent = new Intent(getActivity(), LoginActivity.class);
getActivity().startActivity(intent);
}
});
}
}
Activity (for the moment... but maybe Fragment if we need ?) :
public class LoginActivity extends ActionBarActivity {
public static final String TAG = LoginActivity.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
Button loginButton = (Button) findViewById(R.id.loginButton);
loginButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
TextView emailText = (TextView) findViewById(R.id.emailText);
TextView passwordText = (TextView) findViewById(R.id.passwordText);
ParseUser.logInInBackground(emailText.getText().toString(), passwordText.getText().toString(), new LogInCallback() {
public void done(ParseUser user, ParseException e) {
if (user != null) {
Log.i(TAG, "Yeahhh Login OK");
finish();
} else {
runOnUiThread();
}
}
});
}
});
}
Maybe I have to change something in Manifest ?
All you need to do is enable it inside the activity you're currently at.
When inside a FragmentActivity: getActionBar().setHomeAsUpEnabled(boolean).
Otherwise, inside a Fragment: getActivity().getActionBar().setHomeAsUpEnabled(boolean).
U need to override the onCreateOptionsMenu and onOptionsItemSelected. In the onCreateOptionsMenu method do the following : Inflate the menu into the action bar. You can define the contents of the menu item under res/menu folder.
Next in the onOptionsItemSelected method, you can handle the clicks of the back button added in the action bar. Also keep in mind one thing. In the manifest please use a theme which has action bar in it.
Example : Under the application tag use
android:theme="#android:style/Theme.Light" and not anything like android:theme="#android:style/Theme.Light.NoTitleBar
Well if you are starting a new Activity you can enable the back button in it by writing shouldDisplayHomeUp(); in the onCreate() method and on back should take you to the previous activity in the back stack.
And in the other case of adding a new Fragment you can take a look on this answer for reference as it mentions that when you add a new Fragment you add it to the back stack like this
getSupportFragmentManager().beginTransaction()
.add(detailFragment, "detail")
// Add this transaction to the back stack
.addToBackStack()
.commit();
this will make the back button take you to your previous Fragment