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

A map with pins

OSM needs no API key, so a map works the moment you write it. Opens in a window of its own — a native view inside a scrolling page floats over everything around it.

它展示了什么

A real map with pins on it, and the two things that make a map different from every other widget.

It is a native view on top of the GL canvas, not a component inside it. It does not scroll with a parent, does not clip to one, and does not take part in a screen transition — a fade over a map shows a black rectangle for the whole animation. So a map gets a rectangle of its own and every control you want over it goes outside that rectangle, in ordinary components.

The engine is a constructor argument. Changing provider means building a new MapContainer — there is no setter, and there should not be one. OSM needs no key and is the right default for anything that is not shipping; GOOGLE needs MapContainer.googleMapsKey set before the container is built.

Opened on a button rather than built into this screen, on purpose: a native view inside a scrolling recipe list would float over the recipes above and below it.

在你的机器上运行

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

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

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

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

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

它用到了什么

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

ButtonComponentDebugGapGridLayoutLatLonMapMapContainerMapPinMaterialIconStylesVerticalLayoutWidgetsWindow

源码

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

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

import dev.cf.Tones;

import dev.crossfly.map.*;
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 java.util.ArrayList;
import java.util.List;

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

/**
 * A real map with pins on it, and the two things that make a map different from every other widget.
 *
 * <p><b>It is a native view on top of the GL canvas</b>, not a component inside it. It does not
 * scroll with a parent, does not clip to one, and does not take part in a screen transition — a
 * fade over a map shows a black rectangle for the whole animation. So a map gets a rectangle of its
 * own and every control you want over it goes <i>outside</i> that rectangle, in ordinary
 * components.</p>
 *
 * <p><b>The engine is a constructor argument.</b> Changing provider means building a new
 * {@link MapContainer} — there is no setter, and there should not be one. {@code OSM} needs no key
 * and is the right default for anything that is not shipping; {@code GOOGLE} needs
 * {@code MapContainer.googleMapsKey} set before the container is built.</p>
 *
 * <p>Opened on a button rather than built into this screen, on purpose: a native view inside a
 * scrolling recipe list would float over the recipes above and below it.</p>
 */
public class R25Map extends Recipe
{
   /** A few coordinates to plot. Real ones come from your store — with the nulls filtered out. */
   private static final double[][] WHERE = { { 53.7996, -1.5491 }, { 51.2194, 4.4025 },
      { 41.1579, -8.6291 }, { 45.0703, 7.6869 }, { 55.6050, 13.0038 }, { 51.4545, -2.5879 } };
   private static final String[] WHO = { "Northgate", "Bellamy", "Kestrel", "Halden & Roe",
      "Ironvale", "Meridian" };

   public String title()
   {
      return "A map with pins";
   }

   public String note()
   {
      return "OSM needs no API key, so a map works the moment you write it. Opens in a window of"
         + " its own — a native view inside a scrolling page floats over everything around it.";
   }

   public void build(Component body) throws Exception
   {
      body.add(LAY_AUTO, outgap(label("Six suppliers, plotted from coordinates. The pins are data;"
         + " the map only draws them.", 1f, false, Styles.captionColor, Position.START), 0, 0, 0,
         1f));

      Button open = Tones.action("Open the map");
      open.testTag("map.open");
      open.onAction(c -> new MapScreen().show());
      body.add(LAY_AUTO, open);
   }

   /** The map, in a window of its own, with the app's chrome kept outside its rectangle. */
   private static class MapScreen extends Window
   {
      private MapContainer container;

      @Override
      public void onAdd(boolean firstTime) throws Exception
      {
         if (!firstTime)
            return;
         fullscreenColor = Styles.backColor.color();
         setLayout(new VerticalLayout(Position.START, Position.START));

         Component bar = new Component();
         bar.setLayout(new GridLayout(Position.START, Position.CENTER));
         bar.getStyle()
            .ingap(Gap.ofFont(.6f, .5f, .6f, .5f));
         Button back = new Button(MaterialIcon.of(0xE5C4, 1.4f));
         back.onAction(c -> hide());
         bar.add(0f, 1f, back, outgap(label("Suppliers", 1.5f, true, Styles.textColor,
            Position.START), .6f, 0, 0, 0));
         add(0f, bar);

         // OSM: no key, no account, works offline against its own tiles cache. The callback fires
         // when the native view is ready — plotting before that plots into nothing.
         container = new MapContainer(Map.MapEngine.OSM, 0, this::plot);
         add(LAY_FILL, container);
      }

      private void plot()
      {
         try
         {
            final List<MapPin> pins = new ArrayList<>();
            double lat = 0, lon = 0;
            for (int i = 0; i < WHERE.length; i++)
            {
               pins.add(new MapPin().position(WHERE[i][0], WHERE[i][1])
                  .title(WHO[i])
                  .snippet("Supplier"));
               lat += WHERE[i][0];
               lon += WHERE[i][1];
            }

            // batch(): every add is a call across to the native view, and six of them is six
            // round-trips and six redraws. Inside a batch it is one. At six pins nobody notices;
            // at six hundred it is the difference between a map and a freeze.
            container.map.batch(() -> container.map.add(pins.toArray(new MapPin[0])));

            // Open on the middle of what was plotted, not on a fixed point: a map that opens
            // somewhere the data is not makes the user pan before it tells them anything.
            container.map.centerOnLocation(new LatLon(lat / WHERE.length, lon / WHERE.length), 4);
         }
         catch (Exception e)
         {
            dev.crossfly.util.Debug.handle(e);
         }
      }
   }
}
给 AI 助手

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

本示例(JSON)本示例(Markdown)
上一个Floating action button下一个Images