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.
Related
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);
}
For organization's sake, I use multiple scenes for my game and rather than having each scene have a constructor that receives a Viewport (my game is scalable), I would like to set each stage's viewport separate of the constructor, then after the viewport is set, add the actors. In the main class, it would happen like this:
public void setStage(Stage s)
{
if(currentStage != null)
currentStage.dispose();
currentStage = s;
currentStage.setViewport(view);
}
To make this go fluidly, each stage has an init method that is called within an overriden setViewport:
#Override
public void setViewport(Viewport v)
{
super.setViewport(v);
init();
}
However, all this gives me is a black screen... I have tried updating the camera and viewport, but no avail (note that the actors are having their render methods called).
Why am I getting this black screen and how do I fix it? If it's not possible I'll just revert to using the constructor.
If I understood correctly you want to do this:
Stage stage1 = new Stage();
stage1.getViewport().update(width, height);
rather than this:
Stage stage1 = new Stage (new StretchViewport(width, height)); // It doesn't have to be StretchViewport
In the first case (what you are trying to do) a ScalingViewport will be costructed automatically for you with dimensions of the Gdx.graphics and an orthographic camera and acts like a StretchViewport. Why not using the second case directly where you pass the viewport you want. You can always alter your viewport whenever you want by calling stage1.getViewport().update(width, height);
or by calling stage1.setViewport(width, height, false); in older Libgdx versions.
Viewport has changed recently so if you can extend Viewport class to Override the update method maybe you can achieve what you want:
public class ViewportExtendClass extends StretchViewport{
public ViewportExtendClass(float worldWidth, float worldHeight) {
super(worldWidth, worldHeight);
}
#Override
public void update (int screenWidth, int screenHeight, boolean centerCamera) {
super.update(screenWidth, screenHeight, centerCamera);
// DO YOUR INITIALIZATION HERE
}
}
From your main class you create new stage :
Stage stage1 = new Stage (new ViewportExtendClass (width, height));
and then you call :
stage1.getViewport().update(width, height);
Like this you can alter stage viewport and re initialize your assets.
#Override
public void setViewport(Viewport v)
{
super.setViewport(v);
this.getViewport().update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
Camera c = this.getViewport().getCamera();
c.position.set(c.viewportWidth/2, c.viewportHeight/2, 0);
init();
}
This works, but you should also be able to update the Viewport like that at the begin of your application, if you continue to use the same one. I set the position like that instead of centering because some of my Stages will be larger than the screen.
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)
I have to write a simple Java app which can load pictures, show it in a GUI form, allow the user to apply some transformation, and show the transformed picture.
My solution is working fine, but the UI is flickering a bit, because the repaint method called too often (for example when the user scaling the image with a JSlider)
My code looks like this:
public class ImageCanvas extends Canvas
{
private BufferedImage image;
// ...
#Override
public void paint(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
if(image != null)
{
// I draw out the image...
}
}
public void setImage(BufferedImage image)
{
this.image = image;
this.repaint();
}
public void setRotation(double rotation)
{
this.rotation = rotation;
this.repaint();
}
public void setScale(double scaleX, double scaleY)
{
//set the scaling field, then repaint ....
}
// and so on...
}
And, of course, I have an ImageCanvas control on my main UI, and I simply call the public methods (see for example the "setRotation" method above) which repaint the canvas area. I know it's a simple question, but I don't even find a DoubleBuffered property on the Canvas...
Any help appreciated.
Double buffering is built-in for Swing (i.e. JComponent derived) classes.
If you want built-in double-buffering, you should extend JPanel rather than Canvas, and override paintComponent, not paint.
If you can use JPanel than go for it. Please make sure you are not overriding the JPanel.paint method, override JPanel.paintComponent instead.
See this link for details.
Usually graphic lags in these applications can be caused by setting a empty variable at the top of the script, then changing its value, then waiting for the repaint to update it. You could try changing the:
setRotation(double rotation);
so that it rotates the image in that method.
Just a general thing I happen to see while dealing with graphics.
My goal is to have a splash screen with an animated gif 80 pixels below center of the screen. Loading the screen's background image and animated gif is easy, as is positioning the animated gif 80px below center. My problem is that the VerticalFieldManager background (which contains the animated gif field) is filled with all white (by default). I can set the manager's background color, but the screen's background image isn't just one solid color.
public final class SplashScreen extends MainScreen {
public SplashScreen() {
// create and load the background image BitmapField
this.add(backgroundImage);
// create and load the progress bar
BitmapField progressBar = new BitmapField(progressBarImage, Field.FIELD_HCENTER | Field.USE_ALL_WIDTH | Field.NON_FOCUSABLE);
VerticalFieldManager manager = new VerticalFieldManager(Field.USE_ALL_WIDTH | Field.FIELD_HCENTER) {
protected void sublayout(int maxWidth, int maxHeight) {
// positioning code...
}
};
manager.add(progressBar);
this.setStatus(manager);
}
}
I've tried various subpaint() overrides to set the Graphics, but can't seem to set anything other than a solid color. Calling setGlobalAlpha() doesn't have the desired results either (as noted in other posts).
Any thoughts?
You may try using the paintBackground method to paint all of your background images and colors.
protected void paintBackground(Graphics g) {
g.setGlobalAlpha(255);
g.setColor(backgroundColor);
... more background drawing ...
}
For modifying the background on screens, use
this.getMainManager().setBackground(...);
You should be able to set and image, a color, whatever you need for the background to the screen.