मुख्य सामग्री पर जाएँ
CrossFly 100% ओपन सोर्सGitHub पर फ़ॉलो करें
CrossFlyCrossFly
शुरू करें
सभी उदाहरण
रेसिपीड्रॉइंग119 पंक्तियाँ · 1 फ़ाइलें

Painting your own

A component is a rectangle that can draw. width/height are yours, getAutoHeight says how much room you want, and onPaint puts something in it.

यह क्या दिखाता है

Painting something the framework does not have — and when not to.

Reach for onPaint when the thing you need is a drawing: a gauge, a sparkline, a seat map, a signature. Do not reach for it to make a card look different — that is a ComponentStyle, and a card painted by hand loses the skin, the theme, the press state and the shadow, all of which you then rebuild worse.

Three rules hold for everything drawn here. Sizes come from Styles.fontHeight, so the drawing scales with density instead of shrinking on a good screen. Colours come from tokens, so it follows the theme. And onPaint runs every frame — it may compute, but it must not allocate, which is why the shapes below are fields and not locals.

अपनी मशीन पर चलाएँ

हर उदाहरण एक साधारण Window है, इसलिए लॉन्चर को सिर्फ़ उसका नाम चाहिए।

gradlew lwjgl3:run --args="classname dev.cf.recipe.R23Painting"
इसे बदलना

Java पहले से संकलित होता है, इसलिए ब्राउज़र आपके बदलाव को खुद दोबारा नहीं बना सकता — यहाँ दिखा कोड प्रकाशित होने से पहले TeaVM द्वारा JavaScript में बदला गया था। फ़ाइल को किसी प्रोजेक्ट में कॉपी कीजिए और वह चारों प्लेटफ़ॉर्म पर बिना बदलाव चलती है; ऊपर दी गई कमांड ही पूरी तैयारी है।

यहीं चल रहा हैCrossFly 0.1.32
ऐप शुरू हो रहा है…

TeaVM ने इसे JavaScript में संकलित किया — यह वही कोड है, उसका वीडियो नहीं। · सभी उदाहरण

यह क्या इस्तेमाल करता है

इस उदाहरण में छुए गए फ़्रेमवर्क टाइप। जिनमें लिंक है उनका संदर्भ पृष्ठ मौजूद है।

CardColorUtilsComponentGRectPaintStylesWidgets

सोर्स कोड

पूरा, बिना कटौती के। यह वही फ़ाइल है, उसका अंश नहीं।

कच्चा
dev/cf/recipe/R23Painting.java
package dev.cf.recipe;

import dev.cf.Tones;

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

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

/**
 * Painting something the framework does not have — and when not to.
 *
 * <p>Reach for {@code onPaint} when the thing you need is <b>a drawing</b>: a gauge, a sparkline, a
 * seat map, a signature. Do not reach for it to make a card look different — that is a
 * {@code ComponentStyle}, and a card painted by hand loses the skin, the theme, the press state and
 * the shadow, all of which you then rebuild worse.</p>
 *
 * <p>Three rules hold for everything drawn here. Sizes come from {@code Styles.fontHeight}, so the
 * drawing scales with density instead of shrinking on a good screen. Colours come from tokens, so
 * it follows the theme. And {@code onPaint} runs every frame — it may compute, but it must not
 * allocate, which is why the shapes below are fields and not locals.</p>
 */
public class R23Painting extends Recipe
{
   public String title()
   {
      return "Painting your own";
   }

   public String note()
   {
      return "A component is a rectangle that can draw. width/height are yours, getAutoHeight says"
         + " how much room you want, and onPaint puts something in it.";
   }

   public void build(Component body) throws Exception
   {
      body.add(LAY_AUTO, outgap(label("A bar with a target line — the kind of thing no widget set"
         + " has, because the target is your idea.", 1f, false, Styles.captionColor,
         Position.START), 0, 0, 0, .8f));

      for (int i = 0; i < 4; i++)
      {
         Card c = new Card();
         // The bar is NOT toned: the class above reasons that over-target must read as more of the
         // same hue, and four hues would take that away. The name carries the colour instead.
         c.add(LAY_AUTO, label(new String[] { "North", "South", "East", "West" }[i], 1.2f, true,
            Tones.accent(), Position.START));
         Meter m = new Meter(new float[] { .82f, .41f, 1.12f, .67f }[i]);
         c.add(LAY_AUTO, outgap(m, 0, .3f, 0, 0));
         body.add(LAY_AUTO, outgap(c, 0, 0, 0, .5f));
      }
   }

   /**
    * A bar against a target: filled to {@code value}, with a line at 100% and the excess in a
    * different tone.
    */
   private static class Meter extends Component
   {
      /** Shapes as FIELDS: onPaint runs every frame, and allocating there is how you make garbage. */
      private final GRect track = new GRect(), fill = new GRect(), mark = new GRect();

      private final float value;

      Meter(float value)
      {
         this.value = value;
      }

      /**
       * How tall this wants to be. Expressed in font heights, so it grows with the type rather than
       * staying a fixed number of pixels that is right on exactly one screen.
       */
      @Override
      public int getAutoHeight()
      {
         return Math.round(Styles.fontHeight * 1.1f);
      }

      @Override
      public void onPaint(Paint paint) throws Exception
      {
         int r = height / 2;
         int reached = Math.round(Math.min(value, 1f) * width);

         track.clear()
            .bounds(0, 0, width, height)
            .radius(r)
            .fill(ColorUtils.lerpColor(Styles.backColor.color(), Styles.textColor.color(), .1f));
         paint.rect(track);

         // Over target gets its own tone. A bar that just stops at 100% hides the best news on the
         // screen, and one that keeps growing past the edge hides the worst.
         fill.clear()
            .bounds(0, 0, reached, height)
            .radius(r)
            // Over target gets a DEEPER shade of the same hue, not a different colour: the reader
            // should see "more of the same thing", and tertiary() on a blue seed resolves to a
            // muted tone that reads as less rather than more.
            .fill(value > 1f
               ? ColorUtils.lerpColor(Styles.primaryColor.color(), Styles.textColor.color(), .4f)
               : Styles.primaryColor.color());
         paint.rect(fill);

         // The target line. One pixel is invisible on a dense screen — measure it in font units.
         int t = Math.max(2, Math.round(Styles.fontHeight * .08f));
         mark.clear()
            .bounds(width - t, -t, t, height + t * 2)
            .fill(Styles.textColor.color());
         paint.rect(mark);
      }
   }
}
एआई सहायक के लिए

इस पृष्ठ के मशीन-पठनीय रूप, ताकि मॉडल API का अनुमान लगाने के बजाय उदाहरण पढ़ सके।

यह उदाहरण, JSON मेंयह उदाहरण, Markdown में
पिछलाAnimationअगलाFloating action button