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

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

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;

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.

Android GridVIew Change number of columns depending on Orientation

I want to display 6 images in the form of grid as follows.
in portrait orientation,2 coumns, 3 rows and
in landscare orientation 3 columns, 2 rows
By using Android GridView and by defining different grid layouts in layout-port and layout-land directories I was able to achieve this effect.
Later as per my activity requirement, I added one parameter in manifest.xml that is
android:configChanges = "mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|fontScale|screenSize"`
to stop my activity to recreate once screen orientation changes.
After adding this parameter, my grid view is not behaving in expected way. It sometimes shows 1 column, sometimes 2 columns, and sometimes 3 columns.
I am placing gridView.setNumberOfColumns(2) or gridView.setNumberOfColumns(3) methods in the get view method of my grid adapter depending on orientation of the device.
Please help me to achieve this effect without removing the android:configChanges parameter in Manifest.xml
Use the powerful resource system.
In the xml layout, set the number of columns to a integer resource and then in /values/integers.xml set it to 2 for portrait and in /values-land/integers.xml set it to 3 for landscape
// well, if you do configChanges in manifest, you will have to change column count from java in onConfogurationChanged
#Override
public void onConfigurationChanged(Configuration newConfig) {
grid.setNumColumns(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE ? 3 : 2);
super.onConfigurationChanged(newConfig);
}
you can set number of columns programatically using
float scalefactor = getResources().getDisplayMetrics().density * 100;
int number = getWindowManager().getDefaultDisplay().getWidth();
int columns = (int) ((float) number / (float) scalefactor);
gridView.setNumColumns(columns);
My solution:
values/dimens.xml:
<resources>
<dimen name="grip_view_entry_size">160dp</dimen>
<dimen name="grip_view_spacing">10dp</dimen>
</resources>
layout/gridview.xml
<GridView android:id="#+id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:numColumns="auto_fit"
android:verticalSpacing="#dimen/grip_view_spacing"
android:horizontalSpacing="#dimen/grip_view_spacing"
android:stretchMode="columnWidth"
android:gravity="center"
android:scrollingCache="false"
android:fastScrollEnabled="true"
android:animationCache="false"/>
in your fragment:
private void refreshGridView() {
int gridViewEntrySize = getResources().getDimensionPixelSize(R.dimen.grip_view_entry_size);
int gridViewSpacing = getResources().getDimensionPixelSize(R.dimen.grip_view_spacing);
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
int numColumns = (display.getWidth() - gridViewSpacing) / (gridViewEntrySize + gridViewSpacing);
gridView.setNumColumns(numColumns);
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
refreshGridView();
}
#Override
public void onResume() {
super.onResume();
refreshGridView();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
setContentView(R.layout.lay_vertical);
} else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
setContentView(R.layout.lay_horizontal);
}
};
Then load the data in gridview again according to your need.
Put android:configChanges="orientation" for that activity node in the manifest.
While you use android:configChanges = "orientation" in manifest your activity does not recreate on orientation changed (Landscape to Portrait or vice versa). If you don't want to remove this tag from manifest you must have to override onConfigchanged and put some code logic there.
i made it based by screen size, not dpi
public static int getGridColumnsCount(Context context){
boolean landscape = context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
float hi=displayMetrics.heightPixels/displayMetrics.xdpi;
float wi=displayMetrics.widthPixels/displayMetrics.ydpi;
float screenWidthInch = landscape ? Math.max(wi, hi) : Math.min(wi, hi);
float screenWidthCm = screenWidthInch * 2.54f;
int columns = (int)(screenWidthCm/2);
return columns < 3 ? 3 : columns;
}
Here's the XML:
<GridLayout
android:id="#+id/gridLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnCount="#integer/num_columns"
android:rowCount="#integer/num_rows"
android:orientation="vertical">
<!-- TextViews, ImageViews, etc -->
</GridLayout>
And then inside your fragment:
#BindView(R.id.gridLayout) GridLayout gridLayout;
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
final ArrayList<View> views = new ArrayList<>();
for (int i = 0; i < gridLayout.getChildCount(); i++) {
views.add(gridLayout.getChildAt(i));
}
gridLayout.removeAllViews();
gridLayout.setColumnCount(getContext().getResources().getInteger(R.integer.num_columns));
gridLayout.setRowCount(getContext().getResources().getInteger(R.integer.num_rows));
for (int i = 0; i < views.size(); i++) {
views.get(i).setLayoutParams(new GridLayout.LayoutParams());
gridLayout.addView(views.get(i));
}
}
add this code to onCreate
gridView_menu.setNumColumns(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT ? 3:4);

GridView getMeauredHeight() or getHeight() gives 0

I want to make number of rows in Gridview dynamic depending upon the screen size of the android phone. so i need height of the Gridview in onCreate() to count number of rows.(height / colums) here is a code snippet::
public class GridActivity extends Activity
{
GridView gridView;
GridAdapter adapter;'
public void onCreate(Bundle savedInstance state)
{
setContentView(R.layout.gridview);
gridView = (GridView) findViewById(R.id.grid);
adapter = new GridAdapter(this);
gridView.setAdapter(adapter);
int gridHeight = gridView.getMeasuredHeight();
Log.d("tag"," height :: " + gridHeight);
}
}
In log cat it shows -- height :: 0
I don't understand y it gives zero after properly inflating.
Is this a bug? Or I am missing something?
GridView would return 0 measuredheight and 0 height unless it is drawn to window, so you can not get height of GridVIew at the point, A workaround of your problem may be:
Add your Nth view to gridView by comparing total height of device with height of GridView occupied after n-1 views has been drawn to screen.
public void addNCompareHeight(View view)
{
ViewTreeObserver observer = grid.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
//in here, place the code that requires you to know the dimensions.
//this will be called as the layout is finished, prior to displaying.
if(gridHeight<requiredHeight)
{
grid.addView(view);
addNCompareHeight(next);
}
}
}
I am not sure how you are going to relate your mobile screen size and GridView heigth. But here are the codes for finding out Screen resolution and GridView height.
1)To Find screen resolution do this in your onCreate(),
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int screen_width = dm.widthPixels;
int screen_height = dm.heightPixels;
2)To find gridView height you can use the below method,
#Override
public void onWindowFocusChanged(boolean hasFocus)
{
// TODO Auto-generated method stub
super.onWindowFocusChanged(hasFocus);
System.out.println("...111Height..."+gridview.getMeasuredWidth());
}

Different size images for different orientations

In my application, whenever the orientation of my screen changes, I want to display different images that will fit the screen. How can I do that?
Implement the method onConfigurationChanged in your Activity, there you can check the orientation and change the UI's look.
The parameter: newConfig.orientation will tell you the current orientation.
Try something like:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
ImageView header = (ImageView) this.findViewById(R.id.header);
if ( newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE ) {
header.setImageResource(R.drawable.header480);
}
else if ( newConfig.orientation == Configuration.ORIENTATION_PORTRAIT ) {
header.setImageResource(R.drawable.header320);
}
}
You can also use this kind of code to actually get the screen size in real time:
Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int width = display.getWidth();
...

Categories

Resources