I have a Scaffold with a NavHost as its content. NavHost host 2 screens. One screen contains the bottomNavigationBar and another screen doesnot.
How can I display create a snack bar that can be used globally which is displayed at the bottom of the screen if no bottomNavigationView is there but adds a bottom padding of height = bottomNavigationHeight if the screen contains bottomNavigationView?
Below is my main content:
#Composable
fun MainScreen() {
val navController = rememberNavController()
val scaffoldState = rememberScaffoldState()
Scaffold(
scaffoldState = scaffoldState
) {
NavHost(navController = navController, "first") {
composable("first") {
FirstScreen()
}
composable("second") {
SecondScreen()
}
}
}
}
My first screen.
// No bottom navigation
#Composable
fun FirstScreen() {
Text("Hello World")
}
My second screen:
// Contains bottom nav
#Composable
fun SecondScreen() {
Scaffold(bottomBar = { MyBottomBar() }) {
}
}
Now, I can use CompositionLocal to send snackBarHostState from scaffold state to all my screens. But, I want first screen to display the snack bar without bottom padding and second screen to display the snack bar with padding for the bottomNavView.
How can I achieve the dynamic position of snackBar??
P.S. This is a simplified version of my issue. I have about 6-7 screen for my MainContent and many screens for the screen with bottom nav.
Related
So I have been following this tutorial that tells you how to make a datagrid in TornadoFX, and everything works fine. However, I want to add multiple Views to each cell of my datagrid, so I want to replace the stackpane with a borderpane. This breaks it. Cells still show up, but they are blank white squares. None of the Views show up inside.
I'm not really sure why this happens. It seems to me that cellFormat and cellCache act like for-each loops, making a graphic described inside of them for each element in the list of cells that need formatting. I'm not sure, though.
As such, I'm really not sure how to fix this. I really appreciate it if anybody can help.
Code that puts a green circle and a label on each of the white squares:
class DatagridDemo: View("Datagrid Demo") {
val data = listOf("one", "two", "three")
override val root = datagrid(data) {
cellFormat {
graphic = stackpane() {
circle(radius = 50.0) {
fill = Color.ALICEBLUE;
}
label(it);
}
}
}
}
My code:
class DatagridDemo: View("Datagrid Demo") {
val data = listOf("one", "two", "three")
override val root = datagrid(data) {
cellFormat {
graphic = borderpane() {
//The widgets implement View()
top<TopWidget>();
bottom<BottomWidget>()
label(it);
}
}
}
}
This uses two custom Fragments to create objects that are added to the top and the bottom.
class TopWidget(msg : String) : Fragment() {
override val root = label(msg)
}
class BottomWidget(msg : String) : Fragment() {
override val root = label(msg)
}
class DatagridDemo: View("Datagrid Demo") {
val data = listOf("one", "two", "three")
override val root = datagrid(data) {
cellFormat {
graphic = borderpane {
top { add(TopWidget("Top ${it}")) }
center { label(it) }
bottom { add(BottomWidget("Bottom ${it}")) }
}
}
}
}
class DGDemo : App(DatagridDemo::class)
Using Xamarin.Forms, how do I get the same effect as the application pictured below, specifically to show a centred image on the Action Bar / page tool bar (the section in a blue box)?
I would like to have a long width image in that section, and the solution must work for Android, iOS, Windows Phone, and Universal Windows (even if it means writing custom renderers or platform specific xamarin code).
I suggest you create your own Xamarin.Forms view and handle the navigation by yourself something similar to this:
public class CustomBackNavigationBar : StackLayout
{
public Image BackIcon;
public Image Icon;
public Label IconTitle;
public StackLayout IconContainer;
public CustomBackNavigationBar(string title, string icon)
{
Padding = new Thickness(15,5);
HeightRequest = 40;
Orientation = StackOrientation.Horizontal;
VerticalOptions = LayoutOptions.Start;
BackgroundColor = StaticData.BlueColor;
Spacing = 15;
BackIcon = new Image
{
Source = StaticData.BackIcon,
HorizontalOptions = LayoutOptions.Start
};
Label Title = new Label
{
Text = title,
TextColor = Color.White,
FontSize = Device.GetNamedSize(NamedSize.Default, typeof(Label)),
FontAttributes = FontAttributes.Bold,
VerticalTextAlignment = TextAlignment.Center
};
Icon = new Image
{
Source = icon
};
IconTitle = new Label
{
Text = StaticData.CallAgent,
TextColor = Color.White,
FontSize = Device.GetNamedSize(NamedSize.Micro, typeof(Label)),
};
IconContainer = new StackLayout
{
HorizontalOptions = LayoutOptions.EndAndExpand,
Spacing = 2,
Children = { Icon, IconTitle }
};
Children.Add(BackIcon);
Children.Add(Title);
Children.Add(IconContainer);
#region Events
BackIcon.GestureRecognizers.Clear();
BackIcon.GestureRecognizers.Add(new TapGestureRecognizer
{
Command = new Command(PopAsync)
});
#endregion
}
async void PopAsync()
{
await App.AppNavigation.PopAsync();
}
}
I am adding icons to a listwidget. It is working good for say a 200 or 300 icons but i may have to add 1000 or above. So i need to add or load the icons in listwidget only when i scroll down. Now i have used a for loop but i need to avoid this
imagefiles = imagedir.entryList(QStringList() << "*.jpg",QDir::Files);
if(imagefiles.isEmpty())
{
empty->raise();
empty->show();
}
else
{
imagelist->repaint();
for(const QString& f:imagefiles)
{
final_row++;
const QString finalimage=imagepath+QString::fromStdString("/") +f;
QFileInfo fi(finalimage);
imagelist->addItem(new QListWidgetItem(QIcon(fi.absoluteFilePath()),fi.fileName()));
}
}
I am looking to create an editable label at an arbitrary position on the pane on which I am writing. I am under the impression that TextField or TextArea objects are what I could use to implement that capability. There is obviously more to it as I don't know how to position the object when I create it. I have found an example on the "Chaotic Java" website but I need to do a bit more work to understand what's going on there. http://chaoticjava.com/posts/another-javafx-example-the-editable-label/
I am looking for more input from this group.
(There are no errors because I have not written any code.)
I was kind of curious about how to achieve this, so I gave it a try. This is what I came up with.
The approach used is pretty the same as that suggested by James in his comment:
I would start with a Pane, . . ., TextFields to represent text while being edited. Register mouse listeners with the Pane and Text objects, and use the layoutX and layoutY properties to position things . . . just to use text fields, and to use CSS to make them look like labels when not focused and text fields when focused.
The only significantly tricky part was working out how to correctly size the text fields as the Text inside the text field is not exposed via public API to allow you to listen to it's layout bounds. You could perhaps use a css lookup function to get at the enclosed Text, but I chose to use a private sun FontMetrics API (which may be deprecated in the future), to get the size of the text. In the future with Java 9, you should be able to perform the task without using the private API.
The solution doesn't try to do anything tricky like deal with multi-format or multi-line text, it is just for short, single line comments of a few words that can be placed over a scene.
TextCreator.java
// ## CAUTION: beware the com.sun imports...
import com.sun.javafx.tk.FontMetrics;
import com.sun.javafx.tk.Toolkit;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
/**
* Displays a map of the lonely mountain upon which draggable, editable labels can be overlaid.
*/
public class TextCreator extends Application {
private static final String MAP_IMAGE_LOC =
"http://images.wikia.com/lotr/images/archive/f/f6/20130209175313!F27c_thorins_map_from_the_hobbit.jpg";
public static void main(String[] args) throws Exception {
launch(args);
}
#Override
public void start(final Stage stage) throws Exception {
Pane pane = new Pane();
pane.setOnMouseClicked(event -> {
if (event.getTarget() == pane) {
pane.getChildren().add(
new EditableDraggableText(event.getX(), event.getY())
);
}
});
EditableDraggableText cssStyled =
new EditableDraggableText(439, 253, "Style them with CSS");
cssStyled.getStyleClass().add("highlighted");
pane.getChildren().addAll(
new EditableDraggableText(330, 101, "Click to add a label"),
new EditableDraggableText(318, 225, "You can edit your labels"),
cssStyled,
new EditableDraggableText(336, 307, "And drag them"),
new EditableDraggableText(309, 346, "Around The Lonely Mountain")
);
StackPane layout = new StackPane(
new ImageView(
new Image(
MAP_IMAGE_LOC
)
),
pane
);
Scene scene = new Scene(layout);
scene.getStylesheets().add(getClass().getResource(
"editable-text.css"
).toExternalForm());
stage.setScene(scene);
stage.setResizable(false);
stage.show();
}
/**
* A text field which has no special decorations like background, border or focus ring.
* i.e. the EditableText just looks like a vanilla Text node or a Label node.
*/
class EditableText extends TextField {
// The right margin allows a little bit of space
// to the right of the text for the editor caret.
private final double RIGHT_MARGIN = 5;
EditableText(double x, double y) {
relocate(x, y);
getStyleClass().add("editable-text");
//** CAUTION: this uses a non-public API (FontMetrics) to calculate the field size
// the non-public API may be removed in a future JavaFX version.
// see: https://bugs.openjdk.java.net/browse/JDK-8090775
// Need font/text measurement API
FontMetrics metrics = Toolkit.getToolkit().getFontLoader().getFontMetrics(getFont());
setPrefWidth(RIGHT_MARGIN);
textProperty().addListener((observable, oldTextString, newTextString) ->
setPrefWidth(metrics.computeStringWidth(newTextString) + RIGHT_MARGIN)
);
Platform.runLater(this::requestFocus);
}
}
/**
* An EditableText (a text field which looks like a label), which can be dragged around
* the screen to reposition it.
*/
class EditableDraggableText extends StackPane {
private final double PADDING = 5;
private EditableText text = new EditableText(PADDING, PADDING);
EditableDraggableText(double x, double y) {
relocate(x - PADDING, y - PADDING);
getChildren().add(text);
getStyleClass().add("editable-draggable-text");
// if the text is empty when we lose focus,
// the node has no purpose anymore
// just remove it from the scene.
text.focusedProperty().addListener((observable, hadFocus, hasFocus) -> {
if (!hasFocus && getParent() != null && getParent() instanceof Pane &&
(text.getText() == null || text.getText().trim().isEmpty())) {
((Pane) getParent()).getChildren().remove(this);
}
});
enableDrag();
}
public EditableDraggableText(int x, int y, String text) {
this(x, y);
this.text.setText(text);
}
// make a node movable by dragging it around with the mouse.
private void enableDrag() {
final Delta dragDelta = new Delta();
setOnMousePressed(mouseEvent -> {
this.toFront();
// record a delta distance for the drag and drop operation.
dragDelta.x = mouseEvent.getX();
dragDelta.y = mouseEvent.getY();
getScene().setCursor(Cursor.MOVE);
});
setOnMouseReleased(mouseEvent -> getScene().setCursor(Cursor.HAND));
setOnMouseDragged(mouseEvent -> {
double newX = getLayoutX() + mouseEvent.getX() - dragDelta.x;
if (newX > 0 && newX < getScene().getWidth()) {
setLayoutX(newX);
}
double newY = getLayoutY() + mouseEvent.getY() - dragDelta.y;
if (newY > 0 && newY < getScene().getHeight()) {
setLayoutY(newY);
}
});
setOnMouseEntered(mouseEvent -> {
if (!mouseEvent.isPrimaryButtonDown()) {
getScene().setCursor(Cursor.HAND);
}
});
setOnMouseExited(mouseEvent -> {
if (!mouseEvent.isPrimaryButtonDown()) {
getScene().setCursor(Cursor.DEFAULT);
}
});
}
// records relative x and y co-ordinates.
private class Delta {
double x, y;
}
}
}
editable-text.css
.editable-text {
-fx-background-color: transparent;
-fx-background-insets: 0;
-fx-background-radius: 0;
-fx-padding: 0;
}
.editable-draggable-text:hover .editable-text {
-fx-background-color: yellow;
}
.editable-draggable-text {
-fx-padding: 5;
-fx-background-color: rgba(152, 251, 152, 0.2); // translucent palegreen
}
.editable-draggable-text:hover {
-fx-background-color: orange;
}
.highlighted {
-fx-background-color: rgba(255, 182, 93, 0.3); // translucent mistyrose
-fx-border-style: dashed;
-fx-border-color: firebrick;
}
If you have time, you could clean the sample implementation up and donate it to the ControlsFX project.
You can use a function of label: setGraphic().
Here is my code:
public void editableLabelTest(Stage stage){
Scene scene = new Scene(new VBox(new EditableLabel("I am a label"),
new EditableLabel("I am a label too")));
stage.setScene(scene);
stage.show();
}
class EditableLabel extends Label{
TextField tf = new TextField();
/***
* backup is used to cancel when press ESC...
*/
String backup = "";
public EditableLabel(){
this("");
}
public EditableLabel(String str){
super(str);
this.setOnMouseClicked(e -> {
if(e.getClickCount() == 2){
tf.setText(backup = this.getText());
this.setGraphic(tf);
this.setText("");
tf.requestFocus();
}
});
tf.focusedProperty().addListener((prop, o, n) -> {
if(!n){
toLabel();
}
});
tf.setOnKeyReleased(e -> {
if(e.getCode().equals(KeyCode.ENTER)){
toLabel();
}else if(e.getCode().equals(KeyCode.ESCAPE)){
tf.setText(backup);
toLabel();
}
});
}
void toLabel(){
this.setGraphic(null);
this.setText(tf.getText());
}
}
I'm working on a project in Vaadin 7. In that I need to parse over all the components in a Layout and find a component I need.
The above is the pictorial representation of my layout.
I'm dynamically creating the green coloured Vertical layout inside blue coloured Vertical layout. Since I'm creating them dynamically, I can't have any instance for those dynamically created things. But, I have unique ID's for all the components.
Now I need to find a Combobox using the Id. I donno how to parse in to the combobox from the Blue coloured vertical layout.
All I have is an instance of the blue coloured vertical layout and Id's for combobox.
And, I can have ID's for green and red layouts too if needed.
I need something like this, But stuck..
Iterator<Component> iterate = blueMainLayout.iterator();
Combobox cb;
while (iterate.hasNext()) {
Component c = (Component) iterate.next();
cb = (Combobox) blueMainLayout.....;
if (cb.getId().equals(something.getId())) {
// do my job
}
}
You have to check component recursively.
class FindComponent {
public Component findById(HasComponents root, String id) {
System.out.println("findById called on " + root);
Iterator<Component> iterate = root.iterator();
while (iterate.hasNext()) {
Component c = iterate.next();
if (id.equals(c.getId())) {
return c;
}
if (c instanceof HasComponents) {
Component cc = findById((HasComponents) c, id);
if (cc != null)
return cc;
}
}
return null;
}
}
FindComponent fc = new FindComponent();
Component myComponent = fc.findById(blueMainLayout, "azerty");
Hope it helps
Though using HasComponents.iterator() is still possible com.vaadin.ui.AbstractComponentContainer implements java.lang.Iterable<Component>, which makes the iteration a bit more comfortable:
...
for ( Component c : layout ) {
if ( id.equals( c.getId() ) ) {
return c;
}
}
...