I am using the following code to scale an image to 150dpx150dp and place in inside a 150dpx150dp button but the image overflows the button in all dimensions:
float densityScale = getResources().getDisplayMetrics().density;
float scaledImageWidth = 150 * densityScale;
float scaledImageHeight = 150 * densityScale;
Drawable image = getResources().getDrawable(R.drawable.user_photo);
Bitmap bitmap = ((BitmapDrawable)image).getBitmap();
Drawable scaledImage = new BitmapDrawable(Bitmap.createScaledBitmap(bitmap, (int)scaledImageWidth, (int)scaledImageHeight, true));
scaledImage.setBounds(0, 0, (int)scaledImageWidth, (int)scaledImageHeight);
((Button)findViewById(R.id.button)).setCompoundDrawables(null, scaledImage, null, null);
((Button)findViewById(R.id.button)).setPadding(0,0,0,0);
Button and image are of the same size. Why does this overflow happen and how can it be fixed?
(I know I can use an ImageButton for this but I want to use button drawable because there are cases where I will need to add text etc.)
You need to have a smaller drawable. Button already has a background with a certain padding
Related
Referring to below image, I want that view with yellow background and right border to slide in from right with some text. So this requirements include:
creating a custom view (which will need canvas I guess)
giving it width, height, position, color, border, border-color, etc.
animation to slide from right
textview within this custom view to display text
I referred this tutorial to understand how to include view with a canvas in layout. But instead of hard coded point positions, I tried following:
public MyView(Context context) {
super(context);
WindowManager wm = (WindowManager) DashBoardActivity.mContext
.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
width = size.x;
height = size.y;
width -= 10;
height -= 50;
myPath = new Pt[6];
myPath[0] = new Pt(width, height);
myPath[1] = new Pt(width - 400, height);
myPath[2] = new Pt(width - 500, height - 100);
myPath[3] = new Pt(width - 400, height - 200);
myPath[4] = new Pt(width, height - 200);
myPath[5] = new Pt(width, height);
}
But view is not getting positioned as per the expectation. I tried with different hard-coded positions, but either it's getting displayed at wrong position or not getting displayed at all.
Also, to show the text, I added textview in the layout itself but it is getting displayed at top left of the screen instead of the position shown in below image.
How I can achieve this ? Any suggestions appreciated.
You dont need any custom view for this, you can set shape or 9patch image as background to the textview and animate that textview using object animator.
Border in shape xml
I don't know if it is just me, but drawables confuse me. Are they intended to keep the size they are given, or is there a way to scale the image within them? I understand they can use ninepatch to fill certain areas by stretching an image, but I want to scale the image that it stretches. I am using a TextButton
for my menu buttons, but they are way too big, and I would love to know how to scale them. I am retrieving the skin from an atlas, which has ninepatch images in it.
Here is the settings screen:
Here are the images in the pack I am using:
Here is the initialization of the TextureAtlas, and Skin:
buttonAtlas = new TextureAtlas(Gdx.files.internal("buttons/buttons.pack"));
buttonSkin = new Skin(buttonAtlas);
Here is the initialization of that menu button.
TextButtonStyle textButtonStyle = new TextButtonStyle();
textButtonStyle.up = Assets.buttonSkin.getDrawable("bluebutton");
textButtonStyle.down = Assets.buttonSkin.getDrawable("redbutton");
textButtonStyle.font = font;
buttonMenu = new TextButton("Menu", textButtonStyle);
buttonMenu.pad(20.0f);
buttonMenu.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
game.fade.startFadeOut();
super.clicked(event, x, y);
}
});
And perhaps I could change how I put it in the table, or how I put the table in the stage?
table.add(buttonMenu).width(Gdx.graphics.getWidth()/4);
stage.addActor(table);
As a last resort I suppose I could attempt creating my own text button actor that I could scale, thank you for your time.
First of all if you know that your images are too big: The best would be to scale the images themselves to a smaller size and then use the TexturePacker too generate a new TextureAtlas that contain the smaller images.
Anyhow you can scale the image button with the TableLayout if you really want to, see example:
table.add(buttonMenu).width(100).height(100);
The above answer didnt work for me, but i have a solution.
You can make a secondary camera and attach it to your stage.
To scale the table just scale the viewport size of the secondary camera
An example would be:
//Heres where you set the scale of your buttons and your table
Camera secondaryCamera = new Camera(Gdx.graphics.getWidth() * scale,
Gdx.graphics.getHeight() * scale);
Stage stage = new Stage();
Table table = new Table();
ImageButton button = new ImageButton(drawableUp, drawableDown, drawableChecked);
table.setFillParent(true);
stage.getViewport().setCamera(secondaryCamera);
table.add(ImageButton);
stage.addActor(table);
This works great when your using it for touch controls. You can use a table for the entire UI and scale it to your liking independent of your other game items;
table.add(buttonMenu).width(100).height(100); should work, and you just need to adjust the width and height parameters to your liking, or you can use the setBounds method. Here is an example:
TextButton myButton = new TextButton("Press Me", style);
myButton.setBounds(xCoordinate, yCoordinate, width, height);
You can set size of Drawable in ButtonStyle to resize your Button:
float scale = 0.5f;
float currentHeight = textButtonStyle.up.getMinHeight();
textButtonStyle.up.setMinHeight(currentHeight * scale);
For more information, see official document for layout:
UI widgets do not set their own size and position. Instead, the parent widget sets the size and position of each child. Widgets provide a minimum, preferred, and maximum size that the parent can use as hints. Some parent widgets, such as Table and Container, can be given constraints on how to size and position the children. To give a widget a specific size in a layout, the widget's minimum, preferred, and maximum size are left alone and size constraints are set in the parent.
And you can find the implementation of Button.getPrefHeight() in the source code:
public float getPrefHeight () {
float height = super.getPrefHeight();
if (style.up != null) height = Math.max(height, style.up.getMinHeight());
if (style.down != null) height = Math.max(height, style.down.getMinHeight());
if (style.checked != null) height = Math.max(height, style.checked.getMinHeight());
return height;
}
The problem with properly handling multiple screen sizes on Android has been talked all over thousands of times. However I couldn't find a solution to m problem. In a nutshell I need to align my custom progress bar over an imageView. I've got 3 set of drawables for the imageView - ldpi(240x400), mdpi(320x480), hdpi(480x800). I align my custom view in Java with the following code:
//get screen density
float density = getBaseContext().getResources().getDisplayMetrics().density;
//set the progress bar position according to screen density
if ( density == 1.0f)
{
ImageView micImage = ((ImageView) findViewById(R.id.imageViewClk));
Drawable drawing = micImage.getDrawable();
Bitmap bitmap = ((BitmapDrawable)drawing).getBitmap();
// Get current dimensions
int width = bitmap.getWidth();
int height = bitmap.getHeight();
LayoutParams params = new LayoutParams((int)(height/13.94), (int)(height/13.94));
params.setMargins((int)(width/2.30), 0, 0, (int)(height/2.75));
params.addRule(RelativeLayout.ALIGN_LEFT,R.id.imageViewClk);
params.addRule(RelativeLayout.ALIGN_BOTTOM,R.id.imageViewClk);
myCustomTwistedProgressBar.setLayoutParams(params);
}else if ( density == 1.5f ){
ImageView micImage = ((ImageView) findViewById(R.id.imageViewClk));
Drawable drawing = micImage.getDrawable();
Bitmap bitmap = ((BitmapDrawable)drawing).getBitmap();
int width = bitmap.getWidth();
int height = bitmap.getHeight();
LayoutParams params = new LayoutParams((int)Math.round(height/14.13), (int)Math.round(height/14.13));
params.setMargins((int)Math.round( width/2.27), 0, 0, (int)Math.round(height/2.91));
params.addRule(RelativeLayout.ALIGN_LEFT,R.id.imageViewClk);
params.addRule(RelativeLayout.ALIGN_BOTTOM,R.id.imageViewClk);
myCustomTwistedProgressBar.setLayoutParams(params);
}else if ( density == 0.75f ){
ImageView micImage = ((ImageView) findViewById(R.id.imageViewClk));
Drawable drawing = micImage.getDrawable();
Bitmap bitmap = ((BitmapDrawable)drawing).getBitmap();
// Get current dimensions
int width = bitmap.getWidth();
int height = bitmap.getHeight();
LayoutParams params = new LayoutParams((int)(height/14.88), (int)(height/14.88));
params.setMargins((int)(width/2.27), 0, 0, (int)(height/2.69));
params.addRule(RelativeLayout.ALIGN_LEFT,R.id.imageViewClk);
params.addRule(RelativeLayout.ALIGN_BOTTOM,R.id.imageViewClk);
myCustomTwistedProgressBar.setLayoutParams(params);
}
Everything worked fined on different screen sizes however when I tried to check on 480x854 resolution the vertical alignment of the custom view was incorrect. Checked with 480x800 on the same screen size and it again works. I than went for a big jump and checked in GalaxyTab and the horizontal and vertical alignments were wrong. Now my first though was that the bitmap width and height were the one of the image not the actual resized imageview. So I spent a lot of time on trying to get the real size of the imageview and even went for viewTreeObserver but the results were all the same - the correct, unchanged (unscaled?) bitmap size. So being positive that the problem is not here I couldn't get through further. Does anyone have an idea why the alignment is not working correctly?
PS: as for the image view in layout xml file I have 2 configurations for long and notlong but this image has the same description in both:
<ImageView
android:src="#drawable/cloking"
android:id="#+id/imageViewClk"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_centerHorizontal="true"
android:layout_above="#+id/imageViewProcess"
android:adjustViewBounds="true"
android:cropToPadding="false"
android:layout_marginTop="60dp"
android:scaleType="fitXY">
</ImageView>
Android will scale the image but it will maintain aspect ratio for the image. You can't control aspect ratio with layout settings (as far as I know). I would solve that problem by choosing few screen ratios that I want to support and making few more resources (images that would have aspect ratios that you support). Code would look like this:
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
ImageView image = (ImageView) findViewById(R.id.imageViewClk);
if(width/height == aspectRatio1)
{
image.setImageResource(R.id.imageAspect1);
} else if( width/height == aspectRatio2...
I have an RelativeLayout that contains a custom ImageView, the scaleType="centerInside", I load in a bitmap (usually smaller than the imageView). How can I get the top/left position of where the bitmap was drawn? I need to be able addView's on top a positions relative to the bitmap.
RelativeLayout view = (RelativeLayout) inflater.inflate(R.layout.scroll_scaled, container, false);
ContentImageView image = (ContentImageView) view.findViewById(R.id.base_page);
Bitmap bm = mInterfaceActivity.getPageImage(mPageNumber);
image.setImageBitmap(bm);`
The layout file scrolled_scaled
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:scaleType="centerInside"
android:id="#+id/base_page"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ff00ff00"
android:contentDescription="#string/product_page"
android:src="#android:drawable/ic_menu_report_image" >
</ImageView>
</RelativeLayout>
You'll need to do the math yourself using the bounds of the Drawable.
ImageView test = (ImageView) findViewById(R.id.base_page);
Rect bounds = test.getDrawable().getBounds();
int x = (test.getWidth() - bounds.right) / 2;
int y = (test.getHeight() - bounds.bottom) / 2;
First we calculate the space in the View that is not being used by the image. Then since it is centered the extra space is evenly distributed before and after the image so it is draw half of that length into the View.
These numbers are relative to the location of the View but you can add the views X and Y if you need you.
This method returns the bounds of image inside imageView.
/**
* Helper method to get the bounds of image inside the imageView.
*
* #param imageView the imageView.
* #return bounding rectangle of the image.
*/
public static RectF getImageBounds(ImageView imageView) {
RectF bounds = new RectF();
Drawable drawable = imageView.getDrawable();
if (drawable != null) {
imageView.getImageMatrix().mapRect(bounds, new RectF(drawable.getBounds()));
}
return bounds;
}
UPDATE 2: getX and getY will return 0 if you're using unspecified width and height (e.g. wrap_content). Instead of iv.getX() and iv.getY() replace that with the answer to this question: Getting View's coordinates relative to the root layout then add the bounds of the image to those values.
You can do this by adding the ImageView's position to the top left bound of the drawable inside. Something like this:
ImageView iv = (ImageView)findViewById(R.id.image_view);
Drawable d = iv.getDrawable();
Rect bounds = d.getBounds();
int top = iv.getY() + bounds.top;
int left = iv.getX() + bounds.left;
UPDATE: For images that are scaled, you'll have to multiply the top and left coords by the image scale to get more accurate positioning. You can do that like this:
Matrix m = iv.getImageMatrix();
float[] values = new float[9];
m.getValues(values);
float scaleX = values[Matrix.MSCALE_X];
float scaleY = values[Matrix.MSCALE_Y];
Then you'd have to multiply top by scaleY and the left by scaleX.
Ended up with a two part solution, based on the feedback and a bit of retry.
I created the subviews an added them to the RelativeLayout in "approximate"
position, but as View.INVISIBLE.
I super-classed the RelativeLayout ViewGroup and in the onLayout I walked
the list of child views and put them in the "proper" place as I now
had the RelativeLayout self-aware of its expanded size.
Seems clunky, but it works.
Thanks to all for the suggestions, my solution was taking pieces of everyones advice.
I'm trying to create a dynamic icon menu for my android application.
The icon is made from 2 drawable, a 9-patch background image with the icon image overlay on it.
With reference to overlay two images in android to set an imageview, I've the following code which have the overlay nicely.
Resources res = parent.getResources();
Drawable icon_bg = res.getDrawable(R.drawable.menu_icon_bg);
Drawable icon = res.getDrawable(R.drawable.menu_icon);
// Not working
int int_icon_height = icon.getIntrinsicHeight();
int int_icon_width = icon.getIntrinsicWidth();
Rect rect_icon_bg_bound = new Rect();
rect_icon_bg_bound.left = 0;//(int) Math.round(int_icon_width*-1.5);
rect_icon_bg_bound.right = (int) Math.round(int_icon_width*1.5);
rect_icon_bg_bound.top = 0;//(int)Math.round(int_icon_height*-1.5);
rect_icon_bg_bound.bottom = (int)Math.round(int_icon_height*1.5);
icon_bg.setBounds(rect_icon_bg_bound);
Drawable[] layers = new Drawable[2];
layers[0] = icon_bg;
layers[1] = icon;
LayerDrawable layerDrawable = new LayerDrawable(layers);
ImageView iv_icon_combined = new ImageView(getApplicationContext());
iv_icon_combined.setImageDrawable(layerDrawable);
The problem I'm facing right now is adding a padding so that the icon will have some spacing within the background.
Hope to get some enlightenment here, thanks in advance.
I just ran into this same issue. Take a look at the setLayerInset method on LayerDrawable. It takes the layer level as an argument and then the modifiers for the left, top, right, bottom bounds of the drawable.