skydoves / Balloon

:balloon: Modernized and sophisticated tooltips, fully customizable with an arrow and animations for Android.
https://skydoves.github.io/libraries/balloon/html/balloon/com.skydoves.balloon/index.html
Apache License 2.0
3.73k stars 291 forks source link

Balloon cut off if shown from dialog fragment #131

Closed holgerschlegel closed 3 years ago

holgerschlegel commented 3 years ago

Please complete the following information:

Describe the Bug: In my app I use balloons to show some details on click/tip on a view. The balloon contains a recycler view as content view. Once created, the content of the recycler view (adapter) and thus the ballon is not changed. At most places of my app that works as expected.

But if such a balloon tip with a larger content is opened from within a dialog fragment, the balloon is not fully shown. It looks like it is cut off at some boundary outside the area of the dialog fragment.

Here is a screenshot: grafik

The white background in the top and left of the balloon is the dialog fragment. The gray background on the other sides is the fragment behind the dialog fragment. As you can see by the few black dots at the bottom of the yellow balloon, there should be more text. And the rounded top corners are also a hint that the balloon is not fully shown.

Just in case you need it, here is a code fragment (in Java) that is used to create the recycler view and the balloon:

RecyclerView recyclerView = new RecyclerView(context);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(context));
recyclerView.setAdapter(new ValueDescriptionsRecyclerViewAdapter(items));
int padding = UiUtils.dpToPx(context, 8);
recyclerView.setPadding(padding, padding, padding, padding);

Balloon balloon = new Balloon.Builder(context)
        .setArrowConstraints(ArrowConstraints.ALIGN_ANCHOR)
        .setArrowOrientation(ArrowOrientation.TOP)
        .setBackgroundColor(MaterialColors.getColor(context, R.attr.colorBackgroundTip, 0))
        .setLayout(recyclerView)
        .setMargin(8).setMarginTop(2)
        .setBalloonAnimation(BalloonAnimation.FADE)
        .setLifecycleOwner(lifecycleOwner)
        .setDismissWhenClicked(true)
        .build();

balloon.showAlignBottom(anchor);

It has some not specified input parameter and I copied it together from several methods, but those are the basic commands.

I also tried adding a fixed balloon height with setHeight(200). It has an effect if the balloon is shown from a "normal" fragment. But inside the dialog fragment, the result is exactly what is shown in the screenshot.

Expected Behavior:

The balloon should be fully visible even if shown if used in a dialog fragment.

kishan-jeeves commented 3 years ago

I am also facing the same issue did you get any solution?

skydoves commented 3 years ago

Hi, @KishanVajani I think the balloon would be cut off by the DialogFragment that has wrap_content width size. Could you test with the match_parent size of the DialogFragment and transparent background?

holgerschlegel commented 3 years ago

Hi @skydoves,

I just played around with a dummy PopupWindow trying to find a solution for the popup been cut off some pixels outside of the parent dialog fragment.

The following test Java code is from the onClick listener on a button shown in a not full screen dialog fragment.

// content view that is higher than the fragment dialog
TextView textView = new TextView(anchor.getContext());
textView.setText("1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30");

PopupWindow popupWindow = new PopupWindow(textView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
popupWindow.setBackgroundDrawable(new ColorDrawable(Color.GREEN));
popupWindow.setTouchable(true);
popupWindow.setTouchInterceptor((view, event) -> {
  popupWindow.dismiss();
  return true;
});

popupWindow.showAsDropDown(anchor);

Running it and clicking that button shows a popup that is cut off about a centimeter below the visible border of the dialog. Similar to the screenshot I added when creating this issue.

With some tests I found 3 options that look like it would solve the problem (or could be used to solve it) for me.

  1. Add popupWindow.setAttachedInDecor(false); before calling popupWindow.showAsDropDown The popup window now extends until the bottom of the screen, even overlapping the soft keys for back and home.
  2. Add popupWindow.setIsClippedToScreen(true); before calling popupWindow.showAsDropDown Results looks the same as 1., but this property is available from API 29 only.
  3. Add popupWindow.setIsLaidOutInScreen(true);; before calling popupWindow.showAsDropDown Popup can be placed at any location on the screen. Even completely outside of the dialog fragment. But the coordinates to show the popup must be given according to another parent (I assume the display). This is only available from API 30.

Solution 1 looks like the best for me (min API version of my app is 26) and the real popup is not that high so that it would overlap the back and home buttons. Just high enough to not fit into the dialogs decor view.

But I did not find a way to apply that flag to the popup window of the Balloon. Not even using reflection ...

May I request adding an new optional callback/listener similar to OnBalloonInitializedListener but for the balloon popup window? That would allow me to set "configure" the popup window to my needs using one of the above solutions.

skydoves commented 3 years ago

Hey @holgerschlegel, Thanks for your detailed feedback and many kinds of solutions! 🙏 Just released a new stable 1.3.7. You can access balloon.bodyWindow directly or you can use setIsAttachedInDecor(false) on your Builder class. Thanks for your contribution!