Pular para o conteúdo
CrossFly é 100% open sourceSiga no GitHub
CrossFlyCrossFly
Começar
Todos os exemplos
ReceitasDispositivo124 linhas · 1 arquivos

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.

O que isto mostra

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.

Rodar na sua máquina

Todo exemplo é uma Window comum, então o launcher só precisa do nome dela.

gradlew lwjgl3:run --args="classname dev.cf.recipe.R25Map"
Editar o exemplo

Java é compilado antes de rodar, então o navegador não consegue reconstruir uma edição sozinho — o código que você vê aqui virou JavaScript pelo TeaVM antes de ser publicado. Copie o arquivo para um projeto e ele roda sem mudanças nas quatro plataformas; o comando acima é toda a preparação.

Rodando aquiCrossFly 0.1.32
Iniciando o aplicativo…

Compilado para JavaScript pelo TeaVM — é o mesmo código, não um vídeo dele. · Todos os exemplos

O que ele usa

Tipos do framework que este exemplo toca. Os que têm link têm página de referência.

ButtonComponentDebugGapGridLayoutLatLonMapMapContainerMapPinMaterialIconStylesVerticalLayoutWidgetsWindow

O código

Completo, sem cortes. É o arquivo, não um trecho dele.

Bruto
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);
         }
      }
   }
}
Para uma IA

Versões desta página legíveis por máquina, para um modelo ler a prateleira em vez de adivinhar a API.

Este exemplo, em JSONEste exemplo, em Markdown
AnteriorFloating action buttonPróximoImages