【问题标题】:Is it possible to make rounded image (via mask) on Multibutton (Codename One)是否可以在多按钮(代号一)上制作圆形图像(通过蒙版)
【发布时间】:2017-02-17 01:24:52
【问题描述】:

我有一个InfiniteScrollAdapter,我在其中使用Multibutton 显示包含照片及其描述的列表。

效果很好,但我需要使照片变圆。这就是为什么我在图像遮罩方面受到the official guide 的启发。不幸的是,我得到的只是一个黑色的圆形。这是我使用的代码:

MultiButton[] cmps = new MultiButton[reports.size()];
for (int iter = 0; iter < reports.size(); iter++) {
    Report currentReport = reports.get(iter);
    if (currentReport == null) {
        InfiniteScrollAdapter.addMoreComponents(this.getContentPane(), new Component[0], false);
        return;
    }

    String photoFilenameInStorage = Report.getFilename(currentReport.getPhotoPath());
    Image reportImage = URLImage.createToStorage(placeholder, photoFilenameInStorage, currentReport.getPhotoPath(), URLImage.RESIZE_SCALE_TO_FILL );
    int w = reportImage.getWidth();
    int h = reportImage.getHeight();

    // Generates a mask to make the image round
    Image maskImage = Image.createImage(w, h, 0xff000000);
    Graphics g = maskImage.getGraphics();
    g.setAntiAliased(true);
    g.setColor(0xFFFFFF);
    g.fillArc(0, 0, w, h, 0, 360);

    Object mask = maskImage.createMask();

    Image maskedImage = reportImage.applyMask(mask);

    String summary = currentReport.getLocation();                        
    cmps[iter] = new MultiButton(summary);
    // Only shows a black filled circle!
    cmps[iter].setIcon(maskedImage);
} 

InfiniteScrollAdapter.addMoreComponents(this.getContentPane(), cmps, true);

我注意到,我能在 CN1 中找到的所有关于圆形图像的示例都处理 Label。是否可以在 Codename One 中的 MultiButton 上应用蒙版?如果是这样,我该怎么做?

任何帮助表示赞赏,

看完答案和cmets 2017-02-16的总结

我很难弄清楚为什么@Diamond 的答案确实有效,而不是我的,尽管我确实遵循了@Shai 的蒙版指南以获得圆形图像。所以我写下我的发现结果,以防 CN1 的其他新手遇到这个问题。再次感谢@Diamond 的精彩解释,帮助很大!

首先,上面介绍的圆形遮罩是有效的,因为它会产生黑色圆形。事实上,在应用掩码时,reportImage 尚未下载 since quoting from the javadoc

默认情况下,图像会在 GUI 请求时延迟获取,除非调用 fetch() 方法,在这种情况下会立即执行 IO 代码。

因此reportImage 仍然与定义的占位符一样黑。顺便说一句,这就是为什么@Diamond 建议定义一个圆形占位符,在实际(圆形)图像可用之前显示漂亮的颜色(请参阅他的回答中的第一个cmps[iter].setIcon(placeholder) 调用)。

只有当InfiniteScrollAdapter 需要并获取图像时才会实际下载 URLImage。这就是 @Diamond 包装的原因

因此作为结论,上面的代码不能在InfiniteScrollAdapter 中工作,经过我所有的试验,我倾向于认为实现我想要做的唯一方法是@Diamond 使用@Shai 的建议编写的代码。

请注意,如果下载的图片是 PNG,@Diamond 的圆形遮罩适配器似乎不再起作用 => 仅当 PNG 转换为 JPEG 时,生成的图像才会被四舍五入

【问题讨论】:

    标签: java codenameone


    【解决方案1】:

    是的,多按钮图标是一个标签组件,你可以通过调用来获得

    cmps[iter].getIconComponent()
    

    编辑:

    根据 Shai 的评论,您的代码应该是这样的......

    圆形面罩适配器:

    private final URLImage.ImageAdapter RESIZE_SCALE_WITH_ROUND_MASK = new URLImage.ImageAdapter() {
        @Override
        public EncodedImage adaptImage(EncodedImage downloadedImage, EncodedImage placeholderImage) {
            Image tmp = downloadedImage.scaledLargerRatio(placeholderImage.getWidth(), placeholderImage.getHeight());
            if (tmp.getWidth() > placeholderImage.getWidth()) {
                int diff = tmp.getWidth() - placeholderImage.getWidth();
                int x = diff / 2;
                tmp = tmp.subImage(x, 0, placeholderImage.getWidth(), placeholderImage.getHeight(), true);
            } else if (tmp.getHeight() > placeholderImage.getHeight()) {
                int diff = tmp.getHeight() - placeholderImage.getHeight();
                int y = diff / 2;
                tmp = tmp.subImage(0, y, Math.min(placeholderImage.getWidth(), tmp.getWidth()),
                        Math.min(placeholderImage.getHeight(), tmp.getHeight()), true);
            }
            Image roundMask = Image.createImage(tmp.getWidth(), tmp.getHeight(), 0xff000000);
            Graphics gr = roundMask.getGraphics();
            gr.setColor(0xffffff);
    
            gr.fillArc(0, 0, tmp.getWidth(), tmp.getHeight(), 0, 360);
            Object mask = roundMask.createMask();
            tmp = tmp.applyMask(mask);
            return EncodedImage.createFromImage(tmp, false);
        }
    
        @Override
        public boolean isAsyncAdapter() {
            return true;
        }
    };
    

    代码改进:

    //Placeholder image
    
    int size = Display.getInstance().convertToPixels(20);
    Image placeholder = Image.createImage(size, size, 0xbfc9d2);
    Graphics g = placeholder.getGraphics();
    g.setAntiAliased(true);
    g.setColor(0xbfc9d2);
    g.fillArc(0, 0, size, size, 0, 360);
    
    MultiButton[] cmps = new MultiButton[reports.size()];
    for (int iter = 0; iter < reports.size(); iter++) {
        Report currentReport = reports.get(iter);
        if (currentReport == null) {
            InfiniteScrollAdapter.addMoreComponents(this.getContentPane(), new Component[0], false);
            return;
        }
    
        String photoFilenameInStorage = Report.getFilename(currentReport.getPhotoPath());
    
        String summary = currentReport.getLocation();
        cmps[iter] = new MultiButton(summary);
        // Only shows a black filled circle!
        cmps[iter].setIcon(placeholder);
    
        Display.getInstance().callSerially(() -> {
           cmps[iter].setIcon( URLImage.createToStorage(cmps[iter].getIcon(), photoFilenameInStorage, currentReport.getPhotoPath(), RESIZE_SCALE_WITH_ROUND_CORNER_MASK));
           cmps[iter].getParent().revalidate();
        });
    }
    InfiniteScrollAdapter.addMoreComponents(this.getContentPane(), cmps, true);
    

    【讨论】:

    • 它是这样工作的:第一个setIcon() 在创建并添加到容器时将所有MultiButtons 的图标设置为占位符图像。第二个setIcon()callSerially() 内部调用,它会延迟远程图标的获取,直到MultiButton 可见。这使得连续滚动和获取无缝。 callSerially 延迟执行直到其他任务完成;在这种情况下,任务是创建组件并将其添加到 InfiniteContainer。
    • 您知道,您的占位符图像应该是圆形的。查看添加的代码。
    • 为防止重复使用旧下载的图像,请清除 .cn1 文件夹中的图像。
    • 哇,非常感谢 Diamond 的解释! .cn1 文件夹清理应该可以解决问题,尽管这个旧的 UrlImage 持久性问题已经发生在我身上好几次了,但我忘记了这个缓存!我会及时通知你的!
    • @Diamond 我编辑了我的问题,并根据您的回答和 cmets 添加了我的代码导致黑轮的原因!
    猜你喜欢
    • 2023-04-02
    • 2012-02-12
    • 2020-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-01
    • 1970-01-01
    相关资源
    最近更新 更多