- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
此问题仅针对代号一。
用例
一些应用程序,如 Instagram,具有 x 轴可滚动框,如本视频所示:
https://www.informatica-libera.net/videoLavoro/Video-2019-02-07-11-16-59_0569.mp4
实现起来似乎很容易(将 BoxLayout.x()
设置为可在 x 轴上滚动),但实现起来并不容易。有一个隐藏的复杂性:每个框的宽度是屏幕宽度的百分比,因为用户应该看到第一个框和第二个框的一小部分,以了解滚动是可能的。也许这在 Instagram 应用中还不够明显,但在其他应用中更明显。
我做了什么
我不知道如何嵌套 Codename One 布局以满足 x 滚动 BoxLayout.x
的要求,其中每个 Component
都应该占据屏幕宽度的 60%。然而,我设法通过自定义 Layout
获得了非常相似的东西,但有一个大问题:我没有找到一种方法来根据内容自动计算框的高度。目前我有一个百分比宽度和一个固定高度。请观看在模拟器中拍摄的视频:
https://www.informatica-libera.net/videoLavoro/Video-2019-02-07-11-38-10_0570.mp4
我的方法的另一个问题是我的代码不适用于 SpanLabel
(我将文本拆分为标记,并为每个标记创建了一个 Label
)。
我的代码
以下代码是一个测试用例,可以很容易地复制和运行。注意,真题是根据用户数据生成的,所以提前不知道题长。此外,平板电脑的屏幕宽度与智能手机的屏幕宽度不同(因此这两种情况下的高度应该不同)。目前我设置的固定高度为20mm。
TestBoxes.java
import static com.codename1.ui.CN.*;
import com.codename1.ui.Form;
import com.codename1.ui.Dialog;
import com.codename1.ui.Label;
import com.codename1.ui.plaf.UIManager;
import com.codename1.ui.util.Resources;
import com.codename1.io.Log;
import com.codename1.ui.Button;
import com.codename1.ui.Component;
import com.codename1.ui.Container;
import com.codename1.ui.Display;
import com.codename1.ui.Toolbar;
import com.codename1.ui.geom.Dimension;
import com.codename1.ui.layouts.BoxLayout;
import com.codename1.ui.layouts.FlowLayout;
import com.codename1.ui.layouts.Layout;
import com.codename1.util.StringUtil;
import java.util.LinkedHashMap;
import java.util.List;
/**
* This file was generated by <a href="https://www.codenameone.com/">Codename
* One</a> for the purpose of building native mobile applications using Java.
*/
public class TestBoxes {
private Form current;
private Resources theme;
public void init(Object context) {
// use two network threads instead of one
updateNetworkThreadCount(2);
theme = UIManager.initFirstTheme("/theme");
// Enable Toolbar on all Forms by default
Toolbar.setGlobalToolbar(true);
// Pro only feature
Log.bindCrashProtection(true);
addNetworkErrorListener(err -> {
// prevent the event from propagating
err.consume();
if (err.getError() != null) {
Log.e(err.getError());
}
Log.sendLogAsync();
Dialog.show("Connection Error", "There was a networking error in the connection to " + err.getConnectionRequest().getUrl(), "OK", null);
});
}
public void start() {
if (current != null) {
current.show();
return;
}
Form hi = new Form("Test Boxes", BoxLayout.y());
hi.add(getCompleteProfileCnt());
hi.show();
}
public void stop() {
current = getCurrentForm();
if (current instanceof Dialog) {
((Dialog) current).dispose();
current = getCurrentForm();
}
}
public void destroy() {
}
public Container getCompleteProfileCnt() {
LinkedHashMap<String, Form> questions = new LinkedHashMap<>(6);
int count = getRemainingQuestions(questions);
Label completeProfileLabel = new Label("Complete your profile");
Container boxQuestions = new Container(new BoxLayout(BoxLayout.X_AXIS_NO_GROW));
boxQuestions.setScrollableX(true);
for (String question : questions.keySet()) {
Button button = new Button("Complete");
if (questions.get(question) != null) {
button.addActionListener(l -> {
questions.get(question).show();
});
} else {
button.addActionListener(l -> {
Log.p("To be implemented...");
});
}
Container boxSingleQuestion = new Container(new FixedBoxLayout(60, 20), "ProfileUtilities-BoxSingleQuestion");
Container questionCnt = FlowLayout.encloseCenter(getArrayLabels(question, "Label"));
Container singleQuestionCnt = BoxLayout.encloseYBottomLast(questionCnt, FlowLayout.encloseCenter(button));
questionCnt.setUIID("ProfileUtilities-QuestionCnt");
singleQuestionCnt.setUIID("ProfileUtilities-SingleQuestionCnt");
boxSingleQuestion.add(singleQuestionCnt);
boxQuestions.add(boxSingleQuestion);
}
Container resultCnt = new Container(BoxLayout.y());
resultCnt.add(completeProfileLabel);
resultCnt.add(boxQuestions);
return resultCnt;
}
/**
* Inserts in the given "questions" Map the remaining questions to complete
* the profile of the current logged user, and returns the number of all
* questions (that can be >= to the remaining questions);
*
* @param questions, note that the Map will be cleared before adding the
* remaining questions
*
* @return
*/
private int getRemainingQuestions(LinkedHashMap<String, Form> questions) {
// THIS METHOD IS AN EXAMPLE, the questions are generated according to the user data
int countTotalQuestions = 3;
if (questions == null) {
throw new IllegalArgumentException("ProfileUtilities.getRemainingQuestions invalid \"questions\" param, because it's null");
}
questions.clear();
questions.put("Question 1 - Suppose that this a long text, try to make it longer", null);
questions.put("Question 2 - Suppose a short text", null);
questions.put("Question 3 - Suppose a short text plus an icon", null);
return countTotalQuestions;
}
public static List<String> tokenize(String text, String separator) {
if (separator == null) {
separator = "\n";
}
return StringUtil.tokenize(text, separator);
}
/**
* Converts a string to an array of Labels, that can be placed in a
* FlowLayout: conceptually similar to RichTextView, it serves for special
* use cases (like custom layouts) where a SpanLabel doesn't work well.
*
* @param text
* @param UIID for font style, note that margin and padding will be ignored
* @return
*/
public static Label[] getArrayLabels(String text, String UIID) {
List words = tokenize(UIManager.getInstance().localize(text, text), " ");
Label[] labels = new Label[words.size()];
for (int i = 0; i < words.size(); i++) {
labels[i] = new Label(words.get(i) + " ", UIID);
labels[i].getAllStyles().setMargin(0, 0, 0, 0);
labels[i].getAllStyles().setPadding(0, 0, 0, 0);
}
return labels;
}
class FixedBoxLayout extends Layout {
private int preferredWidth;
private final int preferredHeight;
private boolean isListenerAdded = false;
private int percentageWidth;
public FixedBoxLayout(int percentageWidth, float heightMM) {
preferredWidth = Display.getInstance().getDisplayWidth() * percentageWidth / 100;
preferredHeight = Display.getInstance().convertToPixels(heightMM);
this.percentageWidth = percentageWidth;
}
@Override
public void layoutContainer(Container parent) {
Component cmp = parent.getComponentAt(0);
cmp.setWidth(preferredWidth);
cmp.setPreferredW(preferredWidth);
cmp.setHeight(preferredHeight);
cmp.setPreferredH(preferredHeight);
if (cmp instanceof Container) {
for (Component inner : ((Container) cmp).getChildrenAsList(true)) {
inner.setWidth(preferredWidth);
inner.setPreferredW(preferredWidth);
}
}
if (!isListenerAdded) {
isListenerAdded = true;
parent.getComponentForm().addSizeChangedListener(l -> {
preferredWidth = Display.getInstance().getDisplayWidth() * percentageWidth / 100;
parent.revalidate();
});
}
}
@Override
public Dimension getPreferredSize(Container parent) {
return new Dimension(preferredWidth, preferredHeight);
}
}
}
主题.css
#Constants {
includeNativeBool: true;
}
/* Default text and color */
Default, Label, TextArea, TextField {
font-family: "native:MainRegular";
font-size: 3mm;
color: black;
}
Button {
font-family: "native:MainRegular";
font-size: 3mm;
color: white;
background-color: black;
border: 0.2mm black cn1-pill-border;
padding: 0.5mm 1mm 0.5mm 1mm; /* top, right, bottom, left */
margin: 1mm;
}
Button.pressed, Button.selected {
color: black;
background-color: white;
}
Button.disabled {
color: white;
background-color: gray;
}
ProfileUtilities-completeProfileLabel {
font-family: "native:MainBold";
font-size: 3.5mm;
color: black;
margin: 1mm;
padding: 0;
margin-bottom: 0;
}
ProfileUtilities-completeProfileBox {
margin: 0;
margin-top: 1mm;
margin-bottom: 1mm;
border: 1pt #3399ff solid;
border-radius: 2mm;
}
ProfileUtilities-CompletedQuestions {
font-family: "native:MainRegular";
font-size: 3mm;
color: darkgoldenrod;
margin: 1mm;
margin-top: 0;
padding: 0;
}
ProfileUtilities-SingleQuestionLabel {
font-family: "native:MainBold";
font-size: 3mm;
color: darkslateblue;
text-align: center;
padding: 2mm;
}
ProfileUtilities-BoxSingleQuestion {
border: 1pt darkmagenta solid;
border-radius: 2mm;
/* This is the margin between boxes */
margin: 1mm;
}
ProfileUtilities-SingleQuestionCnt {
/* This is the padding inside each box */
padding: 0;
padding-top: 1mm;
padding-bottom: 1mm;
}
ProfileUtilities-QuestionCnt {
/* This is the padding of each question text */
padding: 2mm;
}
此测试用例的屏幕截图:
我的问题
我需要一个适合这个用例的代码,改进我现有的代码(或者如果我的代码错误太多,则编写一个新代码)。谢谢
最佳答案
编辑,这仍然需要根据您的需要进行一些调整,但这是我更改的要点:
Container boxSingleQuestion = new Container(BoxLayout.y(), "ProfileUtilities-BoxSingleQuestion");
Container questionCnt = new Container(new FlowLayout(CENTER)) {
@Override
protected Dimension calcPreferredSize() {
Dimension d = super.calcPreferredSize();
d.setWidth(Math.min(getDisplayWidth(), getDisplayHeight()) / 10 * 6);
d.setHeight(d.getHeight() / 10 * 18);
return d;
}
};
questionCnt.addAll(getArrayLabels(question, "Label"));
Container singleQuestionCnt = BorderLayout.center(questionCnt).
add(SOUTH, FlowLayout.encloseCenter(button));
questionCnt.setUIID("ProfileUtilities-QuestionCnt");
singleQuestionCnt.setUIID("ProfileUtilities-SingleQuestionCnt");
boxSingleQuestion.add(singleQuestionCnt);
boxQuestions.add(boxSingleQuestion);
我删除了专为全屏设计的 YLast 布局的特殊布局和用法,在这种情况下可能无法正常工作。一般来说,我所做的是减少首选宽度,然后将首选高度增加一个固定值。通过使用 BorderLayout,底部的按钮将始终可见。
原回答如下:
您正在从布局更改组件的首选高度/宽度。那是错误的,你永远不应该那样做。布局应该只设置宽度/高度。如果您设置宽度,您可以使用首选高度来获得正确的高度。要确保所有组件具有相同的高度,只需在组件上循环:
int height = 0;
for(Component c : parent) {
height = Math.max(height, c.getPreferredH());
}
假设您将代码修改为不更改首选宽度或高度(宽度也会影响高度!),这应该会为您提供高度!
一种稍微简单的方法是使用 BoxLayout.X 并为您的组件覆盖 calcPreferredSize() 以返回等于屏幕大小 60% 的值。
关于codenameone - Codename 一种具有百分比宽度和自适应高度的自定义布局,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54573047/
好的,所以我编辑了以下... 只需将以下内容放入我的 custom.css #rt-utility .rt-block {CODE HERE} 但是当我尝试改变... 与 #rt-sideslid
在表格 View 中,我有一个自定义单元格(在界面生成器中高度为 500)。在该单元格中,我有一个 Collection View ,我按 (10,10,10,10) 固定到边缘。但是在 tablev
对于我的无能,我很抱歉,但总的来说,我对 Cocoa、Swift 和面向对象编程还很陌生。我的主要来源是《Cocoa Programming for OS X》(第 5 版),以及 Apple 的充满
我正在使用 meta-tegra 为我的 NVIDIA Jetson Nano 构建自定义图像。我需要 PyTorch,但没有它的配方。我在设备上构建了 PyTorch,并将其打包到设备上的轮子中。现
在 jquery 中使用 $.POST 和 $.GET 时,有没有办法将自定义变量添加到 URL 并发送它们?我尝试了以下方法: $.ajax({type:"POST", url:"file.php?
Traefik 已经默认实现了很多中间件,可以满足大部分我们日常的需求,但是在实际工作中,用户仍然还是有自定义中间件的需求,为解决这个问题,官方推出了一个 Traefik Pilot[1] 的功
我想让我的 CustomTextInputLayout 将 Widget.MaterialComponents.TextInputLayout.OutlinedBox 作为默认样式,无需在 XML 中
我在 ~/.emacs 中有以下自定义函数: (defun xi-rgrep (term) (grep-compute-defaults) (interactive "sSearch Te
我有下表: 考虑到每个月的权重,我的目标是在 5 个月内分散 10,000 个单位。与 10,000 相邻的行是我最好的尝试(我在这上面花了几个小时)。黄色是我所追求的。 我试图用来计算的逻辑如下:计
我的表单中有一个字段,它是文件类型。当用户点击保存图标时,我想自然地将文件上传到服务器并将文件名保存在数据库中。我尝试通过回显文件名来测试它,但它似乎不起作用。另外,如何将文件名添加到数据库中?是在模
我有一个 python 脚本来发送电子邮件,它工作得很好,但问题是当我检查我的电子邮件收件箱时。 我希望该用户名是自定义用户名,而不是整个电子邮件地址。 最佳答案 发件人地址应该使用的格式是: You
我想减小 ggcorrplot 中标记的大小,并减少文本和绘图之间的空间。 library(ggcorrplot) data(mtcars) corr <- round(cor(mtcars), 1)
GTK+ noob 问题在这里: 是否可以自定义 GtkFileChooserButton 或 GtkFileChooserDialog 以删除“位置”部分(左侧)和顶部的“位置”输入框? 我实际上要
我正在尝试在主页上使用 ajax 在 magento 中使用 ajax 显示流行的产品列表,我可以为 5 或“N”个产品执行此操作,但我想要的是将分页工具栏与结果集一起添加. 这是我添加的以显示流行产
我正在尝试使用 PasswordResetForm 内置函数。 由于我想要自定义表单字段,因此我编写了自己的表单: class FpasswordForm(PasswordResetForm):
据我了解,新的 Angular 7 提供了拖放功能。我搜索了有关 DnD 的 Tree 组件,但没有找到与树相关的内容。 我在 Stackblitz 上找到的一个工作示例.对比drag'ndrop功能
我必须开发一个自定义选项卡控件并决定使用 WPF/XAML 创建它,因为我无论如何都打算学习它。完成后应该是这样的: 到目前为止,我取得了很好的进展,但还有两个问题: 只有第一个/最后一个标签项应该有
我要定制xtable用于导出到 LaTeX。我知道有些问题是关于 xtable在这里,但我找不到我要找的具体东西。 以下是我的表的外观示例: my.table <- data.frame(Specif
用ejs在这里显示日期 它给我结果 Tue Feb 02 2016 16:02:24 GMT+0530 (IST) 但是我需要表现为 19th January, 2016 如何在ejs中执行此操作?
我想问在 JavaFX 中使用自定义对象制作 ListView 的最佳方法,我想要一个每个项目如下所示的列表: 我搜了一下,发现大部分人都是用细胞工厂的方法来做的。有没有其他办法?例如使用客户 fxm
我是一名优秀的程序员,十分优秀!