Android Custom Compoent extending FrameLayout in Code - android

I would like to create an Android custom component for a game. The basic idea is that the custom component would be square in shape and contain other square ImageView components inside it. The ImageView components inside may be scaled and/or cropped as needed, but must remain square. The number of rows == columns, always. The difficulty level determines the exact value of rows and columns at runtime. As the game gets more difficult, the number of rows and columns will increase equally, but the scaled size of each ImageView will shrink accordingly. I would like the components to have some fixed small spacing between them, mostly so it looks nice. The display won't be scrollable, all items must fit on the display at the same time.
After a bunch of failed attempts, I'm getting frustrated and I'm not sure what is the best approach is to make this custom component.
My latest idea would be to do roughly the following:
I create my custom component class by "extends FrameLayout". In my constructor, I create an arbitrary small square ImageView object in code. I'd like others to reuse my custom component someday, so I do it in code rather than XML so that the custom component doesn't rely on any external XML drawable having to be defined. I set the scale type so that the ImageView retains it's "squareness" (I think I want fitStart?). I set the square ImageView's layout_width and layout_height to "fill_parent", so the ImageView fills in as big a space as is available in the containing FrameLayout. I add the now large and square ImageView to my layout using addView().
Next I create a RelativeLayout object and also programmatically add it to myself using addView(). Because my base class is a FrameLayout, I think this will make the size of the RelativeLayout the same as the square ImageView previously added. At least that's how I read the documentation.
Next I measure the ImageView to see how large it is. I don't think I can measure myself because my previous attempts failed at this. I kept getting 0 for my size. My research said this was because I can't measure myself during construction. This turned into a Catch-22. When I tried to scale my image to the available space, I couldn't because there was no space available yet. My hope is that because I changed to using the FrameLayout as my base class and I add the ImageView to it, I will be able to measure my newly created and correctly scaled large square ImageView.
If all goes as planned, I now know how big the space available is on the user's device for my RelativeLayout because it's the same as my ImageView. By knowing how much space is available and how many rows and columns need to be displayed, I can correctly scale each ImageView I add accordingly, assuming I remember to account for the spacing between the ImageViews I add. Now I no longer need the square ImageView and can make it go away if I want.
If reasonable, I would like the large ImageView to have rounded corners and each ImageView added also have rounded corners. With a small gap between ImageViews added, this would look cool for gameplay. This way I can leave it as a background.
This seems like a good solution, and better than my previous attempts that didn't work, but if there's a better way..., I'm listening.
Here's some psuedo-code that says mostly the same thing as above to the best of my understanding:
construct()
{
ImageView squareImageView = new ImageView(Square);
LayoutParams squareImageLayoutParams = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
squareImageLayoutParams.addRule(fitStart);
addView(squareImageView, squareImageLayoutParams);
RelativeLayout relativeLayout = new RelativeLayout(context);
LayoutParams relativeLayoutParams = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
addView(relativeLayout, relativeLayoutParams);
int size = squareImageView.getWidth(); // Should be the scaled size and square.
squareImageView.setVisibility(INVISIBLE); // maybe?
loop for each row and col
{
crop, scale and add each image to the relativeLayout object.
}
}
My most basic question is if this seems like a reasonable solution? If so, there's a bunch of things in the psuedocode I don't know how to do (yet).
How do I create a small square ImageView in code?
How do I set the scaleType in code?
Will I be able to measure my square ImageView and get the correct size?
Is there a better way to remove the square ImageView other than making it invisible?
Will making my square ImageView invisible make it unmeasurable?
I see something called a ShapeDrawable, would this be better than an ImageView for making a square?
How do I crop an ImageView to be square, distributing the loss equally to both sides?
I certainly don't expect anyone to know all these answers, but if you know any answers you can share, I would appreciate it.
Thanks.

There is a lot of built-in functionality for proper scaling to the available screen space. I do not fully understand why you want to measure the ImageViews.
Have you considered using weight? I would try a fixed size GridView (or TableLayout, or a LinearLayout of LinearLayouts). If contents are weight'ed properly, they will retain their "squareness". You could use the attributes verticalSpacing or horizontalSpacing of a GridView, or you could make empty Views for spacing in order to put weight to the spaces as well.
Do not set the weightsum attribute of the parent element, but make sure the sum of your elements' weights horizontally are equal to their sum vertically, and your square ImageViews will always scale properly, regardless of how many elements you got in there.

Related

Android: Scale a view like image?

I was creating a banner layout for our App and it turns out that there are essentially two options I have:
Have a static image for the banner
Create a banner layout that actually lays out individual elements of the banner image. This option enables changing the banner content at runtime.
Initially, I thought that creating a dynamic banner(option 2) should always be the way to go(unless you have time crunch) but it turns out if the layout is to be changed in width and height, the margins, dimensioning and position of the views might change. As an example, if there is a TextView that is supposed to take up only single line might spill over to second line if the width is shrunk. This is the case with the dynamic layout.
With static layout, overall image would scale down therefore, although the font size would go down a bit, the text would remain in one line only.
Now, this seems to be the obvious disadvantage with dynamic layouts, is there any way I can fix it...like maybe scaling up/down a view like an image instead dynamically adjusting the positioning and whatnot for the views involved?
Or, having a static banner design is preferred?

Scale down ImageButton / ImageView without leaving space around

I have some problems resizing ImageViews and ImageButtons.
Let's say that I have a Layout that has a rectangular shape (I don't want to know if it is a horizontal or vertical rectangle) and a ImageButton that contains a transparent background and as ImageResource a square image.
I want to keep the button square, so I use setScaleType(ScaleType.FIT_CENTER) to stretch the button. It works well.
The problems come when the button needs to be REDUCED to fit the rectangular layout, instead of stretched: in that case, the image is reduced correctly, but the space reserved in the layout is the one that would be reserved by the image if I hade made it crop.
This is what I think that happens:
the image is put in the layout
the space in the layout is reserved
AFTER THIS the image is resized
if the space asked is increased, the layout is enlarged, otherwise nothing is done
as a consequence in the layout the image results rounded by A LOT of empty space if the image needed to be reduced.
The classical problem is: I have a layout that should contain one row with - say - six square buttons. IF the button size is larger than the height of the Horizontal LinearLayout, the buttons end to be distantiated with a lot of empty space, instead of touching them.
I tried using fixed sizes for the images, to force them resize before putting them in the layout, but this is not a solution for me. First of all I want it to be dynamic (ie: the layout could change size during the app lifetime and the images should follow that). Second of all, when I put the image into the layout it can easily happen that the layout is not set yet and its size returns zero.
Can anyone help me?
Thank you.
Just add the attribute
android:adjustViewBounds="true"
to your image view element in your layout. You can have a look to the post Unwanted padding around an ImageView

Android layout difficulties - dynamic control of parameters and content. Best way to code?

I am attempting to make an 8x8 matrix of coloured squares on a black background in a layout that is limited to portrait only. I need the squares to all be equal in size, and the overall matrix to be 60% of the screen's width and of equal height. I also need to control the colour of each square dynamically as a result of my code, call it a pattern setting code if you will. Here is an example of what I need the final product to look like:
Screen example
I have been researching different ways of doing this and was hoping for some advice on the best approach. Here are some ideas I had:
1) Use GridLayout (not GridView) and set the background of each cell to the required colour. This shouldn't be difficult to control with java, but how do I enforce the correct dimensions? Would I need to fill each grid cell with something of a certain size, or can I use layout_weight attributes to control the dimensions?
2) Use a combination of RelativeLayout and LinearLayout with ImageView and display locally saved images of coloured squares. Can I use layout_weight to control the size of these images, and if these images were too small would they be stretched to fill their required dimensions? (I'm thinking of larger tablet screens.)
What I really need from someone is some sample code to implement a very simple version of what I need (for example one square in the centre of the screen that I can colour-control dynamically). Obviously I can then expand it to my specific requirements. If more details or code are required I will happily post them.
Perhaps you could just create a custom View object, and render the appropriate bitmap in the onDraw method? Seems like overkill to use layout objects, unless you're planning to do more than just render squares of colour?
Edit: Alternatively, I once used the info in the following posting to programmatically build a layout grid. It's not exactly what you need (it generates as many horizontal 'cells' as are necessary), but should make for insightful reading on manipulating layout dimensions:
Line-breaking widget layout for Android

Which Android layout and view to use for simple image-based game?

I would like to make a simple Android game where a large background image is displayed and some other images are displayed in specific locations over it, where the other images may be clickable.
Here's a quick sample image of what I'm talking about:
The user should be able to tap the soccer player or the moose (ah, the classic "soccer player moose problem"!)
How should I render this screen (which layouts and views?) so the user can interact with it and it will scale properly on different devices?
I would use a RelativeLayout.
You can set the you background image to the layout (fill_parent for height and width).
You can then put your ImageViews, containing your moose and soccer player down on the layout relative to the top or sides of the sceen, or relative to each other (making sure to specify "dp" units for everything). Set the backgrounds of your ImageViews to be transparent, and there won't be a bounding box problem (and/or you can also set your ImageViews alignment to be relative to each other, ensuring they don't overlap).
I think this is the simplest way to do this - it is then super easy to attach onClickListener to your ImageViews in your Activity, and you are done.
This type of layout will work the same on all devices and screen sizes.
There are some small gotcha's with RelativeLayouts, but they are pretty simple once you get into them, and provide fast rendering (since the view hierarchy is usually shallow). Good Luck.
ImageView for the clickable elements seems like a fine choice to me. For the background I would just set your image as the background of the parent layout i.e. RelativeLayout
SurfaceView for the whole thing (with your field as a background) and regular *ImageView*s for added elements. You can easily recover the click coordinates from the SurfaceView and thus know what element has been touched.
SurfaceView might offer you additional possibilities anyway.
For most images, I'd use an ImageView for each one, like FoamyGuy said.
If they're close enough for overlapping bounding boxes to be an issue, you can still use an ImageView for each, but with a variation of this answer, testing alpha for each ImageView in range.
I would agree with both FoamyGuy and Booger that if your only goal is to place static images onto the screen that do something when you click them, RelativeLayout and ImageViews all the way.
But...
If you are looking to randomly spawn multiple images onto the screen in intervals and have them move around for the player to interact with while explosions are going off and maidens are being kidnapped, you should look into SurfaceView, Canvas, Drawable, TouchEvents, and FrameBuffers.

How to design ImageViews that stretch according to the screen-size

I have a requirement where few of my image views form border areas of an application, and the application will be running on many screen sizes.
I'll be creating a uniform image for the smallest size possible, which can be repeated as many times as needed, and still presents the same image.
I want the image view to replicate the image contained whenever it is increased.
Is anything like this possible?
I tried 9-patch images, but I couldn't find nice articles on it which could explain how to create useful images with it which could suit my need.
I think you have to write a custom view to do this. Overide onDraw method in it to copy your bitmap as many times as needed.
Get the width and height of the device dynamically and set the imageview width and height in program.

Categories

Resources