跳到内容
CrossFly 是 100% 开源在 GitHub 关注我们
CrossFlyCrossFly
开始使用
全部示例
配方反馈97 行 · 1 个文件

Telling the user something

Interrupt in proportion to what you need back. A confirmation on something reversible teaches people to dismiss confirmations — including the one that mattered.

它展示了什么

Four ways to tell the user something, and the question that picks between them.

The question is what do you need from them: nothing, a decision, a choice from a few, or nothing but they must not miss it. Getting this wrong is why apps end up asking "OK?" about things that were never in doubt — and why the one destructive action arrives as a toast nobody reads.

在你的机器上运行

每个示例都是普通的 Window,启动器只需要它的名字。

gradlew lwjgl3:run --args="classname dev.cf.recipe.R11Telling"
修改它

Java 是提前编译的,浏览器无法自行重建你的修改 —— 这里的代码在发布前已由 TeaVM 转成 JavaScript。把文件复制到项目里,它在四个平台上原样运行;上面那条命令就是全部准备工作。

正在此处运行CrossFly 0.1.32
正在启动应用…

由 TeaVM 编译为 JavaScript —— 是同一份代码,不是录像。 · 全部示例

它用到了什么

本示例触及的框架类型。带链接的有参考页。

ActionSheetAlertButtonCardComponentHintPalColorStylesWidgets

源码

完整无删减。这就是那个文件,不是片段。

原始
dev/cf/recipe/R11Telling.java
package dev.cf.recipe;

import dev.cf.Tones;

import dev.crossfly.ui.*;
import dev.crossfly.ui.color.*;
import dev.crossfly.ui.graphics.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.style.*;

import static dev.crossfly.ui.Widgets.*;

/**
 * Four ways to tell the user something, and the question that picks between them.
 *
 * <p>The question is <b>what do you need from them</b>: nothing, a decision, a choice from a few,
 * or nothing but they must not miss it. Getting this wrong is why apps end up asking "OK?" about
 * things that were never in doubt — and why the one destructive action arrives as a toast nobody
 * reads.</p>
 */
public class R11Telling extends Recipe
{
   private static final int IC_HINT = 0xE7F4, IC_ALERT = 0xE002, IC_SHEET = 0xE5D2,
      IC_INLINE = 0xE000;

   public String title()
   {
      return "Telling the user something";
   }

   public String note()
   {
      return "Interrupt in proportion to what you need back. A confirmation on something reversible"
         + " teaches people to dismiss confirmations — including the one that mattered.";
   }

   public void build(Component body) throws Exception
   {
      // The tones climb with the interruption: the one that needs nothing back wears the quiet
      // supporting tone, the one that stops the user and the one they must fix wear the error
      // tone. Four identical grey cards said the opposite of what the screen is about.
      row(body, IC_HINT, Tones.support(), "Hint — nothing needed", "It happened. A toast that"
         + " fades, over the screen the user is already looking at.",
         () -> Hint.show("Saved", 2000));

      row(body, IC_SHEET, Tones.highlight(), "ActionSheet — one of a few", "Three or four actions"
         + " on one object. Cheaper than a screen, clearer than a long-press nobody discovers.",
         this::sheet);

      row(body, IC_ALERT, Tones.danger(), "Alert — a decision", "Two ways forward and the app"
         + " cannot pick. Name the thing in the question: \"Delete this?\" is not answerable.",
         this::alert);

      row(body, IC_INLINE, Tones.danger(), "Inline — they must fix it", "A validation message"
         + " belongs next to the field, not in a dialog they have to dismiss before they can act"
         + " on it.", null);
   }

   private void alert()
   {
      Alert a = new Alert("Discard this draft?", "It has not been sent, and this cannot be undone.",
         "Keep editing", "Discard");
      // Index 1 is the second button. The destructive one goes LAST: the safe choice is where the
      // thumb rests, and the dangerous one costs a deliberate reach.
      a.buttonAction(1, c -> Hint.show("Discarded", 1500));
      a.show();
   }

   private void sheet()
   {
      ActionSheet s = new ActionSheet("Cancel", "Share", "Duplicate", "Export");
      for (int i = 0; i < 3; i++)
      {
         final int idx = i;
         s.buttonAction(idx, c -> Hint.show(new String[] { "Shared", "Duplicated", "Exported" }[idx],
            1500));
      }
      s.show();
   }

   private void row(Component body, int icone, PalColor tom, String title, String why,
      Runnable demo) throws Exception
   {
      Card c = Tones.card(tom);
      c.add(LAY_AUTO, outgap(Tones.head(icone, title, tom), 0, 0, 0, 0));
      c.add(LAY_AUTO, outgap(label(why, 1f, false, Styles.captionColor, Position.START), 0, .2f, 0,
         demo == null ? 0 : .5f));
      if (demo != null)
      {
         Button b = Tones.action("Show it", tom);
         b.onAction(e -> demo.run());
         c.add(LAY_AUTO, b);
      }
      body.add(LAY_AUTO, outgap(c, 0, 0, 0, .6f));
   }
}
给 AI 助手

本页的机器可读版本,让模型直接读取示例集,而不是猜测 API。

本示例(JSON)本示例(Markdown)
上一个A form that fights back下一个Bottom nav that becomes a rail