how to write the code that read the size of the screen. i have 4 different layout, "layout", "layout-land", "layout-large", and "layout-large-land"
every one of the layout i need to write a different code for each of them, for example at the "layout" , i have this code imagebutton1.setVisibility(View.VISIBLE); , but at the landscape screen, i have remove the imagebutton1. so i plan to if else statement, but i duno how to determine the size of the screen by using android java, need some guide here.
Technically, you could just do something like this:
ImageButton imageButton = findViewById(R.id.image_button);
if (imageButton1 != null) {
// if the imagebutton isn't found in the view hierarchy,
// then don't attempt to manipulate it.
imagebutton1.setVisibility(View.VISIBLE);
}
Otherwise you can use:
Configuration conf = getResources().getConfiguration();
boolean isLarge = (conf.screenLayout & Configuration.SCREENLAYOUT_SIZE_LARGE) ==
Configuration.SCREENLAYOUT_SIZE_LARGE;
boolean isLandscape = (conf.orientation == Configuration.ORIENTATION_LANDSCAPE);
boolean isLargeLand = isLarge && isLandscape;
Related
I have an activity whose layout I need to change after a rotation and part of the layout is a graph that is drawn using the width and height of the view that it will be placed into. The first time my code runs, the graph is drawn correctly, however after the rotation the width and height of the container view are not correct, in fact they appear to be the view as if it was not rotated.
Here is what I have so far,
In my manifest for the activity I am working:
android:configChanges="keyboardHidden|orientation|screenSize"
In my activity I have these following methods:
onCreate
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
patient_id = extras.getInt("patient_id");
patient_name = extras.getString("patient_name");
historyDurationType = 12;
constructLayout();
}
constructLayout
public void constructLayout(){
if(landScape){
setContentView(R.layout.activity_bg_history_static_land);
//Set buttons
btnTwelve = (Button)findViewById(R.id.btnTwelveHoursLand);
btnTwentyFour = (Button)findViewById(R.id.btnTwentyFourHoursLand);
btnSeven= (Button)findViewById(R.id.btnSevenDaysLand);
btnTwelve.setOnClickListener(this);
btnTwentyFour.setOnClickListener(this);
btnSeven.setOnClickListener(this);
btnTwelve.setBackgroundColor(getResources().getColor(R.color.light_blue_regular));
btnTwentyFour.setBackgroundResource(android.R.drawable.btn_default);
btnSeven.setBackgroundResource(android.R.drawable.btn_default);
}else{
setContentView(R.layout.activity_bg_history_static);
//Set buttons
btnTwelve = (Button)findViewById(R.id.btnTwelveHours);
btnTwentyFour = (Button)findViewById(R.id.btnTwentyFourHours);
btnSeven= (Button)findViewById(R.id.btnSevenDays);
btnTwelve.setOnClickListener(this);
btnTwentyFour.setOnClickListener(this);
btnSeven.setOnClickListener(this);
btnTwelve.setBackgroundColor(getResources().getColor(R.color.light_blue_regular));
btnTwentyFour.setBackgroundResource(android.R.drawable.btn_default);
btnSeven.setBackgroundResource(android.R.drawable.btn_default);
btnComment = (Button)findViewById(R.id.btnCommentGraph);
btnComment.setOnClickListener(this);
populateOtherContent(officialReadings12);
TextView tvStats = (TextView)findViewById(R.id.txtStatistics);
Typeface chunkFiveFont = Typeface.createFromAsset(getAssets(), "fonts/chunkfivettfversion.ttf");
tvStats.setTypeface(chunkFiveFont);
TextView tvReading = (TextView)findViewById(R.id.txtReadingTitle);
tvReading.setTypeface(chunkFiveFont);
comment = null;
}
if(needData){
getLatestReadings();
}
populateGraph();
}
populateGraph
public void populateGraph(){
if(landScape){
graph_container = (LinearLayout)findViewById(R.id.graph_land_content_layout);
}else{
graph_container = (LinearLayout)findViewById(R.id.graph_content_layout);
}
//Create graphlayout
mainGraph_Layout = new RelativeLayout(this);
RelativeLayout.LayoutParams glParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
mainGraph_Layout.setId(909);
mainGraph_Layout.setLayoutParams(glParams);
graph_container.addView(mainGraph_Layout);
graph_container.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if(needsGraph){
layoutGraph();
needsGraph = false;
}
}
});
}
layoutGraph
public void layoutGraph(){
viewWidth = mainGraph_Layout.getWidth();
viewHeight = mainGraph_Layout.getHeight();
//MORE STUFF IS HERE BUT NOT IMPORTANT
}
onConfigurationChanged
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
ActionBar actionBar = getActionBar();
if(newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE){
//Config is landscape here
actionBar.hide();
needData = false;
landScape = true;
needsGraph = true;
constructLayout();
}else{
//Config is portrait here
actionBar.show();
needData = false;
landScape = false;
needsGraph = true;
constructLayout();
}
}
After rotation, it is at the layoutGraph() viewWidth and viewHeight objects where I have the problem. I had assumed by that point (having used the global layout listener) that the values would be correct. My understanding was that the listener would only have been triggered once "graph_container" was completed (and landscape or portrait) and so when calling layoutGraph() the width and height of "mainGraph_layout" (a child a graph_container, widths and heights set to MATCH_PARENT) would be good to go. It appears that the width and height I am getting are as if the phone is still portrait, and worth noting it appears that the removal of the action bar has also been taken into account.
Sorry for the long question but I thought it best to show all the code. If anything else needs to be shown then please let me know.
Thanks in advance,
Josh
There is a much better way to do this.
Use resource folders
Put your default layout files in res/layout, and the ones for landscape in res/layout-land. In other words, move res/layout/activity_bg_history_static_land.xml to res/layout-land/activity_bg_history_static.xml.
In onCreate, call
setContentView(R.layout.activity_bg_history_static);
The system will pick the file from res/layout-land when you are in landscape orientation, res/layout otherwise.
If you have views that are only present in one layout but not the other e.g. the comment button, wrap the code inside a null check like this:
btnComment = (Button) findViewById(R.id.btnCommentGraph);
if (btnComment != null) {
btnComment.setOnClickListener(this);
}
For populateGraph(), make sure both res/layout/activity_bg_history_static.xml and res/layout-land/activity_bg_history_static.xml has android:id="#+id/R.id.graph_content. Then you can do findViewById(R.id.graph_content) and get the LinearLayout you need.
Save data across rotation
In your activity, override onSaveInstanceState(), and save the data from getLatestReadings() into the bundle.
Then, in onCreate:
if (savedInstanceState == null) {
getLatestReadings();
} else {
// Restore latest readings from savedInstanceState
}
With that, you can let the system handle the rotation i.e. remove this from your manifest:
android:configChanges="keyboardHidden|orientation|screenSize"
Since the system is handling the rotation, you don't need to have a view tree observer any more. And you don't have to override onConfigurationChanged.
I'm trying to make an android app which has 2 layouts, one for phones and one for tablets.
I have the two layouts made, but I'm having difficulty populating them with content. The phone layout (res/layout) consists of 1 list view which is populated from a database.
The tablet layout (res/layout-large) has 5 separate listviews which all need to be populated.
Basically I need some way of doing this:
if(screensize != large) {
populateSingleListView();
}
else {
populateMultipleListViews();
}
I tried using the following code to do it but it doesn't seem to detect the screen size within the emulator
(getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE)
any ideas for a solution?
Thanks
Chris
public void populateList() {
ListView list1 = (ListView) getView().findViewById(R.id.list1);
ListView list2 = (ListView) getView().findViewById(R.id.list2);
if(list1 != null) {
// Do sth
}
if(list2 != null) {
// Sth else
}
}
So in small screen, you have list1 populate and big screen you have both populated.
I would recommend using fragments (and a class to create each) for each list view.
The phone layout will have a single one, and you can set up the tablet layout to contain all of them.
If you define the class that populates the fragment in the xml then you don't have to worry about choosing, it will be done for you by the framework.
try to detect it using display height & width
DisplayMetrics metrix = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrix);
displayHeigh = metrix.heightPixels;
displayWidth = metrix.widthPixels;
if(displayHeigh > displayWidth){ // or something else
// for phone
}else{
// for tablet
}
Here's a pseudo code to detect screen rotate event, and decide to retain or changes the screen orientation.
public boolean onOrientationChanges(orientation) {
if(orientation == landscape)
if(settings.get("lock_orientation"))
return false; // Retain portrait mode
else
return true; // change to landscape mode
return true;
}
How do I make similar things in Android?
EDIT:
I'm actually looking answer on Where to handle orientation changes. I do not want to fix the orientation by adding screenOrientation="portrait".
I need something, similar to onConfigurationChanges(), where I can handle the orientation, but do no need me to manually redraw the view.
You need a Display instance firstly:
Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
Then orientation may be called like this:
int orientation = display.getOrientation();
Check orientation as your way and use this to change orientation:
setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
I hope it helps.
Update:
Okay, let's say you've an oAllow var which is Boolean and default value is False.
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
int orientation = display.getOrientation();
switch(orientation) {
case Configuration.ORIENTATION_PORTRAIT:
if(!oAllow) {
setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
break;
case Configuration.ORIENTATION_LANDSCAPE:
if(!oAllow) {
setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
break;
}
}
You can add more choices.
I didn't try this sample, but at least tells you some clues about how to solve. Tell me if you got any error.
UPDATE
getOrientation() is already deprecated see here. Instead Use getRotation(). To check if the device is in landscape mode you can do something like this:
Display display = ((WindowManager) getSystemService(WINDOW_SERVICE))
.getDefaultDisplay();
int orientation = display.getRotation();
if (orientation == Surface.ROTATION_90
|| orientation == Surface.ROTATION_270) {
// TODO: add logic for landscape mode here
}
Try running
getResources().getConfiguration().orientation
From your context object to figure out what is the screen orientation at runtime, the possible values are documented here
In order to catch the orientation change event you can find the answer in the Android Dev Guide: Handling the Configuration Change Yourself
From the guide :
For example, the following manifest code declares an activity that
handles both the screen orientation change and keyboard availability
change:
<activity android:name=".MyActivity"
android:configChanges="orientation|keyboardHidden"
android:label="#string/app_name">
Now, when one of these configurations change, MyActivity does not restart. Instead, the MyActivity receives a call to onConfigurationChanged(). This method is passed a Configuration object that specifies the new device configuration. By reading fields in the Configuration, you can determine the new configuration and make appropriate changes by updating the resources used in your interface. At the time this method is called, your activity's Resources object is updated to return resources based on the new configuration, so you can easily reset elements of your UI without the system restarting your activity.
...
if (this.getWindow().getWindowManager().getDefaultDisplay()
.getOrientation() == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
// portrait mode
} else if (this.getWindow().getWindowManager().getDefaultDisplay()
.getOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
// landscape
}
You don't need to intercept the event and then override it. Just use:
// Allow rotation
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER);
// Lock rotation (to Landscape)
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE);
Points to note here are, if on Jellybean and above this will allow a 180 degree rotation when locked. Also when unlocked this only allows rotation if the user's master settings is to allow rotation. You can forbid 180 degree rotations and override the master settings and allow rotation, and much much more, so check out the options in ActivityInfo
In addition, if you have pre-set that there is to be no rotation, then your activity will not be destroyed and then restarted, just for you to set the orientation back which will again cause the activity to be restarted; Thus setting what you want in advance can be much more efficient.
Pre Jellybean use ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE -- no 180 degree rotation with this.
Check your android screen orientation at Runtime:
ListView listView = (ListView) findViewById(R.id.listView1);
if (getResources().getConfiguration().orientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
//do work for landscape screen mode.
listView.setPadding(0, 5, 0, 1);
} else if (getResources().getConfiguration().orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
//Do work for portrait screen mode.
listView.setPadding(1, 10, 1, 10);
}
Another solution to determine screen orientation:
public boolean isLandscape() {
return Resources.getSystem().getDisplayMetrics().widthPixels - Resources.getSystem().getDisplayMetrics().heightPixels > 0;
}
I am using the XML tag
android:configChanges="orientation|keyboardHidden|keyboard"
and the following code to detect device orientation changes and change layouts:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
disp = getWindowManager().getDefaultDisplay();
swidth = disp.getWidth();
sheight = disp.getHeight();
parent.removeAllViews();
parent = new RelativeLayout(this);
if(newConfig.orientation == Configuration.ORIENTATION_PORTRAIT)
layoutPortrait();
else
layoutLandscape();
}
This works fine going form portrait to landscape. But, for whatever reason, going from landscape to portrait (starting in landscape or switching to it then back) doesn't change the screen back to portrait.
Through the use of Log messages I've determined that after being in Landscape mode, the Display and Configuration classes DO NOT UPDATE. They remain holding the same orientation/length/width values as when the device was in landscape.
Does anyone have any idea why this is?
Additional Code (requested by contributor)
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
disp = getWindowManager().getDefaultDisplay();
swidth = disp.getWidth();
sheight = disp.getHeight();
int ornt;
if(swidth == sheight)
ornt = Configuration.ORIENTATION_SQUARE;
else if(swidth < sheight)
ornt = Configuration.ORIENTATION_PORTRAIT;
else if(swidth > sheight)
ornt = Configuration.ORIENTATION_LANDSCAPE;
else
ornt = Configuration.ORIENTATION_UNDEFINED;
parent = new RelativeLayout(this);
labelOne = new TextView(this);
labelOne.setText("Temperature");
labelOne.setId((int)(Math.random()*Integer.MAX_VALUE));
temp = new EditText(this);
temp.setSingleLine(true);
temp.setBackgroundColor(Color.WHITE);
temp.setTextColor(Color.BLACK);
temp.setId((int)(Math.random()*Integer.MAX_VALUE));
labelTwo = new TextView(this);
labelTwo.setText("Humidity(%)");
labelTwo.setId((int)(Math.random()*Integer.MAX_VALUE));
humidity = new EditText(this);
humidity.setSingleLine(true);
humidity.setBackgroundColor(Color.WHITE);
humidity.setTextColor(Color.BLACK);
humidity.setId((int)(Math.random()*Integer.MAX_VALUE));
output = new TextView(this);
output.setBackgroundColor(Color.WHITE);
output.setTextColor(Color.BLACK);
output.setId((int)(Math.random()*Integer.MAX_VALUE));
submit = new Button(this);
submit.setText("Calculate");
submit.setId((int)(Math.random()*Integer.MAX_VALUE));
submit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Double result = Calculate.calculate(getInputs());
if(result !=null) {
String answer = String.format("%,.1f",result);
if(f.isChecked()) {
output.setText(answer + "°F");
} else {
output.setText(answer + "°C");
}
}
}
});
f = new RadioButton(this);
f.setText("Fahrenheit");
c = new RadioButton(this);
c.setText("Celsius");
rg = new RadioGroup(this);
rg.setOnCheckedChangeListener(new ListenForMode());
rg.addView(f);
rg.addView(c);
rg.setId((int)(Math.random()*Integer.MAX_VALUE));
f.setChecked(true);
if(ornt == Configuration.ORIENTATION_PORTRAIT || ornt == Configuration.ORIENTATION_SQUARE)
layoutPortrait();
else
layoutLandscape();
}
Final Update
Issue is with the emulator not responding correctly to the orientation changes. I changed the onConfigurationChanged(...) orientation checking to use the condition width < height for portrait and all else landscape. This works perfectly on my Android device.
Thanks to all contributors to this question!
You really shouldn't be overriding the configChanges in your manifest. Android can handle redrawing the Views for you, and it actually handles it really well, especially if you have filtered layouts in your resource folder.
If you are overriding configChanges because of issues with AsyncTask losing its Context (as I once did), I would recommend using an IntentService to handle your asynchronous work as Services aren't tied to any one Activity.
If it happens on emulator, then it's OK - emulator behaves a little bit weird in sense of configuration changes. I have been trying to solve similar problem, unless I noticed that the app worked fine on a real device.
It seems that the emulator ignores the android:configChanges="orientation" attribute, but in a bit strange way: it does force the configuration change but doesn't call onConfigurationChanged(..) method every time it should be called.
I tried getOrientation() to get the orientation value but it always returns 0!
getOrientation() is deprecated but this is not neccesarily the root of your problem. It is true that you should use getRotation() instead of getOrientation() but you can only use it if you are targeting Android 2.2 (API Level 8) or higher. Some people and even Googlers sometimes seem to forget that.
As an example, on my HTC desire running Android 2.2. getOrientation() and getRotation() both report the same values:
0 (default, portrait),
1 (device 90 degree counterclockwise),
3 (device 90 degree clockwise)
It does not report when you put it "on its head" (rotate 180, that would be the value 2). This result is possibly device-specific.
First of all you should make clear if you use an emulator or a device. Do you know how to rotate the emulator? Then I would recommend to create a small test program with a onCreate() Method like this:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
WindowManager mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
Display mDisplay = mWindowManager.getDefaultDisplay();
Log.d("ORIENTATION_TEST", "getOrientation(): " + mDisplay.getOrientation());
}
Check if the screen of your your device has been locked in the device settings Settings > Display > Auto-Rotate Screen. If that checkbox is unchecked, Android will not report orientation changes to your Activity. To be clear: it will not restart the activity. In my case I get only 0, like you described.
You can check this from your program if you add these lines to onCreate()
int sysAutoRotate = 0;
try {
sysAutoRotate = Settings.System.getInt(getContentResolver(), Settings.System.ACCELEROMETER_ROTATION);
} catch (SettingNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.d("ORIENTATION_TEST", "Auto-rotate Screen from Device Settings:" + sysAutoRotate);
It will return 0 if Auto-Rotate is off and 1 if Auto-Rotate is on.
Another try. In your original program you might have set in manifest
android:screenOrientation="portrait"
Same effect, but this time for your activity only. If you made the small test program this possibilty would have been eliminated (that's why I recommend it).
Remark: Yes the whole orientation / rotation topic is an "interesting" topic indeed. Try things out, use Log.d(), experiment, learn.
If you want to know if the content currently displayed is in landscape mode or portrait (possibly completely independent of the phone's physical rotation) you can use:
getResources().getConfiguration().orientation
Developer Documentation
public int orientation
Since: API Level 1
Overall orientation of the screen. May be one of ORIENTATION_LANDSCAPE, ORIENTATION_PORTRAIT, or ORIENTATION_SQUARE.
getOrientation() is deprecated. Instead, try getRotation().
To avoid use of Deprecated methods use the Android Configuration class found here. It works since API lvl 1 and still works on the latest android devices. (Not deprecated).
As and example consider the following code snippet:
Configuration config = getResources().getConfiguration();
if (config.orientation == Configuration.ORIENTATION_PORTRAIT)
{
setContentView(R.layout.portraitStart);
}
else
{
setContentView(R.layout.landscapeStart);
}
Best of luck- hope this answer helps whoever runs into it.
You should use:
getResources().getConfiguration().orientation
It can be one of ORIENTATION_LANDSCAPE, ORIENTATION_PORTRAIT.
http://developer.android.com/reference/android/content/res/Configuration.html#orientation
/* First, get the Display from the WindowManager */
Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
/* Now we can retrieve all display-related infos */
int width = display.getWidth();
int height = display.getHeight();
int orientation = display.getOrientation();
I think you need to create two different layouts and inflate different layouts on different orientation. I am giving you a sample code which is working fine for me.
"context" you can pass from your activity in case of custom adapter.
If you are using custom adapter then you can try this code:
#Override
public View getView(final int position,
View convertView,
ViewGroup parent)
{
View rowView = convertView;
ViewHolder holder = null;
int i = context.getResources().getConfiguration().orientation;
if (rowView == null) {
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (i == Configuration.ORIENTATION_PORTRAIT) {
rowView = inflater.inflate(R.layout.protrait_layout, null, false);
} else {
rowView = inflater.inflate(R.layout.landscape_layout, null, false);
}
holder = new ViewHolder();
holder.button = (Button) rowView.findViewById(R.id.button1);
rowView.setTag(holder);
} else {
holder = (ViewHolder) rowView.getTag();
}
return rowView;
}
other wise you can directly set two different layouts in your code
int i = context.getResources().getConfiguration().orientation;
if (i == Configuration.ORIENTATION_PORTRAIT) {
ArrayAdapter<String> adt = new ArrayAdapter<String>(getApplicationContext(), R.layout.protrait_layout, name);
} else {
ArrayAdapter<String> adt = new ArrayAdapter<String>(getApplicationContext(), R.layout.landscape_layout, name);
}
I had the same problem on NexusOne SDK 2.3.
This solved it: Check orientation on Android phone.