Introduction
My app should show a button that fills up the entire screen, but stays quadratic. I have accomplished that by referencing orientation-dependend dimen-values:
activity_main.xml
<ImageButton
android:id="#+id/fartbutton"
android:layout_width="#dimen/fartbuttonWidth"
android:layout_height="#dimen/fartbuttonHeight"
android:layout_gravity="center"
android:src="#drawable/sel_fart_button"
android:scaleType="fitCenter"
android:adjustViewBounds="true"
android:background="#android:color/transparent"
android:clickable="false"/>
dimens-land/dimens.xml
<resources>
<dimen name="fartbuttonWidth">#dimen/wrap_content</dimen>
<dimen name="fartbuttonHeight">#dimen/match_parent</dimen>
</resources>
dimens-port/dimens.xml
<resources>
<dimen name="fartbuttonWidth">#dimen/match_parent</dimen>
<dimen name="fartbuttonHeight">#dimen/wrap_content</dimen>
</resources>
This was to ensure, that the ImageButton couldn't be pressed by touching the top of the screen, which would be far away from the image.
I since have implemented a check to ensure, that the button only reacts to presses on an opaque part of the image, ignoring touch on transparent areas. There this might not be as necessary anymore.
I also have programmed a widget on which I think I'm not able to change the layout programmatically. That's why solutions to the following problem that work entirely within the XML-files are prefered.
The problem
I know that when I change the orientation of my device, the activity gets completely destroyed and recreated. In that process, the OS transitions between the two states with a nice (and wanted) rotation. However, it also stretches and fades the two buttons in an ugly way, as shown in the image.
I assume that it tries to respect the match_parent attribute of the old button and therefore stretches the image to match the full new width.
I already searched for how to disable activity transitions and tried to find an existing solution to my problem. Sadly, since most people would like to add custom animation to orientation changes or disable the rotation animation completely, my searches for this problem haven't been successfull.
Is there an easy way to circumvent this ugly stretching? Would a shared element activity transition work? What solutions come to you mind? :)
Edits
First edit
Seems like setting all dimensions to wrap_content (even that of the FrameLayout) and fixing the button's dimension to 200dp don't work. Now I assume that the OS is simply taking a screenshot and stretching it to the new landscape proportions or vice versa.
Is there a way to disable this behavior? The new button is fully opaque and rotates just fine. It probably would be enough to disable the fading animation.
Second edit
I now noticed this behaviour in all the apps on my phone. I could not find a way to tell Android to just not do it... :(
You can create a square FrameLayout by subclassing FrameLayout and overriding onMeasure:
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int size = width > height ? height : width;
setMeasuredDimension(size, size);
}
Then wrap your button in this FrameLayout in your layout.
As Rahil2952 pointed out referring to this answer, there seems to be no solution. It is a "feature" Android provides, over which the programmer does not have easy control.
Related
I'm using a TabLayout, and no matter what layout options I choose, it looks bad somewhere. Here's what I've tried, and the results:
Gravity center, mode scrollable: if there is too much space
horizontally on the screen, the tab bar doesn't fill the width
Gravity center, mode fixed: if there is not enough space, the text
wraps (which would be OK except it's the last letter of a single word.
Looks ridiculous.
Gravity fill, mode fixed: if not enough space, text wraps
Documentation says fill/scrollable is invalid, which is unfortunate because it seems like that's exactly what I need - fill all available space, and scroll if there is not enough. I tried it anyway, and it doesn't fill.
I have tried setting tabMaxWidth to 0dp with all these combinations, and it doesn't seem to have any effect. I have tried various solutions I've found around here with doing things in styles.xml or in code, with no success. Is there just no way to get this thing to behave on all screens? Do I need to calculate the screen width and adjust the layout at runtime (barf)?
UPDATE: I decided to try measuring and adujsting. Here's the code:
tabLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
tabLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
final int tabWidth = tabLayout.getWidth();
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int screenWidth = displaymetrics.widthPixels;
if(screenWidth > tabWidth){
// The tabs won't fill the horizontal space. Switch to fixed mode instead of scrollable.
tabLayout.setTabMode(TabLayout.MODE_FIXED);
}
}
});
What happens is the screen width and tab layout width are the same. So this technique cannot help me distinguish whether there's not enough or too much space. I tried it with the TabLayout width set to wrap_content instead of match_parent and that didn't work either. Still looking for a solution.
EDIT: Here are screenshots of the behavior.
If I can get the white behind the tab layout to be gray that would probably be good enough, but I think that's the activity / application background color, and I don't want to change that to gray.
Here's the background setting in the XML: app:tabBackground="#drawable/tab_selector"
That leads to:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/tab_background" android:state_selected="true"/>
<item android:drawable="#color/tab_background"/>
</selector>
tab_background is #a2a2a3
I want to set dimensions for my custom alert dialog, based on screen orientation. My intention is to swap height and width values to keep the box look like being the same size, yet handled various screen sizes of various devices, thanks to Android fragmentation it seems difficult to achieve the same effect on all devices. Android's auto-resizing seems weird to me.
Portrait:
alertDialog.width=screen.width*0.8
alertDialog.height=screen.height=0.5
Landscape:
alertDialog.width=screen.width*0.5;
alertDialog.height=screen.height*0.8
Please note that the Custom Alert Dialog must use the same code and support Android versions from JellyBean (at least 4.2) to Nougat (7).
i am using android.support.v7.AlertDialog (the latest available thing)
i assume android.app.Dialog should be avoided now (being old)
Also, i need a black border and white background for the same. i am unable to achieve same effect on all devices, (i need transparency for rounded corners)
i have used android:windowMinWidthMajor and android:windowMinWidthMinor but they affect both layouts (portrait and landscape) and seem to be ignored if content does not fit within the specified constraints.
I wish there was android:windowMaxWidthMinor & android:windowMaxWidthMajor
This is something that I've used for resizing specific views on a page:
myView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
item.height = myView.getHeight();
});
Applying it to what you want to do:
myView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
LayoutParams params = (get the layout params according to the layout);
params.width = myView.getWidth() * 0.5;
params.height = myView.getHeight() * 0.8;
myView.setLayoutParams(params);
});
You have to use the listener because the object will be added to the view tree, will be measured and prepared for display, but won't yet be displayed, so you can change its dimensions before it is visible.
Update:
I could achieve it by setting android:layout_centerInParent="true" for my Layout. and layout values for each component in the style to
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_gravity="center"
to achieve the center alignment.
XML Code available at https://github.com/computingfreak/CFTest/blob/master/app/src/main/res/layout/alert_popup.xml
Java Code available at
https://github.com/computingfreak/CFTest/blob/master/app/src/main/java/net/cf/sms/cftest/MainActivity.java
I wonder this line of code is redundant
view.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
and thus left it to Android System to decide dimensions and resizing based on content. It works for my case, but will fail in case of long text, maybe some kind of Scroll Layout will help. Cheers!
Basically my goal is to set some custom View size exactly to 1/3 of the screen for portrait orientation and 1/6 for landscape
The first thought that came to my mind is to simply calculate some mSize variable and set it to the View in OnMeasure like this:
mSize = (AContext.getScreenSize().x / (orientation == Configuration.ORIENTATION_PORTRAIT ? 3 : 6)
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(mSize|MeasureSpec.EXACTLY, mSize|MeasureSpec.EXACTLY);
}
And it's working just fine, till i rotate the screen. The thing is that when screen is rotating View initialization and sizing are called before the orientation value will actually change, so the result is that it goes one third to landscape also, if it was opened with portrait orientation firstly, and other way around.
I'm aware that i can do something like :
android:configChanges="orientation|screenSize"
In AndroidManifest for my Activity and override onConfigurationChanged to handle the rotation and change mSize value there, but, it disables auto choosing between portrait and landscape layouts(from .xml files on inflating). So i'm ending up with the same xml file for both orientations.
Is there a way to keep orientation value from context.getResources().getConfiguration().orientation consistent?
Or i need to do some workaround with onConfigurationChange to enable layout choosing?(i don't want to do it maually in code thou)
Or is there a better way to achieve my goal, and i'm just doing it wrong from the start?
Please help me.
first I would say to not use android:configChanges="orientation|screenSize" on this situation. It makes no sense such a thing on a custom view.
Secondly I believe the main mistake is the way you're capturing the 3, or 6 values. As you can achieve it much simpler using XML.
res/values/integers.xml
<integer name="view_fraction">3</integer>
res/values-land/integers.xml
<integer name="view_fraction">6</integer>
Then during your view constructor you simply call:
int val = context.getResources().getInteger(R.integer.view_fraction)
Furthermore, I will offer some other suggested improve on your view size calculation by suggesting you to simply use code that Google provides us, instead of trying to re-code it. Using the classes from android.support.percent
If your custom view extends from FrameLayout or RelativeLayout I would suggest you to instead extend from their percent counterpart PercentFrameLayout and PercentRelativeLayout.
If the custom view does not extends from one of those, you can use their helper PercentLayoutHelper following the guide on their page.
That way you can easily dinamically assing percentage of view size on your XML layout
I have a DialogFragment with a ViewPager that shows some pictures. The problem that there's a weird black stripe on top, and these pictures are deformed.
This is what I currently have, and as you can see, the picture doesn't really look good and there's a weird black stripe on top of the dialog.
This is how it should look, without black stripes and the picture fits the width of the screen.
How could I do this?
Thanks a lot in advance.
To get rid of the black frame at the top, try calling the DialogFragment.setStyle(int style, int theme) method in your DialogFragment.onCreate(Bundle savedInstanceState) method, e.g. setStyle(DialogFragment.STYLE_NO_TITLE, 0) or setStyle(DialogFragment.STYLE_NO_FRAME, 0).
I'm also having problems like you getting a DialogFragment to be a certain width. The layout_width value of my DialogFragment (as specified in my DialogFragment's xml layout file) seems to get overridden somewhere and sometimes my DialogFragment expands and sometimes it shrinks depending on the content. A bit of a hack I know but the best I've been able to come up with is to call the getDialog().getWindow().setLayout(int width, int height) method in my DialogFragment.onResume() method, e.g. getDialog().getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT).
To then resize your images to fit within your DialogFragment, use the ImageView.setScaleType(ImageView.ScaleType scaleType) method as the other answers in this thread have alluded to.
You could set the imageview android:scaleType="centerCrop" or perhaps just setting the height of the viewpager and images to wrap_content.
you should set the attribute android:adjustViewBounds="true" in your imageView
I have a layout which I want to slide down, but not entirely so you can still see a "scroll back up" text. So how I want to do this:
get the dimensions of the device. Put paddingTop = screenHeight - 7dp (for the text). Is this possible? I've tried with layoutparams too but then everything in the layout resized, including the "scroll back up" text.
What is the best way of doing this?
You could use Animation to accomplish this task.
A working example using animation with ViewFlipper can be found here.