如何在安卓系统中显示工具提示?

33

当我的光标移动到视图上时,我希望显示工具提示(快速操作视图)。 请问有没有人能为我提供一个简单的示例? 工具提示将仅包含文本值。


1
请看我在另一个类似问题上的回答:我的回答 - Mansour
@Mansour 我在我的回答中使用了类似的方法:https://dev59.com/YGct5IYBdhLWcg3wk-Vq#42003384 - ban-geoengineering
有一个内置的方法可以这样做。请查看帖子。 - Bertram Gilfoyle
12个回答

36

可以考虑使用myView.setTooltipText(CharSequence)(从API级别26开始)或TooltipCompat(在API级别26之前)作为另一种选项:

TooltipCompat.setTooltipText(myView, context.getString(R.string.myString));

文档说明:

这个辅助类用于在API级别26之前模拟{@link View#setTooltipText(CharSequence)}的行为。


23

使用AndroidX是推荐的方式。

支持 Android 4.0(API 14)及更高版本

AndroidX支持库为视图和菜单项添加了对tooltips(带有描述性文本的小弹出窗口)的支持。

使用setTooltipText设置工具提示文本,该文本将显示在视图旁边的小弹出窗口中。

请参见以下示例:

FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
TooltipCompat.setTooltipText(fab, "Send an email");

工具提示将会在以下情况下显示:

  • 长按,除非已经被其他方式处理(例如OnLongClickListener或上下文菜单)。
  • 悬停,在指针停止移动后的短暂延迟后。

要将Appcompat库添加到您的项目中,请执行以下操作:

  1. Open the build.gradle file for your application.

  2. Add the support library to the dependencies section.

    dependencies {
    
    compile "androidx.appcompat:appcompat:1.1.0"
    }
    

如果您最低支持的版本是Android 8.0(API级别26)及更高版本,则可以通过调用setTooltipText()方法在视图中指定工具提示文本。您还可以在相应的XML中使用tooltipText属性来设置工具提示文本。要在XML文件中指定工具提示文本,请设置android:tooltipText属性,如以下示例所示:
<android.support.design.widget.FloatingActionButton
    android:id="@+id/fab"
    android:tooltipText="Send an email" />

要在您的代码中指定工具提示文本,请使用setTooltipText(CharSequence)方法,如下例所示:

FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setTooltipText("Send an email");

20

Android 4.0及以上版本只支持对ActionBar按钮进行“工具提示”,但正如Jaguar所提到的,在Android中使用工具提示并不太合适,因为没有悬停的概念。

从Android 4.0开始,如果您在按钮上长按,将会显示您在xml文件或代码中设置的普通标题文本。但如果屏幕上有足够的空间,它将始终可见于ActionBar图标旁边。

如果想要自定义视图,您需要通过为其添加一个LongClickListener来实现,并在长按时显示一个Toast

view.setOnLongClickListener(new OnLongClickListener() {
    public boolean onLongClick(View v) {
        Toast.makeText(v.getContext(), "My tool-tip text", Toast.LENGTH_SHORT).show();
        return true;
    }
}

当然应该使用字符串资源而不是硬编码的字符串。


1
这个 Toast 消息会出现在我们长按的视图下面吗? - John
2
@John:使用Toast类,它将出现在屏幕底部居中位置。使用菜单按钮上的标题文本,文本将直接出现在它们下方。 - Tim Roes
感谢提供代码。这应该成为Android的标准约定,不是吗?我喜欢Material Design,但那些UI设计师太过零散了。我的建议是:代码应该使用getContentDescription(),XML应该使用android:contentDescription,这样你就同时解决了可访问性问题。 - Robin Davies
在可以运行Android应用程序的Chromebook上,悬停的概念非常合理,并且自本回答以来已经实现。请记住,Chromebook在教育领域拥有巨大的市场份额。 - Dan Dascalescu

7

从Android API 14+开始,有一种悬停事件(OnHoverListener)可用。您可以执行以下操作:

view.setOnHoverListener(...)

监听 MotionEvent,例如 ACTION_HOVER_ENTERACTION_HOVER_EXIT,而不是使用 onLongClick


4

基于GregoryK的回答,我创建了一个新的ImageButton类 - 请参见下面的代码。要使用它,您只需要将布局中的ImageButton替换为com.yourpackage.ImageButtonWithToolTip,并给它一个android:contentDescription属性(因为那是将显示在工具提示中的文本)。

package com.yourpackage;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.widget.ImageButton;
import android.widget.Toast;

public class ImageButtonWithToolTip extends ImageButton {

    private static final int ESTIMATED_TOAST_HEIGHT_DIPS = 48;

    public ImageButtonWithToolTip(Context context) {
        super(context);
        init();
    }

    public ImageButtonWithToolTip(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public ImageButtonWithToolTip(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @TargetApi(21)
    public ImageButtonWithToolTip(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    private void init() {
        setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View view) {

                /**
                 * You should set the android:contentDescription attribute in this view's XML layout file.
                 */

                String contentDescription = getContentDescription().toString();

                if (TextUtils.isEmpty(contentDescription)) {

                    /**
                     * There's no content description, so do nothing.
                     */

                    return false; // Not consumed

                }
                else {

                    final int[] screenPos = new int[2]; // origin is device display
                    final Rect displayFrame = new Rect(); // includes decorations (e.g. status bar)
                    view.getLocationOnScreen(screenPos);
                    view.getWindowVisibleDisplayFrame(displayFrame);

                    final Context context = view.getContext();
                    final int viewWidth = view.getWidth();
                    final int viewHeight = view.getHeight();
                    final int viewCenterX = screenPos[0] + viewWidth / 2;
                    final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
                    final int estimatedToastHeight = (int) (ESTIMATED_TOAST_HEIGHT_DIPS
                            * context.getResources().getDisplayMetrics().density);

                    Toast toolTipToast = Toast.makeText(context, contentDescription, Toast.LENGTH_SHORT);
                    boolean showBelow = screenPos[1] < estimatedToastHeight;
                    if (showBelow) {
                        // Show below
                        // Offsets are after decorations (e.g. status bar) are factored in
                        toolTipToast.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL,
                                viewCenterX - screenWidth / 2,
                                screenPos[1] - displayFrame.top + viewHeight);
                    }
                    else {
                        // Show above
                        // Offsets are after decorations (e.g. status bar) are factored in
                        // NOTE: We can't use Gravity.BOTTOM because when the keyboard is up
                        // its height isn't factored in.
                        toolTipToast.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL,
                                viewCenterX - screenWidth / 2,
                                screenPos[1] - displayFrame.top - estimatedToastHeight);
                    }

                    toolTipToast.show();

                    return true; // Consumed

                }

            }

        });

    }

}

你可以使用相同的方法扩展其他视图 - 例如,Button

此代码通常会在 ImageButtonWithToolTip 上方显示工具提示 - 我认为这是首选,因为这意味着用户用手指/拇指遮挡工具提示的可能性较小。 - ban-geoengineering

3
package com.nbfc.tekis.tooltipexample;

import android.support.v7.app.AppCompatActivity; import
android.os.Bundle; import android.view.View; import
android.widget.Button; import android.widget.GridView;

import it.sephiroth.android.library.tooltip.Tooltip;

public class MainActivity extends AppCompatActivity {
    /*Button button1,button2,button3,button4;*/

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void bottomTooltip(View view) {
        Button button1=(Button)findViewById(R.id.button1);
        Tooltip.make(this,new Tooltip.Builder()
            .anchor(button1, Tooltip.Gravity.BOTTOM)
            .closePolicy(new Tooltip.ClosePolicy()
            .insidePolicy(true,false)
            .outsidePolicy(true,false),4000)
            .activateDelay(900)
            .showDelay(400)
            .text("Android tooltip bottom")
            .maxWidth(600)
            .withArrow(true)
            .withOverlay(true)
            .build())
            .show();
    }

    public void topTooltip(View view) {
        Button button3=(Button)findViewById(R.id.button3);
        Tooltip.make(this,new Tooltip.Builder()
            .anchor(button3, Tooltip.Gravity.TOP)
            .closePolicy(new Tooltip.ClosePolicy()
            .insidePolicy(true,false)
            .outsidePolicy(true,false),4000)
            .activateDelay(900)
            .showDelay(400)
            .text("Android tooltip top")
            .maxWidth(600)
            .withOverlay(true)
            .withArrow(true)
            .build())
            .show();
    }

    public void rightTooltip(View view) {
        Button button2=(Button)findViewById(R.id.button2);
        Tooltip.make(this,new Tooltip.Builder()
            .anchor(button2, Tooltip.Gravity.RIGHT)
            .closePolicy(new Tooltip.ClosePolicy()
            .insidePolicy(true,false)
            .outsidePolicy(true,false),4000)
            .activateDelay(900)
            .showDelay(400)
            .text("Android tooltip right")
            .maxWidth(600)
            .withArrow(true)
            .withOverlay(true)
            .build())
            .show();
    }

    public void leftTooltip(View view) {
        Button button4=(Button)findViewById(R.id.button4);
        Tooltip.make(this,new Tooltip.Builder()
            .anchor(button4, Tooltip.Gravity.LEFT)
            .closePolicy(new Tooltip.ClosePolicy()
            .insidePolicy(true,false)
            .outsidePolicy(true,false),4000)
            .text("Android tooltip left")
            .maxWidth(600)
            .withArrow(true)
            .withOverlay(true)
            .build())
            .show();
    } 
}

3

Android没有工具提示。它是基于触摸的用户界面。目前的触摸传感器通常无法检测到悬停,因此工具提示并没有什么用处。

在触摸屏上没有“悬停”这个概念,但您可以为您的视图设置一个长按监听器,并在长时间按下后显示一个Toast。


3
如果您需要为任何视图显示工具提示,可以使用Roman Nurik的CheatSheet实用程序类。(使用Toast和可选的content description来显示工具提示。)
这是一个Android助手类,用于在长按时为仅包含图标的UI元素显示Cheat Sheet(工具提示)。 这已经是仅包含图标的操作栏项目和选项卡的默认平台行为。 该类为任何其他此类UI元素提供了此行为。

1
将此添加到您的按钮中。
android:tooltipText="Tooltip text goes here"

将此代码添加到嵌套视图中,可以防止其onClick事件向上传递到父视图。在处理recyclerView时需要考虑这一点。 - lasec0203

1

https://github.com/skydoves/Balloon

这个库提供了一个轻量级的类似弹出窗口的工具提示,带有箭头和动画,可以完全自定义。使用100% Kotlin编写,并配备所有必要的文档。它正在积极管理中。
以下是他们页面上的一些gif;

e

另一个,

e


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接