使用Toast通知用户

Toast,或“应用内通知”,用于在应用程序内部传达状态变化,或从用户那里收集反馈。

在本教程中,您将学习如何将 toast 叠加层添加到文本查看器应用程序,以及如何在打开文件时显示 toast。

../../../_images/adding_toasts.png

添加Toast叠加层

Toast 由一个叠加层显示,该叠加层必须包含应用程序的其余内容区域。

更新UI定义文件

  1. 找到 TextViewerWindow 的 UI 定义文件

  2. 找到包含主文本区域的 GtkScrolledWindow 的定义

  3. AdwToastOverlay 部件作为 TextViewerWindow 的子部件和 GtkScrolledWindow 的父部件插入,并使用 toast_overlay ID

<property name="content">
  <object class="AdwToastOverlay" id="toast_overlay">
    <property name="child">
      <object class="GtkScrolledWindow">
        <property name="hexpand">true</property>
        <property name="vexpand">true</property>
        <property name="margin-top">6</property>
        <property name="margin-bottom">6</property>
        <property name="margin-start">6</property>
        <property name="margin-end">6</property>
        <property name="child">
          <object class="GtkTextView" id="main_text_view">
            <property name="monospace">true</property>
          </object>
        </property>
      </object>
    </property>
  </object>
</property>

在源代码中绑定叠加层

  1. 现在您必须在 TextViewerWindow 实例结构中添加一个新成员,用于 toast_overlay 部件

struct _TextViewerWindow
{
  AdwApplicationWindow  parent_instance;

  /* Template widgets */
  AdwHeaderBar *header_bar;
  GtkTextView *main_text_view;
  GtkButton *open_button;
  GtkLabel *cursor_pos;
  AdwToastOverlay *toast_overlay;
};
  1. TextViewerWindow 类型的类初始化函数 text_viewer_window_class_init 中将新添加的 toast_overlay 部件绑定到模板

static void
text_viewer_window_class_init (TextViewerWindowClass *klass)
{
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);

  gtk_widget_class_set_template_from_resource (widget_class, "/com/example/TextViewer/text_viewer-window.ui");
  gtk_widget_class_bind_template_child (widget_class, TextViewerWindow, header_bar);
  gtk_widget_class_bind_template_child (widget_class, TextViewerWindow, main_text_view);
  gtk_widget_class_bind_template_child (widget_class, TextViewerWindow, open_button);
  gtk_widget_class_bind_template_child (widget_class, TextViewerWindow, cursor_pos);
  gtk_widget_class_bind_template_child (widget_class, TextViewerWindow, toast_overlay);
}

显示Toast

Toast 特别适用于通知用户异步操作已终止。打开和保存文件是通知的两个典型用例。

打开文件后通知

  1. 找到 TextViewerWindowopen_file_complete 函数

  2. 找到错误处理块,并将其替换为 toast

  3. 在函数末尾添加一个 toast

static void
open_file_complete (GObject          *source_object,
                    GAsyncResult     *result,
                    gpointer          user_data)
{
  GFile *file = G_FILE (source_object);
  TextViewerWindow *self = user_data;

  g_autofree char *contents = NULL;
  gsize length = 0;

  g_autoptr (GError) error = NULL;

  // Complete the asynchronous operation; this function will either
  // give you the contents of the file as a byte array, or will
  // set the error argument
  g_file_load_contents_finish (file,
                               result,
                               &contents,
                               &length,
                               NULL,
                               &error);

  // Query the display name for the file
  g_autofree char *display_name = NULL;
  g_autoptr (GFileInfo) info =
  g_file_query_info (file,
                     "standard::display-name",
                     G_FILE_QUERY_INFO_NONE,
                     NULL,
                     NULL);
  if (info != NULL)
    {
      display_name =
        g_strdup (g_file_info_get_attribute_string (info, "standard::display-name"));
    }
  else
    {
      display_name = g_file_get_basename (file);
    }

  // In case of error, show a toast
  if (error != NULL)
    {
      g_autofree char *msg =
        g_strdup_printf ("Unable to open “%s”", display_name);

      adw_toast_overlay_add_toast (self->toast_overlay, adw_toast_new (msg));
      return;
    }

  // Ensure that the file is encoded with UTF-8
  if (!g_utf8_validate (contents, length, NULL))
    {
      g_autofree char *msg =
        g_strdup_printf ("Invalid text encoding for “%s”", display_name);

      adw_toast_overlay_add_toast (self->toast_overlay, adw_toast_new (msg));
      return;
    }

  // Retrieve the GtkTextBuffer instance that stores the
  // text displayed by the GtkTextView widget
  GtkTextBuffer *buffer = gtk_text_view_get_buffer (self->main_text_view);

  // Set the text using the contents of the file
  gtk_text_buffer_set_text (buffer, contents, length);

  // Reposition the cursor so it's at the start of the text
  GtkTextIter start;
  gtk_text_buffer_get_start_iter (buffer, &start);
  gtk_text_buffer_place_cursor (buffer, &start);

  // Set the title using the display name
  gtk_window_set_title (GTK_WINDOW (self), display_name);

  // Show a toast for the successful loading
  g_autofree char *msg =
    g_strdup_printf ("Opened “%s”", display_name);

  adw_toast_overlay_add_toast (self->toast_overlay, adw_toast_new (msg));
}

保存文件后通知

  1. save_file_complete 函数中,您可以使用 toast 来通知用户操作成功或失败

static void
save_file_complete (GObject          *source_object,
                    GAsyncResult     *result,
                    gpointer          user_data)
{
  GFile *file = G_FILE (source_object);
  TextViewerWindow *self = user_data;

  g_autoptr (GError) error =  NULL;
  g_file_replace_contents_finish (file, result, NULL, &error);

  // Query the display name for the file
  g_autofree char *display_name = NULL;
  g_autoptr (GFileInfo) info =
  g_file_query_info (file,
                     "standard::display-name",
                     G_FILE_QUERY_INFO_NONE,
                     NULL,
                     NULL);
  if (info != NULL)
    {
      display_name =
        g_strdup (g_file_info_get_attribute_string (info, "standard::display-name"));
    }
  else
    {
      display_name = g_file_get_basename (file);
    }

  g_autofree char *msg = NULL;
  if (error != NULL)
    msg = g_strdup_printf ("Unable to save as “%s”", display_name);
  else
    msg = g_strdup_printf ("Saved as “%s”", display_name);

  adw_toast_overlay_add_toast (self->toast_overlay, adw_toast_new (msg));
}

在本教程中,您学习了如何使用 toast 通知用户长时间运行的操作是成功还是失败。