Clickable Hyperlinks in DialogFragment - android

This is my static inner class for creating an AlertDialog inside my MainActivity class:
public static class AboutDialogFragment extends DialogFragment {
public static AboutDialogFragment newInstance() {
AboutDialogFragment frag = new AboutDialogFragment();
return frag;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setIcon(R.drawable.ic_dialog_about)
.setTitle(R.string.about)
.setMessage(R.string.about_message)
..........
.create();
}
}
And I'm showing it when you press a menu item which is inside MainActivity:
case R.id.about:
DialogFragment aboutFragment = AboutDialogFragment.newInstance();
aboutFragment.show(getSupportFragmentManager(), "about_dialog");
// Make links clickable
((TextView) aboutFragment.getDialog().findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
return true;
I'm trying to make the links in the message text clickable using the commented line.
I found this method here and it has worked for me when using a regular Dialog (no fragments). However, this is the first time I have tried using it on a DialogFragment and I always get a NullPointerException when trying to find the view.
I've also tried aboutFragment.getView().findViewById(android.R.id.message) but that returns null as well.
Maybe I am calling the code too early/in the wrong place?
Any ideas would be great!
EDIT: Just tried ((TextView) v.getRootView().findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
and
((TextView) v.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); in onCreateView() and also tried in onCreateDialog() without success.
Still getting null pointer exception...

Hopefully you've already figured this out but I just did this same thing and wanted to document it somewhere. Put this in your DialogFragment class:
#Override
public void onStart() {
super.onStart();
((TextView) getDialog().findViewById(android.R.id.message))
.setMovementMethod(LinkMovementMethod.getInstance());
}

Maybe I am calling the code too early/in the wrong place?
That's my suspicion. Is there any reason you can't do your "make links clickable" inside your onCreateDialog() method?

As the time progressed, adding some updated inputs to the query.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupView(view)
}
private fun setupView(view: View) {
toolbar.setNavigationOnClickListener({ v -> dismiss() })
toolbar.title = "New Message"
view.tvTitle.text = arguments?.getString("title")
view.tvBody.autoLinkMask = Linkify.ALL
view.tvBody.text = arguments?.getString("body")
view.tvBody.movementMethod = LinkMovementMethod.getInstance()
}
Most important 2 steps in the above code (which can be used in any dialog textviews) are:
To Linkify
setMovementMethod
After this all links will work fine.

Related

Android set the text of TextView inside a Fragment - where the Fragment may have already mounted

Within my Android app I'm looking to hotswap the text in a Fragment based on a button press in another fragment.
The Buttons fragment has 6 buttons, each of which need to invoke a configured view of output fragment, so that when "BUtton 1" is pressed in Buttons, a TextView myText is configured to say "Button 1 was pressed" and so on, for 2 - 6.
I've tried instantiating a member version of the TextView inside onViewCreated, and several other strategies but I can't seem to get this not to crash.
Is there an established pattern for this?
//MainActivity Java
public class MainActivity extends AppCompatActivity
implements StringsFragment.OnStringsInteractionListener,
StringFragment.OnStringInteractionListener,
ProgressFragment.OnProgressInteractionListener {
#Override
public void onStringButtonClick(Integer string) {
fm = getSupportFragmentManager();
fm.beginTransaction().remove(progressFragment).commit();
if(liveStringFlag != true) {
liveStringFlag = true;
fm.beginTransaction().add(R.id.fragment_container_bottom, stringFragment).commit();
stringsFragment.activateSummary();
}
stringFragment.updateStringData(string);
}
What does stringFragment.updateString need to look like, and what else needs to happen to make it work?
What isn't immediately clear about this scenario is that it's sometimes tricky to know when onViewCreated has been called. In effect this is a race condition and the update method or the onViewCreated may be called first. For this reason it's important to carefully manage state.
Public Class stringFragment extends Fragment {
private TextView textString;
private Boolean viewable = false;
private String string = "";
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
textString = (TextView) view.findViewById(R.id.text_string);
if(string != null) {
textString.setText(string);
}
viewable = true;
}
public void updateStringData(String s ) {
string = s;
if(viewable == true) {
textString.setText(string);
}
}
}

DialogFragment keeps data in memory, even after dismiss() is called

I am having a very odd behaviour here. From my MainActivity class, I invoke my DialogFragment:
EndRoundDialogFragment df = new EndRoundDialogFragment(myVO);
df.show(fragmentManager, "end_round_dialog_fragment");
The constructor for this DialogFragment is simple:
public EndRoundDialogFragment(UserVO vo) {
this.userVO = vo;
}
This Fragment has a Google Maps fragment inside it. So what I basically do is:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.end_round_dialog, container, false);
mMap = ((MapFragment)getFragmentManager().findFragmentById(R.id.map_result)).getMap();
mMap.setIndoorEnabled(false);
mMap.setMyLocationEnabled(false);
mMap.setTrafficEnabled(false);
buttonClose.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mListener.onEndDialogClosed();
userVO = null;
dismissAllowingStateLoss();
}
});
//Rest of the code is manipulating Markers in this map.
So, when user clicks on Close button, I dismiss the dialog and am OKwith State loss. I am even setting the VO to null.
As you can see, my Activity implements the Dialog's Listener onEndDialogClosed(). This method implementation is:
#Override
public void onEndDialogClosed() {
Fragment prev = fragmentManager.findFragmentByTag("end_round_dialog_fragment");
if(prev != null)
fragmentManager.beginTransaction().remove(prev).commit();
new Get5PointsTask().execute();
}
So I am also removing the whole fragment when it is closed.
I also added the following to this DialogFragments, to make sure that the Google Maps fragment was indeed being removed from the code:
#Override
public void onDestroyView() {
super.onDestroyView();
Fragment f = (MapFragment) getFragmentManager().findFragmentById(R.id.map_result);
if (f != null) {
getFragmentManager().beginTransaction().remove(f).commit();
}
}
While debugging, I verified that the variable f is not null and the remove() code is indeed called.
When I instantiate the DialogFragment again, with a new VO data, Google Maps is shown with new and old data. It's just not resetting the de memory...
Any ideas?
EDIT 1:
And I found what the problem was. Was simply not erasing my VO in the Activity's onEndDialogClosed() method. Stupid me.
Thanks to all and hope this code helps other people.
So, I fixed the issue.
I was simply not re-instantiating the VO that held the user data in the Activity... so when opening the DialogFragment, it held the new and the old that. Simple like that, stupid like that.
Thanks!

Android DialogFragment: How to preserve view in multiple show() invocation?

I have a dialog fragment using a custom layout with a quite complex View hierarchy. The code for the dialog fragment is more or less similar to the following.
public class CardDetailDialog extends DialogFragment {
public CardDetailDialog() {
setRetainInstance(true);
setStyle(STYLE_NORMAL, android.R.style.Theme_Light);
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.card_detail_dialog, container, false);
/* Modify some view objects ... */
return view;
}
}
Whenever I invoked the show() method for this dialog fragment, I noticed that onCreateView is always called and layout inflation process is repeated. In my app, user might want to show the dialog multiple times during a session and I thought this is inefficient. Is there any way to keep the view / dialog instance across multiple show() invocation? Is it possible to do this using DialogFragment, or do I have to deal directly with Dialog class?
Using a boolean flag seems to do the trick (See the KEY CHANGEs). I override onCreateDialog, but employing the same strategy in onCreateView should work as well (keep a reference to your view you create)
I'm still getting some issues related to Orientation changes, but it may be related to a different issue
public class LogFragment extends DialogFragment{
private boolean isCreated; //KEY CHANGE
private Dialog mDialog; //KEY CHANGE -- to hold onto dialog instance across show()s
public LogFragment() {
setRetainInstance(true); // This keeps the fields across activity lifecycle
isCreated = false; // KEY CHANGE - we create the dialog/view the 1st time
}
#Override
public Dialog onCreateDialog(Bundle inState) {
if (isCreated) return mDialog; // KEY CHANGE - don't recreate, just send it back
View v = View.inflate(getActivity(),R.layout.log_layout,null);
mDialog = new AlertDialog.Builder(getActivity())
...
.create();
isCreated = true; // KEY CHANGE Set the FLAG
return mDialog;
}

Android - Dialog getSupportFragmentManager undefined

I'm trying to implement a simple Dialog into my code. But it does not work. I have searched every available tutorial, including the official developer guide but nothing works. The error I got from logcat is that I'm getting a nullPointerException, I'm guessing that's on the getActivity. Any help?
This is what I have: This is my Custom Dialog class.
public class SaveDialog extends DialogFragment {
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Save Password");
builder.setView(getContentView());
Dialog dialog = builder.create();
dialog.show();
return dialog;
}
private View getContentView() {
LayoutInflater inflater = getActivity().getLayoutInflater();
return inflater.inflate(R.layout.dialog, null);
}
}
and this is my main activity where the onclick occurs
private void savePassword() {
SaveDialog savePasswordDialog = new SaveDialog();
savePasswordDialog.show(savePasswordDialog.getSupportFragmentManager(), "tag");
}
Every single time I fire up the onClick, the app crashes. On top of that, currently I am trying to use getSupportFragmentManager, but it says it's undefined.
You should use getSupportFragmentManager(), which is only available in FragmentActivity.
You should change your activity to a fragment one.
Check this answer
Try this..works!!
((AppCompatActivity)activity).getSupportFragmentManager()
Just call getFragmentManager() from your android.support.v4.app.DialogFragment or android.support.v4.app.Fragment. It will return a android.support.v4.app.FragmentManager (this is, the support FragmentManager)
You don't have to manually show the dialog in onCreateDialog(), just returning it is sufficient for DialogFragment to work its magic (and show the dialog) when you call savePassword().
So remove this line from onCreateDialog :
dialog.show();
and it should work. Good luck!

How to dismiss a DialogFragment when pressing outside the dialog?

I am using a DialogFragment, and while I have successfully set an image to close (i.e. dismiss) the dialog when pressed, I am having a hard time finding the way to dismiss the dialog when the user clicks anywhere outside it, just as it works with normal dialogs. I thought there would be some sort of
dialogFragment.setCanceledOnTouchOutside(true);
call, but I don't see that in the documentation.
Is this possible with DialogFragment at all? Or am I looking in the wrong places? I tried intercepting touch events in the 'parent' activity but apart from not getting any touch event, it didn't seem right to me.
DialogFragment.getDialog().setCanceledOnTouchOutside(true);
Must be called in onCreateView (as Apurv Gupta pointed out).
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
getDialog().setCanceledOnTouchOutside(true);
...
}
/** The system calls this only when creating the layout in a dialog. */
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// The only reason you might override this method when using onCreateView() is
// to modify any dialog characteristics. For example, the dialog includes a
// title by default, but your custom layout might not need it. So here you can
// remove the dialog title, but you must call the superclass to get the Dialog.
Dialog dialog = super.onCreateDialog(savedInstanceState);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setCanceledOnTouchOutside(true);
return dialog;
}
Lot of answers here but, the app crash when dialog opens.
Writing getDialog().setCanceledOnTouchOutside(true); inside onCreateView did not work and crashed my app.
(I am using AppCompatActivity as my BaseActivity and android.app.DialogFragment as my Fragment).
What works is either of the two following lines:
getDialog().setCanceledOnTouchOutside(true);
OR
this.getDialog().setCanceledOnTouchOutside(true);
inside onActivityCreated like
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//getDialog().getWindow().getAttributes().windowAnimations = R.style.DialogAnimationZoom;
//getDialog().getWindow().setDimAmount(0.85f);
getDialog().setCanceledOnTouchOutside(true);//See here is the code
}
What not to use:
DialogFragment.getDialog().setCanceledOnTouchOutside(false);
throws following error
And writing the code in onCreateView crashes the App!
Please update the answer if you find something wrong.
If you want to execute some logic when clicking outside of a DialogFragment, just override the onCancel method.
override fun onCancel(dialog: DialogInterface) {
super.onCancel(dialog)
// Do your work here
}
This works fine for Java:
DialogFragment.getDialog().setCanceledOnTouchOutside(false);
I would recommend to use my solution only after trying out above solutions. I have described my solution here. Just to brief, I am checking touch bounds of DialogFragment.getView(). When touch points are outside DialogFragment, I am dismissing the Dialog.
Dialog.SetCanceledOnTouchOutside(true);
Worked for me
My Code
class dlgRegister : DialogFragment
{
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
....
....
}
public override void OnActivityCreated(Bundle savedInstanceState)
{
Dialog.Window.RequestFeature(WindowFeatures.NoTitle);
Dialog.SetCanceledOnTouchOutside(true);
base.OnActivityCreated(savedInstanceState);
Dialog.Window.Attributes.WindowAnimations = Resource.Style.dialog_animation;
}
}
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup
container, #Nullable Bundle savedInstanceState)
{
DialogConfermationdialogBinding binding = DialogConfermationdialogBinding.inflate(inflater,container,false);
View view = binding.getRoot();
getDialog().setCanceledOnTouchOutside(false);
return view;
}

Categories

Resources