textfield with scrollable in codenameone - codenameone

I implemented textfield with multiline and scrollable in y-direction. But it works weird as shown in figure below. If I add one text after other in multiline fashion, as soon as I reach the keyboard pop-up the text at top is still visible it just dont scroll till end.
As it can be seen in first image if I scroll it starts going at top of the screen and in second image it just don't show the text written at end. Any suggestions on this will be helpful. Thanks
I even used the DataChangedListener but I think that's not issue here.
dataTextField = (TextField) uib.findByName(DESIGNER_NAME_TEXT_FIELD, container);
dataTextField.setMaxSize(model.getMaxLength());
if (model.isMultiLine()) {
dataTextField.setSingleLineTextArea(false);
dataTextField.setRows(2);
} else {
dataTextField.setSingleLineTextArea(true);
}
dataTextField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (dataTextField != null) {
if (dataTextField.getText().compareTo(model.getData().toString()) != 0) {
updateModel(dataTextField.getText());
}
}
}
});
public void updateModel(String text) {
synchronized(syncLock) {
model.onUserDataEntered(text);
}
}

Related

Scrolling on VBox with lots of Textfields

I am having lots of Textfields in VBox in a Scrollpane. When scrolling and touching a textfields it just grabs the focus. So smooth scrolling is not possible. How can I get it nice scrolling without the unwanted focus on any textfield. Do I need to consume the events on the textfield while scrolling?
This is a possible solution for the case where you want to scroll over a long list of textfields, without letting them take the focus, until you stop scrolling at all, and clearly want to select one of the textfields.
It is based in a custom "press and hold" event, inspired by this question.
The idea is to bundle the TextField control in an HBox, and disable the access to the control using the mouse transparent property of the container.
Then, whenever you tap on the container, if you press long enough the container will give access to the control and the keyboard will show up. Otherwise, you will continue scrolling, but without showing the keyboard.
I'll use the KeyboardService referred in this question on iOS only.
public class BasicView extends View {
public BasicView(String name) {
super(name);
setTop(new Button("Button"));
VBox controls = new VBox(15.0);
controls.setAlignment(Pos.CENTER);
ScrollPane pane = new ScrollPane(controls);
controls.prefWidthProperty().bind(pane.widthProperty().subtract(20));
for (int i = 0; i < 100; i++) {
final Label label = new Label("TextField " + (i + 1));
final TextField textField1 = new TextField();
HBox.setHgrow(textField1, Priority.ALWAYS);
HBox box = new HBox(10, label, textField1);
box.setMouseTransparent(true);
box.setAlignment(Pos.CENTER_LEFT);
box.setPadding(new Insets(5));
controls.getChildren().add(box);
}
addPressAndHoldHandler(controls, Duration.millis(300), eStart -> {
for (Node box : controls.getChildren()) {
box.setMouseTransparent(true);
}
}, eEnd -> {
for (Node box : controls.getChildren()) {
if (box.localToScene(box.getBoundsInLocal()).contains(eEnd.getSceneX(), eEnd.getSceneY())) {
box.setMouseTransparent(false);
((HBox) box).getChildren().get(1).requestFocus();
break;
}
}
});
setCenter(pane);
// iOS only
Services.get(KeyboardService.class).ifPresent(keyboard -> {
keyboard.visibleHeightProperty().addListener((obs, ov, nv) -> {
if (nv.doubleValue() > 0) {
for (Node box : controls.getChildren()) {
Node n1 = ((HBox) box).getChildren().get(1);
if (n1.isFocused()) {
double h = getScene().getHeight() - n1.localToScene(n1.getBoundsInLocal()).getMaxY();
setTranslateY(-nv.doubleValue() + h);
break;
}
}
} else {
setTranslateY(0);
}
});
});
}
#Override
protected void updateAppBar(AppBar appBar) {
appBar.setNavIcon(MaterialDesignIcon.MENU.button(e -> System.out.println("Menu")));
appBar.setTitleText("Scrolling over TextFields");
}
private void addPressAndHoldHandler(Node node, Duration holdTime,
EventHandler<MouseEvent> handlerStart, EventHandler<MouseEvent> handlerEnd) {
class Wrapper<T> {
T content;
}
Wrapper<MouseEvent> eventWrapper = new Wrapper<>();
PauseTransition holdTimer = new PauseTransition(holdTime);
holdTimer.setOnFinished(event -> handlerEnd.handle(eventWrapper.content));
node.addEventHandler(MouseEvent.MOUSE_PRESSED, event -> {
handlerStart.handle(event);
eventWrapper.content = event;
holdTimer.playFromStart();
});
node.addEventHandler(MouseEvent.MOUSE_RELEASED, event -> holdTimer.stop());
node.addEventHandler(MouseEvent.DRAG_DETECTED, event -> holdTimer.stop());
}
}
Note that I've added a button on top to get the focus on the first place when you show the view.
Whenever you click/tap on the controls VBox, it sets all the boxes mouse transparent: box.setMouseTransparent(true);, and start a PauseTransition.
If there is a mouse release or a mouse drag before 300 ms (this could be changed at your convenience), the transition will stop. Otherwise, after 300 ms, it will set the box to box.setMouseTransparent(false);, and set the focus on the TextField, and at that moment the keyboard will show up.
Here is a class which I use for the purpose you describe:
public class MouseClickedFilter{
private final Node observableNode;
private BooleanProperty scrolling = new ReadOnlyBooleanWrapper(false);
private EventHandler<? super MouseEvent> dragDetectedFilter = e -> scrolling.set(true);
private EventHandler<? super MouseEvent> mouseExitedHandler = e -> scrolling.set(false);
private EventHandler<? super MouseEvent> mouseClickedFilter = evt ->
{
if (scrolling.get()) {
evt.consume();
scrolling.set(false);
}
};
private boolean listenersEnabled;
public MouseClickedFilter(Node observableNode) {
this.observableNode = observableNode;
}
public void activate() {
if (!listenersEnabled) {
observableNode.addEventFilter(MouseEvent.DRAG_DETECTED, dragDetectedFilter);
observableNode.addEventHandler(MouseEvent.MOUSE_EXITED, mouseExitedHandler);
observableNode.addEventFilter(MouseEvent.MOUSE_CLICKED, mouseClickedFilter);
}
}
public void deactivate() {
if (listenersEnabled) {
observableNode.removeEventFilter(MouseEvent.DRAG_DETECTED, dragDetectedFilter);
observableNode.removeEventHandler(MouseEvent.MOUSE_EXITED, mouseExitedHandler);
observableNode.removeEventFilter(MouseEvent.MOUSE_CLICKED, mouseClickedFilter);
}
}
public final ReadOnlyBooleanProperty scrollingProperty() {
return scrolling;
}
public final boolean isScrolling() {
return scrolling.get();
}
}
ObservableNode is your ScrollPane containing the textFields

How to disable image fade in effect in React Native?

Situation
Dynamically toggling images
React Native
Dev mode
Android
Problem
The images fade in when appearing during dev mode. This is an issue since I am developing and tuning images animations with actual fade in effects. Is it possible to disable the fade in effect?
Attempts
Switched to release mode. Works but not appropriate during development.
Minimizing the image file size. No visible difference.
Minimizing the image display size. No visible difference.
Just set fadeDuration={0} to Image component, this is not documented
You can check here for more information
I managed to prevent the fade animation by wrapping my <Image /> with a custom ViewGroupManager and setting ReactImageView.mFadeDuration to zero with reflection before the Image is added to the custom ViewGroup.
Edit: But this adds a noticeable delay when displaying the image :( There's actually no delay.
Something like this:
public class NoFadeImageWrapper extends ViewGroup {
public NoFadeImageWrapper(Context context) {
super(context);
}
#Override
public void onViewAdded(View child) {
if (child instanceof ReactImageView) {
((ReactImageView) child).setFadeDuration(0);
ReflectionUtils.setField(child, "mIsDirty", true);
}
super.onViewAdded(child);
}
}
ReflectionUtils.setField implementation:
public class ReflectionUtils {
public static void setField(Object obj, String name, Object value) {
try {
Field field = getField(obj.getClass(), name);
if (field == null) {
return;
}
field.setAccessible(true);
field.set(obj, value);
} catch (Exception e) {
e.printStackTrace();
}
}
}

Codenameone Load overFlow menu

I have customized my form titlebar and added buttons to it. Is it possible to add a listener to one of the buttons to add command(s) an overflow menu and show it.
Yes, command/s can be added to overflow menu by using the following codes and actionPerformed is called when click on the command
Toolbar toolbar = new Toolbar();
f.setToolbar(toolbar);
toolbar.addCommandToOverflowMenu(new Command("Test") {
#Override
public void actionPerformed(ActionEvent evt) {
showForm("NewForm",null);
}
});
Please try this it displays overflow menu when you click on button.
void showOverFlow(final Form f) {
Toolbar toolbar = new Toolbar();
f.setToolBar(toolbar);
toolbar.addCommandToOverflowMenu(new Command("overflow"));
Button button = new Button("show menu");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if (f.getToolbar() != null) {
MenuBar mb = f.getToolbar().getMenuBar();
if (mb != null) {
mb.showMenu();
}
}
}
});
toolbar.addComponent(BorderLayout.WEST,button);
}

Codename One Back Command on left and Menu on Right

i am trying to make an app in Codename one where i want to create a handburger menu on the right side at the top of the screen and a back button on the left side, but cannot get it to work I know it can be done where you have a handburger menu on the left side and a button on the right side. I made a picture of how I want it to look like. The back button is added in paint and not through the code.
Picture of app example
below is the code that I have used to get the menu on the right side.
public class MainForm {
public static Form mainForm;
Command cmd_back, cmd_AboutTheApp;
private enum SideMenuMode {
SIDE, RIGHT_SIDE {
public String getCommandHint() {
return SideMenuBar.COMMAND_PLACEMENT_VALUE_RIGHT;
}
};
public String getCommandHint() {
return null;
}
public void updateCommand(Command c) {
String h = getCommandHint();
if(h == null) {
return;
}
c.putClientProperty(SideMenuBar.COMMAND_PLACEMENT_KEY, h);
}
};
SideMenuMode mode = SideMenuMode.RIGHT_SIDE;
public void init(Object context) {
theme = UIManager.initFirstTheme("/theme");
UIManager.getInstance().setThemeProps(theme.getTheme theme.getThemeResourceNames()[0]));
UIManager.getInstance().getLookAndFeel().setMenuBarClass(SideMenuBar.class);
Display.getInstance().setCommandBehavior(Display.COMMAND_BEHAVIOR_SIDE_NAVIGATION);
}
public void start() {
if(mainForm != null){
mainForm.show();
return;
}
mainForm = new Form();
mainForm.setTitleComponent(title);
mainForm.setLayout(new BorderLayout());
addCommands(mainForm);
}
private void addCommands(Form f){
cmd_Back = new Command("Back");
final Button btn_Back = new Button("Back");
cmd_Back.putClientProperty("TitleCommand", btn_Back);
btn_BackButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//do some thing
}
});
cmd_AboutTheApp = new Command("About the app");
final Button btn_AboutTheApp = new Button("About the app");
cmd_AboutTheApp.putClientProperty("SideComponent", btn_AboutTheApp);
btn_AboutTheApp.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//do some thing
}
});
mode.updateCommand(cmd_Back);
f.addCommand(cmd_Back);
mode.updateCommand(cmd_AboutTheApp);
f.addCommand(cmd_AboutTheApp);
}
}
if I move the back button so that it is added after AboutTheApp button then the back button is displayed on the right side of the screen but also to the right of the menu, which is also on the right side. I've tried a lot of different ways but none seems to be working
We supported a right side menu bar in the SideMenuBar but not in the Toolbar API. We support placing components/commands in the left/right side of the title area in the Toolbar API but not in the SideMenuBar.
I guess the solution is to add support for the right menu bar into the Toolbar API but I'm not sure what the complexities are for such a change.
I suggest filing an RFE in the issue tracker asking for this but it probably won't be soon as we are closing the features for 3.3 right now.
I have an app that does this. Search Google Play (or App Store) for "Torquepower Diesel Cummins Engine" app.
in the theme Constants I set my own rightSideMenuImage and rightSideMenuPressImage, but the default hamburger menu may be OK for you.
On the beforeXXXX of each form I do something like this:
super.beforePartNumberForm(f);
Toolbar tb = createToolbar(f);
createBackCommand(f, tb);
addHelpX(tb);
addViewCartX(tb);
addCallTorquepowerX(tb);
addReverseSwipe(f);
create the toolbar
Toolbar createToolbar(Form f) {
Toolbar tb = new Toolbar();
f.setToolBar(tb);
Label l = new Label();
l.setIcon(res.getImage("tpd_logoZZ.png"));
tb.setTitleComponent(l);
return tb;
}
create the back button
void createBackCommand(Form f, Toolbar tb) {
Command c = new Command("") {
#Override
public void actionPerformed(ActionEvent evt) {
back();
}
};
c.setIcon(res.getImage("black_left_arrow-512.png"));
c.setPressedIcon(res.getImage("grey_left_arrow-512.png"));
// MUST set this before adding to toolbar, else get null pointer
f.setBackCommand(c);
tb.addCommandToLeftBar(c);
}
add whatever commands are needed to the sidemenu
void addHelpX(Toolbar tb) {
Command c = new Command("Help") {
#Override
public void actionPerformed(ActionEvent evt) {
showForm("HelpForm", null);
}
};
c.putClientProperty(SideMenuBar.COMMAND_PLACEMENT_KEY, SideMenuBar.COMMAND_PLACEMENT_VALUE_RIGHT);
c.putClientProperty("SideComponent", new SideMenuItem(fetchResourceFile(), c.toString(), "very_basic_about.png"));
c.putClientProperty("Actionable", Boolean.TRUE);
tb.addCommandToSideMenu(c);
}
I use my own SideMenuItem which is:
public class SideMenuItem extends Button {
SideMenuItem() {
this("");
}
SideMenuItem(String s) {
super(s);
setUIID("SideMenuItem");
int h = Display.getInstance().convertToPixels(8, false);
setPreferredH(h);
}
SideMenuItem(Resources res, String s, String icon) {
super();
setIcon(res.getImage(icon));
setText(s);
setUIID("SideMenuItem");
int h = Display.getInstance().convertToPixels(8, false);
setPreferredH(h);
}
}

FlowDocumentPageViewer mouse scroll navigates to the next pages instead of scrolling to the end of the page first

I am trying to show a PrintPreview in ActualSize Mode and I have the following structure in my xaml:
The problem is when I mouse scroll, instead of scrolling to the end of the page as you scroll and then navigate to the next page if any , it directly navigates to the next page and then on the last page, it scrolls to the end as you continue scrolling with your mouse.
Is there a way to overcome that problem without handling the ScrollChanged event of the ScrollViewer in the code behind ?
To do this you will need to override the OnMouseWheel method of FlowDocumentPageViewer. Below is the original code:
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
if (e.Delta != 0)
{
if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
{
if (e.Delta > 0)
{
this.IncreaseZoom();
}
else
{
this.DecreaseZoom();
}
}
else if (e.Delta > 0)
{
base.PreviousPage();
}
else
{
base.NextPage();
}
e.Handled = false;
}
if (!e.Handled)
{
base.OnMouseWheel(e);
}
}
In your code you must do as below:
public class MyPageViewer : FlowDocumentPageViewer
{
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
if (scroll_within_page_applicable())
{
scroll_within_page();
}
else
{
base.OnMouseWheel(e);
}
}
}

Resources