Android Studio - Images Expand Buttons (and break weight rules?) - java

I have been working around an issue for far too long. Any time I drop an image into an ImageButton, the button expands to be very large. To try to fix this, I created a TableLayout with TableRows, where the TableLayout has a weightSum and the rows each have their own layout_weight. However, regardless of how much weight that I assign a row, the image blows up and compresses all of my other rows. In other words, the TableRows do not respect the layout_weight assigned to them.
Below, I have four rows with weights 4, 5, 3, 1, respectively. The ImageButton is in the 3rd row with layout_weight="3". However, as you can see, the row expands to fit the button image.
At any rate, this is a major issue when I have multiple buttons on the screen. I have created many buttons of the same exact size thinking that I would make them large, so they will scale well with larger devices. Once again, the problem is that they don't scale down to fit inside of a button, but they expand the button, destroying all of the layout_weights in the process.
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="13"
android:background="#drawable/edit_users_view">
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="4"/>
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="5">
<ScrollView>
<!-- Figure out button first -->
</ScrollView>
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="3">
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/selector_cancel_button"/>
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
</TableRow>
</TableLayout>
In addition - This issue may be in part with how I am storing my images. I have saved everything into my drawable folder, but nothing inside my mipmap folders. Though, I did try saving this cancel button into the mipmap-mdpi folder and loading it into the ImageButton, but the effect was exactly the same. Mipmap folders probably just set resolution, not size? I didn't expand my drawable folder because there are maybe 50 images/selectors inside.

<ImageButton
android:layout_width="XXdp"
android:layout_height="XXdp"
android:background="#drawable/selector_cancel_button"/>
Set a specific density pixel for your ImageButton, it will limit it from expanding.
This answer is more like a HACK. The right way to do it is to have respective different images for all your screen sizes.
ldpi, mdpi, hdpi, xhpdi, xxhdpi, xxxhdpi. There are multiple open threads here on Stack on how to achieve that. Hope that helps.

The best that I can recommend you is to get your images sliced on the highest resolution you are targeting, let's say your higher resolution you are targeting is 1080x1920. Get you screen designed on this resolution and get the images on the actual size from this screen design. Put that images in respective "drawable" not "mipmap" like for 1080x1920 the respective folder is "drawable-xxhdpi". Access your images though drawable folder and then you don't even need to use weights or even fixed sizes. It will work like a charm.

The problem is that I was working with a single layout size with a single drawable sized button. The fact is, there are different screen densities, and different images should go to each. For those new to android programming, you can see my project folders transform to be what they "should have been" from the start. Take a look below.
As a short note - androd:layout_weight="1" for example, refers to how important that layout is to the entire layout. Widgets or layouts with lower layout_weights are HIGHER PRIORITY than those with higher layout_weights. As far as I know know, weightSum and layout_weight aren't related, like I thought they were in my XML example.
_
I created different sized images and put them in their respective folders, where the first drawable folder is used for "selectors" only. Each folder has the same images, just 80 percent smaller than the last folder. Android automatically takes the correct image for you and adds it to the layout preview you are working with. Once I had all of the images for each folder size, I compressed the files, then added them to android studio. I no longer had any issues running my program on ANY phone. Not to mention it was a lot easier to work with my buttons since they weren't physically MASSIVE in size for small phones, and normal sized for XLarge devices.
If issues still persist with out of memory errors, one could increase the heap size in the manifest.xml, but it doesn't seem necessary unless you are making a game. I tried increasing the heap in my super small program, and I could see a speed difference on some devices - the lesson here is to avoid largeHeap="true" unless you REALLY need it
The bottom line is that, if you want a good program, there aren't shortcuts. Learning libraries such as Picasso take time as well. Pick your poison.
On a final note, you can see that there are now 4 layout folders. Each of them contained XML files that were programmed independently so that everything looks the same for each screen density. If we are being honest here, this was mostly copying and pasting with minor modifications to each XML. When making the XML files inside each folder, you name them the files the same names. So activityMain.xml would be created in all 4 folders, and the device running the application would pick the correct XML layout from the folder that the device see's fit for it's screen density. Quite amazing actually.

Related

How to make scrollable long image page?

I am making activity showing TOS(Terms of Service) contents.
TOS text content is written very long single image, which should be scrolled. And confirm button is located below it.
Is there any best practice to make it?
I used ScrollView to scroll contents.
ScrollView contains ImageView and ImageButton.
First, I insert very long TOS content image by android:src attribute.
But, xxxhdpi image file is about 1MB size and height is about 18000 thus the app crashed (it shows 'canvas trying to draw too large bitmap' error)
After that, I try using image library which are Glide and Picasso. Using them, the error doesn't occur but image quality got degraded.
I searched and tried many solution to keep resolution and render speed but failed.
I think trying to use smaller image is better solution, but in emulator scroll speed and behavior was very strange when used src attribute to draw image.
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/scrollView">
<FrameLayout
android:id="#+id/layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/imageview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"/>
<ImageButton
android:id="#+id/textview"
some code... />
</FrameLayout>
</ScrollView>
I am not sure if using single long image with scrollView to show TOS contents is correct or not. And not sure if it is possible to handle long image properly with ImageView.
Respectfully, you're making life difficult for yourself.
Having the TOS in image form only is unusual; the 'correct' approach is to have your TOS in text form, which would also be fastest to code.
If the TOS is composed elsewhere, and you don't wish to re-type it, then possibly feed the image to an online OCR service and see what comes back?
Alternately, use a WebView component connecting to a web server serving a page with only the TOS image. (But this is a bad idea, because now you'll need to set-up and maintain a web-server!)
Try to put image to drawable-nodpi folder
If you are using Glide try to use .thumbnail() attr
Add to Android manifest largeHeap attr
And at least decrease size of big image

Why does ImageButton quality blurs or reduces to worst?

My app has a ImageButton whose quality is too bad. The actual image dimensions are 4176*4176 (4176pixels) which looks completely fine when opened separately. But when I import this to android studio and assign it to a ImageButton, the quality of the image downgrades. I have been trying a number of ways to fix this but haven't succeeded yet. I'm completely new to Android Programming.I go to res/drawable then right click to create a new Image Asset and then specify the location which imports the png file.
Actual image:
Image inside studio:
Here is the code in activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:gravity="center"
android:orientation="vertical">
<ImageButton
android:id="#+id/police"
android:layout_width="317dp"
android:layout_height="295dp"
android:layout_centerInParent="true"
android:adjustViewBounds="true"
android:scaleType="fitXY"
android:background="#drawable/custom_button"
/>
</LinearLayout>
Custom button code which calls the image:
<item
android:state_pressed="true"
android:drawable="#mipmap/pressed" />
<item
android:drawable="#mipmap/defaultt" />
</selector>
You are actually referencing the image like Launcher icon in /mipmap directory.
I suggest reducing the image size which you are only using it for ImageButton and placing it inside /drawable with the quality you want or maybe smaller than the current one instead of placing it inside /mipmap directory.
Also, I don’t actually see the reason of how scaleType helps in ImageButton. You may wanna remove that line too.
I'd start by reviewing density independent pixels on Android. This is a good blog that covers the concept: https://www.captechconsulting.com/blogs/understanding-density-independence-in-android
The main issue is that your image (which is very high res) is getting compressed to fit inside of the image button. Typically, you would want to include image assets for different densities via different drawable resource directories (e.g., drawable-hdpi, drawable-xhdpi, drawable-xxhdpi).
However, these days, you can use vector drawables, which will reduce the need for having multiple assets for each density bucket, assuming you have the ability to generate SVG asset files: https://developer.android.com/guide/topics/graphics/vector-drawable-resources

How to create a large selection screen?

My app tracks how players at a pokertable play. I give my users the option to save up to 50 players stats in the form of a 'Player' object stored inside a JSON array within sharedPreferences. Allowing the user a way of selecting and loading one of these players has proven difficult.
An alertDialog seems to small, a new activity seems a bit overboard for what is essentially just a large menu and I fear passing my objects to it will prove difficult. A viewFlipper sounds interesting but I've no idea whether it's suitable.
How should I go about doing this? Filling the screen with dozens of buttons is really all I wish to do.
I agree that creating a new activity for this would be an overkill. One way to address this would be to have a GridView populated with your "buttons" - and the user would select one from the grid by clicking it. The question is where/how to display this grid.
ViewFlipper is a nice option in my opinion. The way you would go about it is place your existing layout inside the view flipper, then put the GridView into the ViewFlipper after your existing layout:
<ViewFlipper xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/flipper">
<LinearLayout ...>
<!-- this is where your main layout goes -->
</LinearLayout>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/player_select"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</ViewFlipper>
Then in your activity set up the Adapter for your grid view and the OnItemClickListener - to do something when one item is clicked. Finally somewhere (either in the main layout or in the options menu or elsewhere) provide something to display this grid view. In the handler code for that action you'd have something like
ViewFlipper flip = (ViewFlipper)flip.findViewById(R.id.flipper);
flip.showNext();
This would effectively hide your main layout and show the grid instead. And at the end of your OnItemClickListener you'll have
ViewFlipper flip = (ViewFlipper)flip.findViewById(R.id.flipper);
flip.showPrevious();
This would hide the grid view and navigate back to your main layout. Feel free to add any animation you like for the transition (e.g. 3G flip animation looks particularly nice).
Try an AutoCompleteTextView. Start typing one of the names, and a list of all possible matches pops up.
Screenshot from Google's tutorial:
I went with a ListView. It combines the filtering and tidyness of the autocomplete yet displays the names so users don't have to remember them like the ViewFlipper solution.
Thanks for both answers, they are both good solutions that helped me come to the solution I needed which combines the two.
The autocomplete had the advantage of searching so I could extend the number of players a user can save to my hearts content, it also looked neat but could not easily see the whole list which for poker players was necessary as the names you give when titling your notes are rarely your fellow players name but rather off the cuff nicknames based on their appearance/playing style. Hence using autocomplete the user will have to remember the nicknames they gave which over 50 players and potentially months apart would prove tricky.
Alek Gs solution would avoid that problem but would not be suited large numbers of names or long names for that matter as the buttons would be off fixed sizes.

Can multiple android views be stored in the same .xml file without belonging to the same parent?

I have an android project that has several small views which I need to instantiate at runtime. I haven't been able to figure out a way to store all of these related views in a single xml file and I now there are going to be many of these xml files. I was just wondering if there is any way to have them all in a single file, but not belonging to some parent ViewGroup.
The layout folder in android kinda sucks since there's no way to make subfolders, everything is just piled into the same place, ugh.
I hope someone can tell me of a better way of organizing these things.
If I understand you correctly you want several views meged onto one screen or merged into one xml file. You can include other xml's into one.
The articles showed you how to use the tag in XML layouts,
to reuse and share your layout code. This article explains the tag and how it complements the tag.
http://developer.android.com/resources/articles/layout-tricks-merge.html
Also, this video might help (about 19 minutes in). Shows you how to extract a current layout and be able to include it in others.
a couple things:
Yes, the layout folder is a pain. I use strict naming conventions to make it bearable, and in eclipse use the shortcut ctrl + shift + r to quickly find the layout I am looking for. Try naming your layouts after your activity: activity1_menu_overlay and activity1_main. With the above shortcut, just type out Activity1 and it will only show you the relevant layouts.
And if that doesn't work, you can try wrapping all your views in LinearLayouts and using view.setVisibility(View.Gone); or view.setVisibility(View.Visible); to show/hide the appropriate views.
Here is an example of that second one, because it's tough to explain.
one XML file:
<LinearLayout>
<LinearLayout ... android:visibility="visible">
<copy/paste of view 1>
</Linearlayout>
<Linearlayout ... android:visibility="gone">
<copy/paste of view 2>
</Linearlayout>
<Linearlayout ... android:visibility="gone">
<copy/paste of view 3>
</Linearlayout>
<Linearlayout ... android:visibility="gone">
<copy/paste of view etc.>
</Linearlayout>
</Linearlayout>
keep in mind this approach will require you to define a reference to each "child" LinearLayout view in your activity, so you can call setVisiblity appropriately.
This approach works well for animations, and I would only use it for 2 or 3 possible views in one xml file.

Help making a "launcher screen" for my app, and making it look right across devices

I posted a question here before: Good way to make a launcher screen for sub-apps within your app?, and then started working on other parts of the app, and now I'm back to the same thing.
I want to make a nice screen with icons that the user can press, with room for more icons at a later date. Or maybe something different, I'm not sure.
Here's a current screenshot of what it looks like:
It looks pretty bad there, on my phone it looks better, with less space between the apps (this is a friend's phone), but ideally I want it to look good on all devices.
My XML code for this is as follows:
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/gridview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:numColumns="auto_fit"
android:verticalSpacing="10dp"
android:horizontalSpacing="20dp"
android:columnWidth="90dp"
android:stretchMode="columnWidth"
android:gravity="center"
android:background="#FF6699FF"
/>
Any tips/suggestions are appreciated, I want to make this look good.
I'm not sure what format to store the icons in, right now they're just large (400x400 or so) png files.
If your icons are just squares you might want to use a compressed format like jpg or gif to reduce your app's file size.

Categories