I have a custom View that will manage hundreds of discrete user-defined sequential drawing events. Rather than maintaining a collection of all of the individual text, line, shape updates and then redrawing them all during each onDraw, I grab a Bitmap of the canvas at the end of each onDraw and then start the next onDraw with that Bitmap. A description of my problem follows this snippet:
public class TestView extends View implements OnTouchListener {
private Paint mPaint;
private Bitmap mPrevCanvas;
private int mTouchCount = 0;
float mX = 50f;
float mY = 50f;
public TestView(Context context) {
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
this.setDrawingCacheEnabled(true);
mPaint = new Paint();
mPaint.setTextSize(30f);
}
#Override
protected void onDraw(Canvas canvas) {
if (mTouchCount == 0) {
canvas.drawText("Touch screen to begin", 50f, 100f, mPaint);
} else {
if (mPrevCanvas != null) {
canvas.drawBitmap(mPrevCanvas, 0, 0, mPaint);
}
canvas.drawText(Integer.toString(mTouchCount), mX, mY, mPaint);
mPrevCanvas = getDrawingCache().copy(Bitmap.Config.ARGB_8888, false);
}
}
public boolean onTouch(View arg0, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
mX = event.getX();
mY = event.getY();
mTouchCount += 1;
invalidate();
}
return true;
}
}
It seems to be working okay for the first touch event, but then mPrevCanvas never gets updated again. In reviewing the previous questions related to getDrawingCache(), only getDrawingCache is not updated seemed relevant, but based on that user's self-discovered answer, that apparently wasn't the same problem.
When running this custom view, touching the screen displays a "1" at the position you touch. It then captures a Bitmap of the canvas with that "1" in it. Subsequent touches redisplay that Bitmap stored in mPrevCanvas (showing the "1" again at the same position), and then the new number representing the current touch event (e.g., "2", "3", etc.) Since I'm refreshing mPrevCanvas at the end of each onDraw, I expect each onDraw to begin by displaying a Bitmap containing the results of all of the previous touch events... but for some reason the mPrevCanvas Bitmap is never updated to include that anything except that initial event ("1").
I've (a) verified that isDrawingCacheEnabled() is still true during each pass through onDraw; (b) tried throwing in destroyDrawingCache() and buildDrawingCache() to no avail; (c) forced mPrevCanvas to null before the call to getDrawingCache() to make sure it's really getting updated; and (d) searched through my copy of O'Reilly's Java in a Nutshell on the hunch that maybe I have a java headspace problem rather than an Android API problem.
Q1: Why will getDrawingCache() only return a Bitmap containing that first call to canvas.drawText, but never with the results of any of the subsequent drawText calls?
Q2: Given that I'm doing it this way for resource efficiency, should I be using some other design pattern anyway?
Even its too late to reply for this, I thought it could help somebody searching for this to correct answer.
same question here (with reply)
Related
I am trying to simulate tap and joystick movement on screen using AccessibilityService.
In addition i'm getting my input from gamepad controller device. doing tap is ok and done. my problem is simulating joystick movement on screen.
I don't know how can i do continuous touch with GestureDescription, because of time duration that this function requires.
i have used this code for tap:
public void virtual_touch(int posX, int posY)
{
Path path = new Path();
path.moveTo(posX, posY);
GestureDescription.Builder gestureBuilder = new GestureDescription.Builder();
gestureBuilder.addStroke(new GestureDescription.StrokeDescription(path, 10, 10));
//gestureBuilder.build();
boolean isDispatched = dispatchGesture(gestureBuilder.build(), new AccessibilityService.GestureResultCallback()
{
#Override
public void onCompleted(GestureDescription gestureDescription)
{
super.onCompleted(gestureDescription);
MyUtils.Log("onCompleted");
}
#Override
public void onCancelled(GestureDescription gestureDescription)
{
super.onCancelled(gestureDescription);
MyUtils.Log("onCancelled");
}
}, null);
MyUtils.Log("virtual_touch isDispatched : " + isDispatched);
}
For Continue Stroke Use this method may be this will help to you.
willContinue --
continueStroke
public GestureDescription.StrokeDescription continueStroke (Path path,
long startTime,
long duration,
boolean willContinue)
boolean: true if this stroke will be continued by one in the next gesture false otherwise. Continued strokes keep their pointers down when the gesture completes.
I want to make a button that directly extends Actor. The reason I want to do this is because I don't want to go through the trouble of making a text button that has skins and such. I just want to be able to load my png file on the screen and make it clickable. Anyone have ideas or should I just stick to the Textbutton?
How about an ImageTextButton?
Or you use a Button, and add a Stack (which holds multiple items, that you can place on them self)
I don't recommend you, to do your own button. You'll reinvent the wheel.
I suggest: try ImageTextButton.
If that does not help --> Button + Stack
public class TextureActor extends Actor {
private Texture texture;
public TextureActor(Texture texture) {
this.texture = texture;
}
#Override
public void draw(Batch batch, float parentAlpha) {
batch.draw(texture, getX(), getY(), getWidth(), getHeight());
}
}
You can certainly replace Texture with anything else which can be drawn by the batch. Or use another draw method with more detailed parameters.
Buttons don't actually need a skin, so it would be far easier to just make a factory method to simplify it, rather than code all the logic of a proper button:
public static Button makeButton (TextureRegion upImage, TextureRegion downImage, Actor contentActor) {
Button.ButtonStyle style = new Button.ButtonStyle();
style.up = new TextureRegionDrawable(upImage);
style.down = new TextureRegionDrawable(downImage);
return contentActor == null ? new Button(style) : new Button(contentActor, style);
}
I want to achieve something similar to the following image:
Problem: how can we achieve red coloured, unread counter? am I going to design some psd and then reuse it in the app? but then I have to duplicate alot of .png's for each number (let's say my limit is 99 for that). but that would be redundancy.
What is the best practice to achieve this effect ?
You could create a custom View and override the onDraw() method to draw the numbers. What you would probably want to do is to have an icon fully prepared like above except for the number missing in the red circle. Then, in the custom View, you first draw that icon and then you draw the number (you will have to work a little to figure our the precise position in pixels where to draw it, and how to draw it, i.e. text-size, font, color).
Modulo a method getSomeBitmapFromResources() that imports a bitmap from resources (see e.g. here), your custom View could look something like this:
public class MyView extends View {
//Fields:
private Paint paint; //Need a Paint object for colors, fonts, etc.
private RectF rect;
private int numberToPaint;
//Constructors:
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
//Choose the text properties that work for you here:
paint.setColor(Color.WHITE);
paint.setTypeface(Typeface.create("sans-serif", Typeface.BOLD));
paint.setTextSize(12);
}
public MyView(Context context) {
this(context, null);
}
//Most importantly: override onDraw for rendering of the view:
#Override
protected void onDraw(Canvas canvas) {
rect.set(0, 0, getWidth(), getHeight()); //But: make sure your View
//will have the same size of the Bitmap you use! Set the size in XML!
canvas.drawBitmap(getSomeBitmapFromResources(), null, rect, paint);
//Here you will have to carefully choose the position of the text.
//Also consider that depending on numberToPaint the x-coordinate may have to
//be modified. Likely you want to use the Paint.getTextBounds method determine the size.
canvas.drawText("" + numberToPaint, 60, 30, paint);
}
public void chooseNumberAndDraw(int n) {
numberToPaint = n;
postInvalidate(); //Force redraw
}
}
In XML, you want to add your custom View using a tag like
<com.mysite.myproject.MyView
android:layout_width="64dp"
android:layout_height="64dp"
/>
of course replacing width and height by the actual bitmap dimensions.
Use public TabLayout.Tab setCustomView (int layoutResId)
Create a Layout with TextView and Button use this in Custom view. you may use textView for showing counter.
For reference
setCustomView
Following is the complete Example:
Example
You can also use this library.
So i have an actor which is a sprite, set on a screenviewport stage. What i want to do is be able to touch the actor, then touch a spot on the screen it will move that fluently. Currently when i touch the actor it just jumps seemingly to random spots. Here is some of the code in my actor class,
public MyActor(){
setBounds(sprite.getX(),sprite.getY(),
sprite.getWidth(),sprite.getHeight());
setTouchable(Touchable.enabled);
addListener(new InputListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y,
int pointer, int button) {
MoveByAction mba = new MoveByAction();
mba.setAmount(x,y);
MyActor.this.addAction(mba);
return true;
}
});
}
#Override
protected void positionChanged() {
sprite.setPosition(getX(),getY());
super.positionChanged();
}
#Override
public void draw(Batch batch, float parentAlpha) {
sprite.draw(batch);
}
#Override
public void act(float delta){
super.act(delta);
}
Few things to ask here. First of all, your touch is only on touching your Actor. That's going to be exactly where the actor is. You need to implement at your Scene level some basic state machine to know "on first tap, this actor is selected", then it has to be in a "select where this actor goes" state, and finally when you select a position it has to send that XY to the selected actor to do the move.
Now, as Tenfour04 mentioned, you have to figure out the conversion of the screen's XY of the touch point into the game world's coordinates. Tenfour04 made a good comment about using the projection method on the viewport camera to achieve this. Once you do that, you can send the coordinates to your actor to do the previously mentioned stuff.
To achieve the movement, I'd use the Action framework, like below:
actor.addAction(moveTo(x, y, 0.4f, Interpolation.circle));
This page shows you all the nice actions available for Scene2d: https://github.com/libgdx/libgdx/wiki/Scene2d#actions
Hope that's what you needed. :)
I'm developing a Tower Defense game using libGDX. I've just started and I am able to display the path, the "environment" and the enemies walking along the path.
I displayed the environment using a SpriteBatch-Object, like this:
public LevelController(Level level) {
spriteBach = new SpriteBach();
atlas = new TextureAtlas(Gdx.files.internal("images/textures/textures.pack"));
}
public void setSize() {
spriteBatch.setProjectionMatrix(this.cam.combined);
}
public void render() {
spriteBatch.begin();
drawTowerBases();
spriteBatch.end();
}
private void drawTowerBases() {
// for each tower base (=environment square)
TextureRegion towerBaseTexture = atlas.findRegion("TowerBase");
if(towerBaseTexture != null) {
spriteBatch.draw(towerBaseTexture, x, y, 1f, 1f);
}
}
This is working properly and the textures are displayed well: Tower Defense using spriteBatch
Now, I was wondering if it is possible to cache the background. Because it stays the same, there is no need to calculate it every time. I've found the SpriteCache through Google-Search. So I changed the code as follows:
public LevelController(Level Level) {
spriteCache= new SpriteCache();
atlas = new TextureAtlas(Gdx.files.internal("images/textures/textures.pack"));
spriteCache.beginCache();
this.drawTowerBases();
this.spriteCacheEnvironmentId = spriteCache.endCache();
}
public void setSize() {
this.cam.update();
spriteCache.setProjectionMatrix(this.cam.combined);
}
public void render() {
spriteCache.begin();
spriteCache.draw(this.spriteCacheEnvironmentId);
spriteCache.end();
}
private void drawTowerBases() {
// for each tower base (=environment square)
TextureRegion towerBaseTexture = atlas.findRegion("TowerBase");
if(towerBaseTexture != null) {
spriteCache.add(towerBaseTexture, x, y, 1f, 1f);
}
}
And now the game looks like this: Tower Defense using spriteCache
For me it seems as if the transparency is not rendered properly. If I take images without transparency, everything works fine. Does anyone have an idea, why this happens and how I can fix this?
Thank you in advance.
Taken from the SpriteCache documentation:
Note that SpriteCache does not manage blending. You will need to enable blending (Gdx.gl.glEnable(GL10.GL_BLEND);) and set the blend func as needed before or between calls to draw(int).
I guess there is not much more to say.