I have the following code that works:
Button b = (Button) findViewById(R.id.my_button);
if(b != null) {
Rect bounds = new Rect();
parentLayout.getHitRect(bounds);
if(b.getLocalVisibleRect(bounds)) {
//it is visible, do code
}
}
Question: How can I change the code so that the I do what I am currently doing inside if(b.getLocalVisibleRect(bounds)) but when the middle of or the complete button has appeared?
With my code now, I can detect when the upper edge of the button has appeared. But it would be best if I was able to detect when almost all of the button has appeared.
Related
So I am facing a weird bug I cannot explain - I cannot even reproduce it sometimes.
Basic context:
I have an application, which lists objects. Every object has a name and a point value. For every object, the addCustomSpinner function creates a "ticket" (a custom view, kind-of-spinner) and shows them in a scrollview so the user can select the one needed. There are four different 'containers' for four different kind of objects - so the layout can be populated with four kind of "ticket" package.
The data for the objects are collected from a database. The addCustomSpinner is called with a for cycle for every object in the database, and - Important - before the for method, the Layout it populates with the tickets is cleared (removeAllViews).
Inside addCustomSpinner, everything is created as "new" - like the button in question.
addCustomSpinner creates this button and adds a new onClickListener. Inside onClickListener, a new boolean is created - this is used to show a different animation when the button is clicked again. On first click (boolean = true), the arrow turns 180 degrees and faces upwards, on second click (boolean = false) the arrow turns 180 degrees and faces downwards. Works like a charm, until...
The bug I am facing:
Sometimes - as I already mentioned, not every time - if I click the button for one "ticket", then leave it 'opened' and click on an another one, and leave it 'opened' also, THEN I choose to populate the layout with a different kind of "ticket" package - The arrow faces upwards by default on every ticket in every package! Sometimes - again, just sometimes - with the same pattern I can turn it back, but it happens just "by accident".
I don't understand how the animation and state of the buttons can be connected, if every created ticket is new, every button is new, every onClickListener is new, and every boolean inside onClickListener is new. And if these are connected somehow, then why can that be that every behavior is "unique" for the buttons, nothing else shows any connection - even this is just a "sometimes" bug, a pretty rare one.
Can anybody help me why this happens?
What I tried:
Well, tried to trace the issue - but since it happens just by accident, I have no clue, I just searched if I can do anything else than the boolean to add different animation for the clicks. Sadly using ObjectAnimator is not a good solution for me - not the same result at least, since my animated arrow not only rotates, but it also changes its color. Shapeshifter seemed like a good idea to create animations easily, but now as I see it, maybe a simple rotation will be my ultimate solution.
Here's the code for the button:
customButton.setOnClickListener(new View.OnClickListener() {
boolean isCustomButtonClicked = true;
#Override
public void onClick(View v) {
if (isCustomButtonClicked) {
customButton.setImageResource(R.drawable.avd_anim_arrow_blue_back);
Drawable d = customButton.getDrawable();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (d instanceof AnimatedVectorDrawable) {
animArrowAnim = (AnimatedVectorDrawable) d;
animArrowAnim.start();
}
}
routeWhoClimbed.setVisibility(View.VISIBLE);
isCustomButtonClicked = false;
} else if (!isCustomButtonClicked) {
customButton.setImageResource(R.drawable.avd_anim_arrow_blue);
Drawable d = customButton.getDrawable();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (d instanceof AnimatedVectorDrawable) {
animArrowAnim = (AnimatedVectorDrawable) d;
animArrowAnim.start();
}
}
routeWhoClimbed.setVisibility(GONE);
isCustomButtonClicked = true;
}
}
});
EDIT:
The full addCustomSpinner():
private void addCustomSpinner(Routes mRouteItemToAdd, String placeName) {
//creating a new View for my custom layout created in xml
View customRoutesView = new View(this);
LinearLayout.LayoutParams customViewParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
customRoutesView.setLayoutParams(customViewParams);
customRoutesView = LayoutInflater.from(this).inflate(
R.layout.custom_view_layout, routeLayout, false
);
//Setting up the views inside the custom view
ImageView imageViewDiffImage = customRoutesView.findViewById(R.id.routeDiffImageView);
TextView textViewRouteName = customRoutesView.findViewById(R.id.routeNameTextView);
TextView textViewRouteDiff = customRoutesView.findViewById(R.id.routeDiffTextView);
ImageButton customButton = customRoutesView.findViewById(R.id.customButton);
RadioButton climberNameOne = customRoutesView.findViewById(R.id.climberNameOne);
RadioButton climberNameTwo = customRoutesView.findViewById(R.id.climberNameTwo);
Button climbedItButton = customRoutesView.findViewById(R.id.climbed_it_button);
RadioGroup climberNameRadioGroup = customRoutesView.findViewById(R.id.climberNameRadioGroup);
RadioGroup climbingStyleRadioGroup = customRoutesView.findViewById(R.id.styleNameRadioGroup);
RelativeLayout routeWhoClimbed = customRoutesView.findViewById(R.id.routeWhoClimbedRelativeLayout);
imageViewDiffImage.setImageResource(R.mipmap.muscle);
textViewRouteName.setText(mRouteItemToAdd.name);
textViewRouteDiff.setText("Difficulty: " + (int) mRouteItemToAdd.difficulty);
climberNameOne.setText(climberName1);
climberNameTwo.setText(climberName2);
routeWhoClimbed.setVisibility(GONE);
//Here comes the button with the animated image
customButton.setOnClickListener(new View.OnClickListener() {
boolean isCustomButtonClicked = true;
#Override
public void onClick(View v) {
if (isCustomButtonClicked) {
customButton.setImageResource(R.drawable.avd_anim_arrow_blue_back);
Drawable d = customButton.getDrawable();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (d instanceof AnimatedVectorDrawable) {
animArrowAnim = (AnimatedVectorDrawable) d;
animArrowAnim.start();
}
}
routeWhoClimbed.setVisibility(View.VISIBLE);
isCustomButtonClicked = false;
} else if (!isCustomButtonClicked) {
customButton.setImageResource(R.drawable.avd_anim_arrow_blue);
Drawable d = customButton.getDrawable();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (d instanceof AnimatedVectorDrawable) {
animArrowAnim = (AnimatedVectorDrawable) d;
animArrowAnim.start();
}
}
routeWhoClimbed.setVisibility(GONE);
isCustomButtonClicked = true;
}
}
});
//Button, works like an 'OK' or something, and I have no
//problem with this
climbedItButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int checkedNameButton = climberNameRadioGroup.getCheckedRadioButtonId();
int checkedStyleButton = climbingStyleRadioGroup.getCheckedRadioButtonId();
RadioButton checkedNameRadioButton = (RadioButton) findViewById(checkedNameButton);
RadioButton checkedStyleRadioButton = (RadioButton) findViewById(checkedStyleButton);
String checkedName = (String) checkedNameRadioButton.getText();
String checkedStyle = (String) checkedStyleRadioButton.getText();
addClimbToDatabase(user.getUid(), checkedName, mRouteItemToAdd, placeName, checkedStyle);
}
});
//And finally, I add this new "ticket" with the custom view to the layout i want to show it. Again, this also works like a charm, no problem here.
routeLayout.addView(customRoutesView);
}
Ultimately, I did not manage to understand the problem throughly, but I was able to eliminate it.
So during my fixing tries I narrowed down the problem to the animated drawable state - credit to #avalerio for his pro tip, but the answer wasn't addig an id to the button. I think somehow and sometime, the state of the first animation (turning the arrow 180 degrees) stuck in the end position - causing the other views using this animatedDrawable showing it in end position on start.
.reset() did not help, since it resets the animatedVectorDrawable object, not the animation xml drawable state. My solution is a kind of workaround, but it is working: when the custom-view 'ticket' is created with the animated-drawable-imagebutton, I set the imageResource of the button to a not-animated xml drawable - this drawable is basically the start position of my animated-drawable. This way, when the 'tickets' are generated, the imagebutton is 'hardcoded' in the start position.
Not elegant, but works. BUT(!) I would really appreciate if someone could explain to me how this weird behavior is possible - just sometimes, randomly, with no pattern I can reproduce intentionally.
I am developing a drawing application where the user can also insert a text sticker with the text they want. For this, when the user selects the text sticker, an AlertDialog appears, where he types the text. When inserting the first text there are no problems. The problem arises when the user already has a sticker and is going to add a new one. When the sticker is added to the canvas, all other stickers disappear, leaving only the new one. However, if the user double-clicks on the new sticker, or once outside the new sticker and clicks inside, the stickers reappear in their proper locations.
I already did a test, where I generate sticker defaults with the same name outside the alertDialog, with just a press of any button, and the stickers are added correctly without the others disappearing. In other words, my stickers just don't work when I use alertDialog. I've already run and I can't find the error. Can someone help me?
MainActivity:
text.setOnClickListener {
showAlertDialogSticker()
}
//Change text color dialog box
private fun showAlertDialogSticker() {
val dialogBuilder = AlertDialog.Builder(this#MainActivity)
val layoutView = layoutInflater.inflate(R.layout.dialog_sticker, null)
checkBold = layoutView.findViewById(R.id.radio_bold)
checkItalic = layoutView.findViewById(R.id.radio_italic)
checkSublime = layoutView.findViewById(R.id.radio_sublime)
pickedColorSticker = layoutView.findViewById(R.id.pickedColorSticker)
txtSticker = layoutView.findViewById(R.id.txt_sticker)
sticker = layoutView.findViewById(R.id.sticker)
multiColorPickerSticker = layoutView.findViewById(R.id.multiColorPickerSticker)
multiColorPickerSticker.setInitialColor(0x7F313C93)
multiColorPickerSticker.subscribe { color: Int, _: Boolean, _: Boolean ->
pickedColorSticker.setBackgroundColor(color)
sticker.setTextColor(color)
textColor = color
}
dialogButtonCancel = layoutView.findViewById(R.id.btnCancel)
dialogButtonAdd = layoutView.findViewById(R.id.btnSave)
dialogBuilder.setView(layoutView)
dialogAdd = dialogBuilder.create()
dialogAdd.window?.attributes?.windowAnimations ?: R.style.DialogAnimation
dialogAdd.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
dialogAdd.show()
dialogButtonCancel.setOnClickListener {
dialogAdd.cancel()
}
dialogButtonAdd.setOnClickListener {
//Add text sticker
validFiel()
if (isValid) {
my_canvas.addTextSticker(textStick, textColor, null)
dialogAdd.dismiss()
}
}
}
Using the code above I have the problem reported. Calling the method as below, it was possible to add several stickers without problems.
text.setOnClickListener {
my_canvas.addTextSticker(textStick, textColor, null)
}
I'm doing a little connect4 game and I've started on the GUI. I made the piece class which creates the button for the piece and sets its color. But when I test it out in the GUI, the only thing that appears is the text, if there was no text(which was only used to check) the button is invisible
code for creating button
piece = new Button("testing");
piece.setShape(new Circle());
if (colour == 1) {
piece.setStyle("fx-background-color: #DC143C");
} else {
piece.setStyle("fx-background-color: #0000FF");
}
code for adding button
int col = piece.getCol();
Button button = piece.getPiece();
root.addColumn(col, button);
I have no skill at all with CSS and very little in JavaFX so I don't understand why it's not working
So, I dont know if I am missing something but any way I work it or look into it I am unable to click on any buttons on the screens.
I made a dialog box with a button essentially as shown in the sample projects but when ever I try to click the button nothing happens at all.
I tried firing the onClick programmatically and it works fine, I also tested that the mouse inputs were being registered okay and they were.
I am at a total loss for any reason why this wouldnt work.
My class code is below:
public class Interactable : UICanvas
{
public void interact()
{
var skin = Skin.createDefaultSkin();
var table = stage.addElement(new Table());
table.center();
table.setFillParent(true);
table.add(talk(this.entity.name, "Stay a while and glisten", "Bye!"));
}
public Dialog talk(string title, string messageText, string closeButtonText)
{
var skin = Skin.createDefaultSkin();
var style = new WindowStyle
{
background = new PrimitiveDrawable(new Color(50, 50, 50)),
//Dims the background
stageBackground = new PrimitiveDrawable(new Color(0, 0, 0, 150))
};
var dialog = new Dialog(title, style);
dialog.getTitleLabel().getStyle().background = new PrimitiveDrawable(new Color(55, 100, 100));
dialog.pad(20, 5, 5, 5);
dialog.addText(messageText);
var exitButton = new TextButton(closeButtonText, skin);
exitButton.onClicked += butt => dialog.hide();
dialog.add(exitButton);
return dialog;
}
}
}
The interact() is called when running up to another entity and pressing "E".
Which causes everything to render properly but I can't click on the button.
Additionally:
When i try to view exitButton co-ordinates theyre always 0 no matter what although the dialog appears in the middle of the window
Monogame version: 3.7
Nez version: 0.9.2
UPDATE:
So it seems like buttons are clickable but their click box is not even nearly aligning with where the buttons are truely rendered.
UPDATE2:
It seems that the issue is that where the button is being rendered and where the actual click box is are not the same.
I have Zoomed in the camera by 2 and the camera also follows my little character around. The dialog will then appear at the X,Y in relation to the current camera view but the actual click box appears at the X,Y in terms of the TiledMap (which is not always on screen).
Not too sure how to work around this.
So! The issue I was having was I was using one renderer for the entire this (The RenderLayerRenderer.) What I have done to fix this is start another renderer (A ScreenSpaceRenderer). This allows me to use it to render UI and its XY variables do not change but are just static to the visual area.
So i ended up with two renders like so:
addRenderer(new RenderLayerRenderer(0,new int[] { (int)RenderLayerIds.First, (int)RenderLayerIds.Second, (int)RenderLayerIds.Third}));
addRenderer(new ScreenSpaceRenderer(1, new int[] { (int)RenderLayerIds.UILayer }));
Using the first for my game rendering and the bottom on just for HUD things!
I am struggling with intersections i need to .getShape() on a button.
But as the API states
When null, the Region is rendered as a rounded rectangle.
that means that by default button dont have shape set.
I don't want to .setShape() on the button but to check my intersections i need to .getShape() of the button which comes back null.
Is there a way to get the default shape of the button node while .getShape() returns null ?
I have 2 .observableArrayList() buttons and circles (kind of bubbles)
private final ObservableList<Circle> circles = FXCollections.observableArrayList();
private final ObservableList<Button> buttonsList = FXCollections.observableArrayList();
private final ObjectProperty<BoundsType> selectedBoundsType = new SimpleObjectProperty<>(BoundsType.BOUNDS_IN_PARENT);
Then I add all of my buttons and circles to obs lists:
buttonsList.addAll(rootPane.getChildrenUnmodifiable()
.stream()
.filter(node -> node instanceof Button)
.map(node -> (Button) node)
.collect(Collectors.toList()));
Circles are a bit different I add them separately with a mouse click.
and then check the intersections between circles and buttons.
for (Button btn : buttonsList) {
for (Circle c : circles) {
ShapePair pair = new ShapePair(c.getShape(), btn.getShape());
if (pair.intersects(selectedBoundsType.get())) {
System.out.println("Colision");
//logic
}
}
}
but like i said the btn.getShape() gets me null ;(
Right i think it just easier to do
for (Button btn : buttonsList) {
for (Circle c : circles) {
if (btn.getBoundsInParent().intersects(b.getBoundsInParent())) {
System.out.println("Colision");
}
}
}