23

I'm trying to build an app with image buttons that work like the action bar but i can't get them to show a tooltip on long press.

   <ImageButton
        android:id="@+id/editUrgent"
        style="?android:attr/borderlessButtonStyle"
        android:layout_width="48dp"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toLeftOf="@+id/editImportant"
        android:hint="@string/hint_urgent"
        android:contentDescription="@string/hint_urgent"
        android:text="@string/hint_urgent"
        android:src="@drawable/clock_light" />

android:contentDescription works for hovering(s-pen) but long press still does nothing.

user3536471
  • 231
  • 1
  • 2
  • 3
  • 1
    Check out Context Menu option for this feature on long press - http://www.thegeekstuff.com/2013/12/android-app-menus/ – Atul O Holic Apr 15 '14 at 15:07

4 Answers4

34

With api level 26 you can use the built-in TooltipText: Via XML:

android:toolTipText="yourText"

ViewCompatDocs

If your minSdk is below 26, use ToolTipCompat, for example:

TooltipCompat.setTooltipText(yourView, "your String");

Unfortunately, there's is no way to do this in your XML-File.

AsterixR
  • 547
  • 7
  • 9
10

This is the code that Support Library v7 uses to show "cheat sheet"s for action menu items:

public boolean onLongClick(View v) {
    if (hasText()) {
        // Don't show the cheat sheet for items that already show text.
        return false;
    }

    final int[] screenPos = new int[2];
    final Rect displayFrame = new Rect();
    getLocationOnScreen(screenPos);
    getWindowVisibleDisplayFrame(displayFrame);

    final Context context = getContext();
    final int width = getWidth();
    final int height = getHeight();
    final int midy = screenPos[1] + height / 2;
    int referenceX = screenPos[0] + width / 2;
    if (ViewCompat.getLayoutDirection(v) == ViewCompat.LAYOUT_DIRECTION_LTR) {
        final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
        referenceX = screenWidth - referenceX; // mirror
    }
    Toast cheatSheet = Toast.makeText(context, mItemData.getTitle(), Toast.LENGTH_SHORT);
    if (midy < displayFrame.height()) {
        // Show along the top; follow action buttons
        cheatSheet.setGravity(Gravity.TOP | GravityCompat.END, referenceX, height);
    } else {
        // Show along the bottom center
        cheatSheet.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height);
    }
    cheatSheet.show();
    return true;
}
Mansour
  • 1,787
  • 2
  • 20
  • 33
5

Solution that works in xml and supports minSdk less than 26

@BindingAdapter("tooltipTextCompat")
fun bindTooltipText(view: View, tooltipText: String) {
    TooltipCompat.setTooltipText(view, tooltipText)
}

and usage in layout.xml

app:tooltipTextCompat="@{@string/add_for_all_tooltip}"
krishnakumarp
  • 8,967
  • 3
  • 49
  • 55
  • androidx understands app:tooltipText="@string/mystring" but at runtime it just won't work. Do I need both XML and code? – Slion Jun 05 '20 at 23:34
  • 1
    Yes. both are required. – krishnakumarp Jun 06 '20 at 03:26
  • So that kotlin function scope is global? It is then being picked up by the binding framework thanks to that @BindingAdapter annotation? I may as well just bind "contentDescription" and save myself more work and redundancy in the XML right? – Slion Jun 06 '20 at 03:53
  • Got it working eventually was missing that base layout element in my XML and the call to the generated MyLayoutBinding.inflate function. See https://youtu.be/W7uujFrljW0 – Slion Jun 06 '20 at 06:05
  • Will this tooltip be shown only on long press of view ? if i want to show the tooltip text without even user tapping on the view, what should i do ? – K Pradeep Kumar Reddy Sep 26 '21 at 16:14
  • Probably should have mentioned that if you do not already use view binding or are willing to convert, this is incompatible. @Slion alluded to this with the video, which was actually replacing findViewById with view binding. The best way to go about it is to always assume the person reading is only using the base API. – Abandoned Cart Oct 16 '22 at 12:09
3

Not exactly what you are looking for but it does something very similar.

1) Insure your view is android:longClickable="true" (should be by default) and has a defined content description android:contentDescription="@string/myText":

<ImageButton android:id="@+id/button_edit"
     android:contentDescription="@string/myText"
     android:src="@drawable/ic_action_edit"
     android:onClick="onEdit"
     android:longClickable="true"/>

2) Register a callback to be invoked when the view is long pressed. Handler will display the content description as a toast message.

findViewById(R.id.button_edit).setOnLongClickListener(new View.OnLongClickListener() {

            @Override
            public boolean onLongClick(View view) {
                Toast.makeText(context,view.getContentDescription(), Toast.LENGTH_SHORT).show();
                return true;
            }
        });
JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
Pascal Chardon
  • 186
  • 1
  • 4
  • 1
    This isn't ideal as it won't show the tooltip where the long-click was made, but will show it in the standard Toast message location(??). – ban-geoengineering Jan 15 '15 at 11:52