how to change layout at runtime? - android

I have a linear layout wrapping a button, a gridview and a textview set in a xml file. When the screen is in portrait orientation all these elements are displayed fine. However, when I change the orientation of the screen into landscape orientation the textview disappears. I'd like to change the layout on configuration change. I'd like to display the elements horizontally in a way that each of them takes up a certain percentage of the screen. I also have to change the number of items shown per row in the gridview, and maybe some others parameters. Until now I have this, but i don't know how to change the rest of the parameters.
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
LinearLayout linearlayout= (LinearLayout) findViewById(R.id.LinearLayout02);
GridView gridview=(GridView) findViewById(R.id.gridview);
if(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE){
linearlayout.setOrientation(LinearLayout.HORIZONTAL);
}
else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
linearlayout.setOrientation(LinearLayout.VERTICAL);
}
}

You'll want to create a folder in your /res/ directory that is titled layout-land and then create a new layout xml in that folder that is the same name as your other layout and place the items (TextView, etc.) where you would like them when the device is in landscape and from there Android will take care of the rest.
Edit: Use the following code:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
setContentView(R.layout.my_main_layout);
//save your text from textviews, edittexts, etc. in temp variables
InitializeUI(); //take your findViewById stuff out of onCreate and put it in its own method that can be called here as well.
//set you textviews, etc back to previous values from temp vars
}
That should do it.

Related

Android onConfigurationChanged new layout not updated

I need to replace my layout on orientation change and keep my views state and listeners (ex. in portrait mode I change a TextView color from blue to red and when I rotate the device the new layout with the same TextView needs to be red). I have 2 layouts: one in layout/ and one in layout-land/ and I added in AndroidManifest.xml this: android:configChanges="orientation|keyboardHidden|screenSize"
and this is my onConfigurationChanged
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDisplayWidth = Helper.getDisplayWidth(context);
mDisplayHeight = Helper.getDisplayHeight(context);
mDisplayOrientation = getResources().getConfiguration().orientation;
if(mDisplayOrientation == Configuration.ORIENTATION_LANDSCAPE){
//landscape
}else{
//portret
}
final View newView = View.inflate(getActivity(), R.layout.harta, null);
ViewGroup rootView = (ViewGroup) getView();
rootView.removeAllViews();
rootView.addView(newView);
}
The problem is that the new layout doesn't keep the old state and listeners, how can I achieve this?
Delete android:configChanges="orientation|keyboardHidden|screenSize" from manifest. Else onConfigurationChanged() doesn't cause;

How can I recreate toolbar when rotation occurs

Reading this so question one can see that toolbar uses different heights on landscape vs portrait mode.
But when android:configChanges="orientation|screenSize" is specified, toolbar height remains static according to the orientation in which the activity was first created and won't change when rotating the device.
How can I work this around? I'm thinking that either I should resize the toolbar inside onConfigurationChanged() method or I should destroy and recreate the toolbar and let it get its default height from scratch. I actually like this 2nd way better but I don't know how to do any of these so any suggestions are welcome.
to get rotation event:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
}
to resize layout:
First you have to declare the layout u wanna resize:
RelativeLayout rl = (RelativeLayout) findViewById(R.id.yourId);
And resize:
rl.getLayoutParams().height = 100; // replace 100 with your dimensions
rl.getLayoutParams().width = 100;

Android: Can I set converted view layout in getView()

I'm setting different height for my custom listview items based on screen orientation, and as in code below I listen to screen orientation changes, and set a global value according to it, and when getView(...) gets called on listview items I set the height of the converted view.
My question is, is there a better solution than this?
How bad this approach affect the UI loading speed process?
I'm targeting API14+
P.S: (200 & 300) below are added here as example, they are not fixed at runtime, they are changed during runtime according to screen dpi.
int mConvertViewHeight;
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
{
mConvertViewHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 200, getResources().getDisplayMetrics());
}
else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT)
{
mConvertViewHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 300, getResources().getDisplayMetrics());
}
}
In my listview custom array adapter
#Override
public View getView(final int aConvertViewPosition, View aConvertView, ViewGroup parent)
{
mParams = aConvertView.getLayoutParams();
mParams.height = mMainActivity.mConvertViewHeight;
}
If you need just different item view in portrait/landscape mode, you can create different layouts in layout-land and layout-port folders

Android View width and height have not changed after rotation

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.

replace layout on orientation change

My app has a webview and some buttons inside a LinerLayout.
the problem is, I want the buttons to be on bottom in portrait mode and on left in landscape mode while the webview maintains it's state.
Two different layout doesn't work as it force recreation of the activity that refresh the webview. for now I use android:configChanges="orientation" in activity tag so webview doesn't get refreshed on orientation change.
Is there anyway to replace the layout of buttons on the change of screen mode?
portrait mode
landscape mode
I tested fragments, but dealing with fragment makes things much more complex and the fragment itself needs saving and restoring which may not work in a webview which has javascript state, So I searched more and find a nice article somewhere and with some modification I came to a solution which I suggest:
First, add android:configChanges="orientation|screenSize|keyboard|keyboardHidden" so the app handles the config changes instead of android.
Make two different layout for landscape and portrait. In both layouts instead of webview place a FrameLayout which acts as a placeholder for the webview.
Define initUI method like this and put everything related to UI initialization in this method:
public void initui()
{
setContentView(R.layout.main);
if (wv == null) wv = new WebView(this);
((LinearLayout)findViewById(R.id.webviewPlace)).addView(wv);
findViewById(R.id.home).setOnClickListener(this);
}
If the webview doesn't exist yet it will be created and after setContentView(R.layout.main) it will be added to the layout. Any other UI customization you need came after this.
and in onConfigurationChanged:
#Override
public void onConfigurationChanged(Configuration newConfig)
{
((LinearLayout)findViewById(R.id.webviewPlace)).removeAllViews();
super.onConfigurationChanged(newConfig);
initUI();
}
In onConfigChange the webview is removed from old placeholder and initui will be called which will add it back to the new layout.
In oncreate() call initui() so the ui will be initialized for the first time.
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
initUI()
}
I wish it would be helpful for someone.
If you are using android:configChanges="orientation|screenSize"
In manifest,it ignores the XML in "layout-land". If you create a different XML for landscape don't use the android:configChanges="orientation|screenSize" tag for that activity in manifest.
put that at layout-land for the layouts you want as landscape.
The idea is, you shouldn't really use configChange="orientation" because it has its downsides. You can find a detailed post here . You should manually handle your state if you want to change your layout. Of course you can programmaiclly do this but if you want to use xml to do this. You can maintain you webView with fragments.
Try to use this code:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
setContentView(R.layout.activity_splash);
}
Make your view a relative layout. When the orientation changes just adjust the layout params for each view in code.
Have your buttons be contained in a linear layout
As in..
Portrait
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
lp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
buttonLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
buttonLinearLayout.setLayoutParams(lp);
LayoutParams webParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
lp.addRule(RelativeLayout.ABOVE, R.id.buttons);
webView.setLayoutParams(webParams);
Landscape
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
buttonLinearLayout.setOrientation(LinearLayout.VERTICAL);
buttonLinearLayout.setLayoutParams(lp);
LayoutParams webParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
lp.addRule(RelativeLayout.TO_RIGHT_OF, R.id.buttons);
webView.setLayoutParams(webParams);
Make sure the LayoutParams you are using are the RelativeLayout params (always use the Layoutparams of the view's parent)
Add in the manifest
<activity android:name=".MyActivity"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
android:label="#string/app_name">
and
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Resources.getSystem().getDisplayMetrics().widthPixels>
Resources.getSystem().getDisplayMetrics().heightPixels)
setContentView(R.layout.activity_layout1);
else setContentView(R.layout.activity_layout2);
...
}
and
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
setContentView(R.layout.activity_layout1);
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
setContentView(R.layout.activity_layout2);
}
}
Documents here:
https://developer.android.com/guide/topics/resources/runtime-changes.html
You can add values-(configuration that you require - eg. land,portrait) folder under resources and mention the layout you need for this configuration.. It's as simple as that.
Please checkout the below link for further information-
http://developer.android.com/training/multiscreen/screensizes.html#TaskUseAliasFilters

Categories

Resources