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
Related
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.
I have two views which overlap each other and one of them acts as a master to other. I am translating all the pinching and panning to scale and adjust the master view.
Now I wanna send this info over to the slave(Subclass of android.view.View). Being said that the other view doesn't respond to this dimensions. I have tried following methods
ViewGroup.LayoutParams params = this.getLayoutParams();
params.height = height;
params.width = width;
this.setLayoutParams(params);this.requestLayout();
setMeasuredDimension(width, height);
this.setMinimumHeight(height);
this.setMinimumWidth(width)
None of these seem to work.
Using the onTouchEvent I resize my TextureView and send the same to the other View object. On getting this Info about change in size which is in most cases greater than the parent dimensions(and screen size) the other view should also increase/change its size.
The subclassed view doesn't grow to the dimensions supplied to it. Moreover the increase is limited to the parent size(in my case its width: 1080 height: 1776) while it can go above that in the textureView which uses
textureView.setMinimumWidth(newWidth);
textureView.setMinimumHeight(newHeight);
Any ideas as to what maybe going wrong or a trusted way to change layout/dimensions across two views?
setLayoutParams => that would be the canonical way to position a View inside its parent.
setMeasuredDimension => this is used from View.onMeasure to tell the layout system what size your particular View wants. Use only if you're implementing your own View subclass.
setMinimumWidth/setMinimumHeight => tells the default View implementation what minimum size the View should have. If you implement View.onMeasure yourself, that shouldn't be needed.
All in all, if you stick with the standard Android framework components, setLayoutParams should be the place to look into.
The methods you've listed are all valid ways of setting sizes if used correctly, and in the right situations.
This is difficult to solve without further information.
In what way isn't it working? Is it causing a crash, or are the view sizes just not what you expect?
Where does that snippet sit in your code? I would guess its part of a custom class of your own which extends ViewGroup, but as you're new to stackoverflow we have no idea of your level of programming experience. It might be in completely the wrong place, and this refers to some other object entirely.
One thing I can suggest you check :
You mention your slave is a subclass of android.view.View, but this on its own is not enough to be able to use ViewGroup.LayoutParams. You need to ensure your slave is a direct or indirect subclass of android.view.ViewGroup.
Provide more of your code and info on what you are observing, and we will try and help you further.
Update:
Ok, so it's a TextureView that you are trying to resize.
I'd recommend you check the reported size of your TextureView after you set it's height and width. You could do this with break-points and run a debug, or you could use myTextureView.getWidth() and .getHeight(), and use Log statments to output them to the LogCat.
You can also check the size of the SurfaceTexture associated with your TextureView. Set a SurfaceTextureListener on your TextureView. When this listener is triggered, onSurfaceTextureAvailable() will provide the width and height of the SurfaceTexture.
I suggest this because you may find that you are able to change the size of the TextureView, but it is the content of the the TextureView that is not changing size. In this case you can override TextureView.onSizeChanged(int w, int h, int oldw, int oldh) to define the necessary transform to scale your content between the old and new sizes.
Is there any way to auto fit the screen when changing the orientation?
Because when I view my App in Portrait mode all the images seems fined but when I change it into Landscape the images becomes pix-elated or has been stretched to much. So I'm wondering if there is auto fit screen.
thanks for any thoughts.
Specify different layouts with same name in layout-land folder and use suitable drawables.
For more help see this tutorial
http://www.androidpeople.com/android-portrait-amp-landscape-differeent-layouts
Display display;
int width;
int height;
in onCreate() add
width = display.getWidth();
height = display.getHeight();
in onResume() add
if(width<height){
//you can add your layout here (landscape)
}else{
//you can add your layout here (portrait)
}
you must have two layouts, one for portrait and another for landscape orientation. You can use the same images if you use two layouts.
There are two possibilities,
Option 1 : You can have different XML layouts in layout-port ,layout-land,drawable,drawable-land. In those XML layouts, you can fix different sized images that matches your screen density.For different set of images, you can review on ldpi,mdpi,hdpi,xhdpi.
Option 2 : You can go with Nine patch images.
If you find a better solution,Share it.
Cheers.
You can use following snippet to recognize the configuration has been changed
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen and do your action here
}
Cheers.
Is it possible to change the graphic object according to the orientation of the screen.
Say for e.g. I draw a wide rectangle in landscape mode , but if i go to the portrait mode i can see only half of the rectangle drawn.
Is it programatically possible to resize according to the orientation of the screen ?
Add android:configChanges="orientation" to the manifest file and write required drawing code in onConfigurationChange() in your activity.
You can pass Display object in your custom view to get current width/height of screen,
e.g. display.getWidth() and display.getHeight().
You can obtain display object in activity as follows:
Display display = getWindowManager().getDefaultDisplay();
I am facing a weird behavior regarding the subject.
I have a very simple layout containing only an empty RelativeLayout.
Once I have input form the user this relative layout is filled with square tiles to achieve a mosaic-like effect. Each tile is made by a FrameLayout containing two images (only one is drawn at any given time). It is not possible for me to put the tiles in the XML layout because I do not know in advance how many of them I will need.
In the onSizeChanged of my relative layout, I force a resize on all the tiles to fit the new size.
The code is something like this:
public void resizeTiles(int w, int h) {
int l1 = w / X; int l2 = h / Y;
int tileS = (l1 <= l2 ? l1 : l2);
android.view.ViewGroup.LayoutParams lp;
for (Tile t : myTiles) {
lp = t.getLayoutParams();
lp.width = tileS;
lp.height = tileS;
}
}
In my manifest file I have the following:
<uses-sdk
android:minSdkVersion="4"
android:targetSdkVersion="4"
/>
Thus, target system is 1.6.
So far so good, this is working like a charm ... but only on 2.2.
The same binary placed on emulator 2.1-update1 or previous is giving me back an empty layout (I also tried a couple of physical devices, same result).
Debugging, I tracked down the problem is in the resize; commenting out width and height assignments I see the tiles but with distorted proportions.
Any suggestion on how to make this working ?
Thanks in advance.
onSizeChanged() is called late in the layout process, once the final size has been determined. There may already have been some layout passes that have happened down through the hierarchy at that point.
Basic answer is: layout params are for telling the view's parent its layout params prior to is performing a layout. If they change, the layout must be invalidated to perform a new complete layout with the new params. You should never change these in the middle of a layout.
The best thing to do is just write your own layout manager. (If you are doing layout of tiles, RelativeLayout does a ton more stuff that you don't need, making it a lot less efficient than necessary.) It is actually not very hard to write a simple layout manager.
You can use the simple layout managers in the framework as a guide:
https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/widget/AbsoluteLayout.java
https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/widget/FrameLayout.java
(Note that even these are a lot more complicated than you probably need, since they are intended to be general purpose for the layouts they are implementing. We really should have an API demo of a custom layout that is truly simple.)