Suppose I have a StateListDrawable. I want to add 2 drawables inside it: the first if it is clicked, second for any other state.
I tried it as following (pseudo-code):
Drawable clickdDrawable = getResourses.getDrawable(R.drawable.presseddrawable);
clickDrawable.setBounds(-100, -100, 100, 100);
Drawable otherStateDrawable = getResources().getDrawable(R.drawable.somedrawable);
otherStateDrawable.setBounds(-50,-50, 50, 50);
StateListDrawable sld = new StateListDrawable();
sld.addState(new int[]{andriod.R.attr.state_pressed, android.R.attr.state_focussed}, clickDrawable);
sld.addState(StateSet.WILDCARD, otherStateDrawable);
sld.setBounds(-50, -50, 50, 50);
now if I'm in state pressed I will get the presseddrawable, but it sticks to the bounds of StateListDrawable. So my question is: How to store Drawables with different bounds inside a StateListDrawable? Is this possible?
You will have to create "custom" Drawables, but before you go that way, let me invite you (and whoever is involved, often a designer) to re-think a bit what you are doing, some years ago I did a heavy work on programmatically drawn extends Drawables (yet it was awesome) just to trash it few months later in favor of simplicity and practicality, I don't see why you can't achieve something like this with a well made 9-patch (a.k.a. n-patch) rather than hardcode dimensions, anyways before you call me grandpa here is a quick answer that could work for ya:
In example say you are using color drawables:
public class FixedBoundsColorDrawable extends ColorDrawable {
private boolean mFixedBoundsSet = false; // default
public FixedBoundsColorDrawable(int color) {
super(color);
}
#Override
public void setBounds(int left, int top, int right, int bottom) {
if (!mFixedBoundsSet) {
mFixedBoundsSet = true;
super.setBounds(left, top, right, bottom);
}
}
}
With red as pressed and blue as wildcard and your values you get on a Nexus 4:
You could also create a wrapper to wrap any drawable and call its methods but I would go that way as there are some final methods that you certainly will need.
Related
I have an ImageButton. The texture for it is basically a white square, with black text in the center. I want to be able to dynamically change the color of this button. The problem is that ImageButton.setColor does not do anything. I can call tint on the ImageButtonStyle which does work, but I want to be able to change the color later down the road if for instance the player clicks on the button. Thanks! Here is some code :
ImageButton.ImageButtonStyle style_button_music = new ImageButton.ImageButtonStyle();
style_button_music.imageChecked = new SpriteDrawable(new Sprite((Texture) Game.assetManager.get("button_music.png")));
style_button_music.imageUp = new SpriteDrawable(new Sprite((Texture) Game.assetManager.get("button_music.png")));
style_button_music.imageDisabled = new SpriteDrawable(new Sprite((Texture) Game.assetManager.get("button_music.png")));
button_music = new ImageButton(style_button_music);
button_music.setColor(new Color(22f/255f, 100f/255f, 255f/255f, 1f));
table.setFillParent(true);
table.setDebug(true);
table.top();
table.pad(100);
table.add(button_music).width(200).height(200);
stage.addActor(table);
Use
button_music.getImage().setColor(Color color)
The setColor() on ImageButton is just inherited method from Actor but it doesn't do anything.
Actor color doesn't cascade down to children (except for the alpha component). Since the Image of an ImageButton is a child of the Button, the Image does not inherit the color of the Button.
However, the way in which you're currently using it, I think you could use a plain Button, and set the background image instead. That does get tinted.
style_button_music.checked = new TextureRegionDrawable(new TextureRegion(Game.assetManager.get("button_music.png")));
style_button_music.up = style_button_music.checked;
style_button_music.disabled = style_button_music.checked;
You should probably be using TextureRegionDrawable instead of SpriteDrawable. It's a much lighter-weight object, and it's rare to need the extra overhead of Sprites for buttons.
If you do need to use an actual ImageButton, and you're recoloring it dynamically, you could subclass ImageButton and use it's act method to transfer it's color to its child. That way you can use ColorActions with it.
#Override
public void act (float delta) {
super.act(delta);
Color color = getColor();
getImage().setColor(color.r, color.g, color.b, 1f); //leave opaque, alpha transferred in draw()
}
I followed every instruction I could find, tried various ways to implement this, always with the same symptom: Nothing happens...
Expectation:
Have an image that is fading from 100% transparent to 0% transparent.
I have this FadingImage class:
public class FadingImage{
private FadeTransition ft;
public FadingImage(String imgName,int posX, int posY, double from, double to, Group root) {
ImageView img = new ImageView(imgName);
ft = new FadeTransition(Duration.millis(1000));
ft.setNode(img);
ft.setFromValue(from); //sets the start opacity value
ft.setToValue(to); //sets the target opacity value
ft.setCycleCount(1);
ft.setAutoReverse(false);
img.setTranslateX(posX);
img.setTranslateY(posY);
root.getChildren().add(img);
}
public void play(){
ft.playFromStart();
}
}
And I call it like this:
FadingImage fi = new FadingImage("images/dock1.png",500, 500, 0.0, 1.0, root);
fi.play();
I am getting no exceptions whatsoever.
If I add a System out in the play method, it shows it.
I feel like I am missing something basic here, I just don't find it...
The code is correct. The parameters used were incorrect, as the image was displayed outside the screen.
I am interested in simple game programming with AndEngine. And I would like to do some basic round based strategy stuff. So I would like to have a top down view to some grid. Every square in this chess like grid should be clickable (touchable on android of course). But I can´t imagine drawing lines and squares is the best solution to do so. I would like to have some kind of abstract object list, which I can extend to different behaviours (one click triggers menu to open, on other field a click triggers an explosion, whatever...).
I have been searching for this in several engines over the years now. It is a hobby, but I would like to find a solution for it. Can anyone give me a hint about how this could be done in an elegant way? Double buffering, rendering and stuff isn´t that important. The important thing is, every square should be an object that gets painted.
Anyone? ;)
Regards.
Simplet solution would be something like that (lets say that your screen is 800x480 in portrait mode, and I assume that you have GLES2-AC andEngine branch).
in your onCreateScene() method:
Rectangle rect1 = new Rectangle(80, 133, 160, 266, engine.getVertexBufferObjectManager()){
#Override
public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY){
if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN){
//here put what you want to be done after your button was pressed
}
}
Rectangle rect2 = new Rectangle(240, 133, 160, 266, engine.getVertexBufferObjectManager()){
#Override
public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY){
if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN){
//here put what you want to be done after your button was pressed
}
}
and you continue 7 more times with changing first two numbers in new Rectangle(x, y....) which are coordinates of the center of rectangle(second pair of numbers is the height and wisth of the rectangle). (so bottomrow has coordinates: (80, 133), (240, 133) and (400, 133). Middle row: (80, 399), (240, 399) and (400, 399). Third row you can figure out. Of course it does not give you completely covered screen. This you can achieve by dividing your WIDTH and HEIGHT of the screen by certain numers und use it as a coordinates for rectangles. remember to attach all rectangles to your scene and add
this.setOnSceneTouchListener(getOnSceneTouchListener());
this.setOnSceneTouchListenerBindingOnActionDownEnabled(true);
and register touch area for all rectangles.
More difficult way would be to create class for example MyButton.class that extends rectangle or sprite class that has a methods that will be used when "button" is pressed. It depends on what you really need.
My little project involves a diagram editing tool, in which different sized boxes can be linked together. The drawing requirement for this is complex to say the least. You see the idea is that one can zoom in/out as far as they like and create ever smaller/larger boxes. This is sort of like a Mandelbrot, but as a diagram tool. This is shown in the image below.
These boxes have text in them and my overall aim was for this text to be centered in the absolute center of the box. The only simple way I know for text to both center and wrap is by using JLabels. But when I tried this I came across a strange bug. The labels with multiple lines were prone to "disalign" vertically every other time they were repainted. (Sometimes this happened, other times it didn't. It has some consistency in that it keeps its behaviour when I replicate the same movement and positioning). This bug is shown in the image below.
Depending on the position, it would effectively alternate between the two images above. I have isolated the drawing of each box and ensured there was no escaping graphics transformations, and it seems this problem is down to the label painting.
I am aware that the practices I've used may not be preferable (e.g. painting JLabel directly), however I struggle to find any decent alternatives. If you guys can come up with a good alternative to using JLabels for centering and word wrap I'm happy to try it. Any ideas are welcome really.
Below is the drawing code for a Box. The colors are temporary.
public void draw(Graphics2D g, Map map, int fillAlpha, int lineAlpha, double zoom)
{
if(this == map.selectedBox)
{
if(this == map.highlightedBox)
g.setColor(new Color(200,235,235,fillAlpha));
else
g.setColor(new Color(200,225,225,fillAlpha));
}
else
{
if(this == map.highlightedBox)
g.setColor(new Color(235,235,200,fillAlpha));
else
g.setColor(new Color(225,225,200,fillAlpha));
}
g.fill(rect);
if(this == map.selectedBox)
g.setColor(new Color(0,0,255,lineAlpha));
else
g.setColor(new Color(0,0,0,lineAlpha));
g.draw(rect);
g.translate(rect.x, rect.y);
label.setForeground(g.getColor());
label.paint(g);
g.translate(-rect.x, -rect.y);
}
Below is the drawing code for the whole diagram.
public void draw(Graphics2D g, int layer, Color aboveColor)
{
for(Link link : linksObj(layer))
{
g.setColor(Color.black);
link.draw(g, this, aboveColor);
}
AffineTransform at = g.getTransform();
g.scale(getZoom(layer), getZoom(layer));
double ratio = getRatio(layer);
int fill = getAnimAlpha(255, 0, ratio);
int line = getAnimAlpha(255, 32, ratio);
for(Box box : boxesObj(layer))
box.draw(g, this, fill, line, getZoom(layer));
g.setTransform(at);
}
The label uses the following to center the text.
public String convertForLabel(String in)
{
return "<html><div style=\"text-align: center;\">"+in.replaceAll("\n", "<br>")+"</html>";
}
Edit: I have created a test project for you to see the problem yourself. It is only one class so I just uploaded that. You can find it here: JLabel Bug Class
Please bear with me if this isn't clear, this is my first posting here.
I'm drawing a couple of lines on a canvas and trying to translate the canvas to centre the lines on the screen. The trouble is, I have an actionbar (using actionbarsherlock) which I want to exclude from the translation i.e. I want the top of the view to be under the action bar.
As it is, the data is centred vertically on the whole screen height, but I want it to be centred vertically only on the visible part of the canvas under the action bar.
Any ideas of the best way to achieve this?
#Override
protected void onDraw(Canvas canvas) {
Paint paint = mPaint;
paint.setAntiAlias(true);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
int centrew = canvas.getWidth()/2;
int centreh = canvas.getHeight()/2;
canvas.translate(centrew, centreh);
canvas.drawLine(0, -5, 0, 5, mPaint);
canvas.drawLine(5, 0, -5, 0, mPaint);
}
if you know the exact size of the bar, you could apply it it to the overall canvas height to increase the shift:
int maxV = canvas.getHeight() + barHeight;
int centreh = maxV/2;
I am assuming, the bar is on top, covering apart of the canvas, so the shift (from the top left corner) has to be greater. If the bar is on the bottom, the shift should be reduced:
int maxV = canvas.getHeight() - barHeight;
int centreh = maxV/2;
EDIT: If the bar has a different size in pixels on different devices, you have to hack a bit to make it work. You can safely make assuptions about the bar and revise them in case they don't hold. You could assume a certain ratio reserved for the bar and adapt the absolute pixel count accordingly (the oneliner is rather for illustration):
int maxV = Math.round(canvas.getHeight()*(1f + barRatio));
You can further adapt the ratio depending on the aspect ratio of the screen to make it work even better.
Unfortunately there is no really clean solution as you cannot read the current layout and extract sizes.
The solution I used was as described here :
http://developer.android.com/resources/samples/HoneycombGallery/src/com/example/android/hcgallery/TitlesFragment.html
Basically my activity has the following layout listener defined:
ViewTreeObserver.OnGlobalLayoutListener layoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
mmv.setAbShift(MunroBag.this.actionBar.getHeight());
}
};
Then the view class has the following method defined:
public void setAbShift(int shift)
{
abShift = shift;
this.invalidate();
}
So onDraw gets called and the shift is applied to the view depending on the actionBar height.