Android TabLayout no layout works on all devices - android

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

Related

control dimensions of custom alert dialog in different screen orientations

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!

Avoid animation on orientation change to prevent ugly view stretching

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.

Android ViewPager center item on screen

I am trying to show a dialog over my screen. And that dialog should have ViewPager in it with FragmentPagerAdapter. Each item in adapter has width set to .7f. What is important to me is that when some item is selected it should be snapped to center of the ViewPager with parts of next and previous fragments visible (exactly as image shows). Unfortunately the default behavior is snap to the left.
Is there any way of achieving it please?
Thank you
(Just if anybody asks: On that picture the ViewPager is not stretched over dialog. In real the dialog matches parent's width and is layouted the way so it doesn't look like it)
Just in case anyone is looking for the same thing, I've come to solution:
Simply set left and right padding to ViewPager and then set clipToPadding to false. That will result into one fragment to be centered and pieces of neighbor fragments in sides as it is in picture. Then to add space between fragments use viewPager.setPageMargin(); in code.
That's it :)
EDIT://
Here is some sample code
<android.support.v4.view.ViewPager
android:id="#+id/viewPager"
android:clipToPadding="false"
android:paddingLeft="40dp"
android:paddingRight="40dp"
android:layout_width="match_parent"
android:layout_height="match_parent" />
ClipToPadding=false ensures that fragments will be drawn even when they are positioned out of the viewPager's content area.
And then in code add spaces between viewPager's items:
mViewPager.setPageMargin(100);
Please note that setPageMargin takes number of pixels as parameter, not number of display points. You probably should convert some dp value to pixels to have correct spacing across all devices. This method should work fine:
public static float dipToPixels(Context context, float dipValue) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dipValue, metrics);
}
I was facing a similar issue and no one tried to approach it this way, it might not be completely accurate but visually looks centered.
Use DisplayMetrics to get the device height dimension, and then set the padding for your viewpager as follows:
int height = Resources.getSystem().getDisplayMetrics().heightPixels;
pager.setPadding(0,height/6,0,0);
Note that the layout of the items of the viewpager must be set to "wrap_content" and viewpager in the activity/fragment's height must be "match_parent".
In my case, height/6 as the top padding makes it look centered. Play around with this number for your best results.

Shift layout down by using paddingTop and device Height

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.

Android: scaling a button with a background image

I'm probably just being daft but my Google searches are not working out well.
I have a bunch of buttons i add in code that all have dynamic text. I've set a background image for each of these buttons since the default greybutton doesn't work well for my application.
This works perfectly and when the text size (or content) changes, the button automatically grows to accommodate the expanded text. What doesn't work is that I'd like the button to scale proportionally - i.e. if the background image is round, i'd like it to stay round rather than oval as the button gets bigger.
With an imagebutton, there is a property "Adjust view bounds" that does exactly this but I cant put text on an imagebutton. Is there something equivalent for a regular button?
or am I going about this wrong?
i also tried setting the width of the button in code, but I can't seem to determine the new height (button.getHeight() returns 0)
ok i found one way to do it...
I modified the patch-9 to have its expandable area be the maximum on both axis.
then used the DisplayMetrics like this:
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
buttonView.setGravity(Gravity.CENTER);
int buttonSize=(int) Math.floor(metrics.density*1.6*fontSize);
buttonView.setWidth(buttonSize);
buttonView.setHeight(buttonSize);
where fontSize is the size of the font in DIP that i'm placing on each button. In this case, since I only have a single letter on each button, i don't need to worry about the text length, but one could obviously tweak this to handle that situation as well.

Categories

Resources