Android: alternate layout xml for landscape mode

Android: alternate layout xml for landscape mode

Ganesh Quique Author: Ganesh Quique Date: 2022-08-16
Android: alternate layout xml for landscape mode

All you need to know about Android: alternate layout xml for landscape mode , in addintion to Android: xml layout for a listview with different items , xml - android: Which practice is better for using CoordinatorLayout , Eclipse Not Showing Graphical Layout for Android XML files , android - Use XML Layout as view for View Subclass?

  1. Android: alternate layout xml for landscape mode
  2. Question:

    How can I have one layout for landscape and one for portrait? I want to assume extra width and conserve vertical space when the user rotates the phone over sideways.


    Solution 1:

    By default, the layouts in /res/layout are applied to both portrait and landscape.

    If you have for example

    /res/layout/main.xml
    

    you can add a new folder /res/layout-land, copy main.xml into it and make the needed adjustments.

    orientation

    See also http://www.androidpeople.com/android-portrait-amp-landscape-differeent-layouts and http://www.devx.com/wireless/Article/40792/1954 for some more options.

    Solution 2:

    In the current version of Android Studio (v1.0.2) you can simply add a landscape layout by clicking on the button in the visual editor shown in the screenshot below. Select "Create Landscape Variation"

    Android Studio add landscape layout

    Solution 3:

    The layouts in /res/layout are applied to both portrait and landscape, unless you specify otherwise. Let’s assume we have /res/layout/home.xml for our homepage and we want it to look differently in the 2 layout types.

    1. create folder /res/layout-land (here you will keep your landscape adjusted layouts)
    2. copy home.xml there
    3. make necessary changes to it

    Source

  3. Android: xml layout for a listview with different items
  4. Question:

    I'm reading this tutorial http://android.amberfog.com/?p=296 . I'd like to create a Listview weith different types of rows. I understand how to create the adapter, but what about the xml layout? So I definire an xml layout like this one:

    <ListView/>
    
    <TextView android:id="@+id/id1" />
    
    <TextView android:id="@+id/id2" />
    
    <ImageView android:id="@+id/id3" />
    
    <TextView android:id="@+id/id4" />
    

    Will it be a problem (for performance) if maybe one row uses just some elements (only some textviews) of the layout and another row maybe uses other elements? I don't understand if mine is the right way to define the xml or if I have to create different layout for each type of row.

    Thank you in advance

    EDIT: now I'm having a null point exception.

    java code from the adapter:

    @Override
    
    public View getView(int position, View convertView, ViewGroup parent) {
    
    ViewHolder holder = null;
    int type = getItemViewType(position);
    
    if (convertView == null) {
        holder = new ViewHolder();
    
        convertView = mInflater.inflate(R.layout.listview_main, null);
        holder.textView_title = (TextView)convertView.findViewById(R.id.listview1);
    
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder)convertView.getTag();
    }
    
    **holder.textView_title.setText("aaaa");** //NULL POINT EXCEPTION HERE
    
    return convertView;
    

    }

    class ViewHolder {
        public TextView textView_title;
    }
    

    xml 1:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:id="@+id/main_layout"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:orientation="vertical"
                  android:gravity="left"
                  android:layout_margin="0dp">
    
        <!-- android:background="#0094ff" -->
    
        <ListView
                android:id="@id/android:list"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:fastScrollEnabled="true"
                android:scrollbarStyle="insideInset"
                android:textFilterEnabled="false"
                android:divider="@null"
                android:layout_margin="0dp"
                android:paddingTop="0dp"
                android:paddingBottom="0dp"
                android:paddingLeft="15dp"
                android:paddingRight="22dp"/>
    
    
    
    </LinearLayout>
    

    xml2

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:gravity="left"
        android:layout_margin="0dp">
    
        <TextView
            android:id="@+id/listview1"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:paddingTop="7dp"
            android:paddingBottom="0dp"
            android:paddingLeft="0dp"
            android:paddingRight="0dp"
            android:textSize="18sp"
            android:textColor="#000000"
            android:lines="1">
        </TextView>
    
    </LinearLayout>
    


    Solution 1:

    You need to override getViewItemType and getViewTypeCount. You will also need to have custom layouts.

    getItemViewType(int position) - returns information which layout type you should use based on position.

    You should have a look at the video in the link.

    http://www.youtube.com/watch?v=wDBM6wVEO70

    private static final int TYPE_ITEM1 = 0;
    private static final int TYPE_ITEM2 = 1;
    private static final int TYPE_ITEM3 = 2; 
    

    Then

    int type;
    @Override
    public int getItemViewType(int position) {
    
        if (position== 0){
            type = TYPE_ITEM1;
        } else if  (position == 1){
            type = TYPE_ITEM2;
        }
        else
        {
             type= TYPE_ITEM3 ;
        }
        return type;
    }
    
     @Override
     public int getViewTypeCount() {
            return 3; 
     }
    @Override  
    public View getView(int position, View convertView, ViewGroup parent) {
    View row = convertView;
    LayoutInflater inflater = null;
    int type = getItemViewType(position);
      // instead of if else you can use a case
       if (row  == null) {
        if (type == FIRST_TYPE) {
                //infalte layout of type1
          }
        if (type == SECOND_TYPE) {
                //infalte layout of type2
        }  else {
                //infalte layout of normaltype
     }
    } 
    

    Solution 2:

    • I have just solved this problem of creating different layouts for different rows.
      1. Define all the different layouts in their corresponding different xml files.
      2. Override getViewTypeCount() method and return number of defined layouts from this.
      3. Override getItemViewType() method and according to the relation between the 'position' of the element in the listview and the proposed xml layout define the condition and return the appropriate integer values.
      4. By calling the getItemViewType() method in the getView() method, we can get the number corresponding to layout, then inflate the convertView with the corresponding xml layout. And then by using findViewById(), you can get the values into objects of the TextView class defined in ViewHolder class and setText or whatever operation you want to use you can do further. As simple as it is. Suppose we have 4 types of layouts and 4 xml files named as element1, element2, element3, element4 and two common textview id as text1, text2.

    @Override public int getItemViewType(int position) { if (position % 4 == 0) { return 0; } else if (position % 4 == 1) { return 1; } else if (position % 4 == 2) { return 2; } return 3; }

        public View getView(int position, View convertView, ViewGroup parent) {
    
        ViewHolder holder = null;
    
        int type = getItemViewType(position);
        if (convertView == null) {
            switch (type) {
            case 0: {
                convertView = mInflater.inflate(R.layout.element1, null);
                break;
            }
            case 1: {
                convertView = mInflater.inflate(R.layout.element2, null);
                break;
            }
            case 2: {
                convertView = mInflater.inflate(R.layout.element3, null);
                break;
            }
            case 3: {
                convertView = mInflater.inflate(R.layout.element4, null);
                break;
            }
            }
            holder = new ViewHolder();
            holder.txt1 = (TextView) convertView.findViewById(R.id.text1);
            holder.txt2 = (TextView) convertView.findViewById(R.id.text2);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        String rowItem = null;
        rowItem = rowItems[position];
        holder.txt1.setText(rowItem);
        rowItem = rowItems[position+1];
        holder.txt1.setText(rowItem);
        return convertView;
    }
    
    
    
    private class ViewHolder {
        TextView txt1, txt2;
    }
    

    Solution 3:

    This might be a wrong method to do it. If you have only one component in the ListView then use simple adapter else use custom adapter with separate XML for the list row.

    Sample code:

    @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.listhistory);
            initcomponents();
    
            ArrayList<HashMap<String, String>> alist = new ArrayList<HashMap<String, String>>();
    
            for (int i = 1; i < 20; i++) {
                HashMap<String, String> hmap = new HashMap<String, String>();
                hmap.put("date", "" + i + "/13");
                hmap.put("restaurant", "Restaurant" + i);
                hmap.put("distance", "" + (i * 100) + "kms");
                alist.add(hmap);
    
            }
    
            final CustomListAdapter adapter = new CustomListAdapter(this,
                    R.layout.listitemhistory, alist);
    
            list.setAdapter(adapter);
    
        }
    
        private void initcomponents() {
            list = (ListView) findViewById(R.id.history_lst_list);
    
        }
    
        public void backButtonClick(View v) {
            finish();
        }
    
        class CustomListAdapter extends ArrayAdapter<HashMap<String, String>> {
            Context context;
            int textViewResourceId;
            ArrayList<HashMap<String, String>> alist;
    
            public CustomListAdapter(Context context, int textViewResourceId,
                    ArrayList<HashMap<String, String>> alist) {
                super(context, textViewResourceId);
                this.context = context;
                this.alist = alist;
                this.textViewResourceId = textViewResourceId;
    
            }
    
            public int getCount() {
    
                return alist.size();
            }
    
            public View getView(int pos, View convertView, ViewGroup parent) {
                Holder holder = null;
    
                    LayoutInflater inflater = ((Activity) context)
                            .getLayoutInflater();
                    convertView = inflater.inflate(R.layout.listitemhistory,
                            parent, false);
                    holder = new Holder();
                    holder.date = (TextView) convertView
                            .findViewById(R.id.listitemhistory_txt_date);
                    holder.restaurant = (TextView) convertView
                            .findViewById(R.id.listitemhistory_txt_restaurant);
                    holder.distance = (TextView) convertView
                            .findViewById(R.id.listitemhistory_txt_distance);
                    holder.lin_background = (LinearLayout) convertView
                            .findViewById(R.id.history_lin_background);
                    convertView.setTag(holder);
    
    
    
                holder = (Holder) convertView.getTag();
    
                holder.date.setText(alist.get(pos).get("date"));
                holder.restaurant.setText(alist.get(pos).get("restaurant"));
                holder.distance.setText(alist.get(pos).get("distance"));
    
                return convertView;
    
            }
    
            class Holder {
                TextView date, restaurant, distance;
                LinearLayout lin_background;
            }
        }
    

  5. xml - android: Which practice is better for using CoordinatorLayout
  6. Question:

    I am new to material design aspect of android. So, please bear with me. I tried implementing the FAB for my home activity, and then implemented the snackbar. Naturally, it came above my FAB. I researched on CoordinatorLayout and what's bothering me is which one is a better practice for using a CoordinatorLayout?

    For example, here's the xml of my activity.

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@color/primary_color"></android.support.v7.widget.Toolbar>
    
    
            <android.support.design.widget.FloatingActionButton
                android:id="@+id/searchfab"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_alignParentBottom="true"
                android:layout_marginBottom="20dp"
                android:layout_marginRight="20dp"
                android:src="@drawable/ic_add_black_24dp"
                app:fabSize="normal">
    
            </android.support.design.widget.FloatingActionButton>
    
    </RelativeLayout>
    

    I watched other people adding CoordinatorLayout like this.

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
    
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/primary_color"></android.support.v7.widget.Toolbar>
    
        <android.support.design.widget.CoordinatorLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <android.support.design.widget.FloatingActionButton
                android:id="@+id/searchfab"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentBottom="true"
                android:layout_alignParentRight="true"
                android:layout_marginBottom="20dp"
                android:layout_marginRight="20dp"
                android:src="@drawable/ic_add_black_24dp"
                app:fabSize="normal">
    
            </android.support.design.widget.FloatingActionButton>
    
        </android.support.design.widget.CoordinatorLayout>
    </RelativeLayout>
    

    My question is, can we use <android.support.design.widget.CoordinatorLayout> as the root of all elements. Completely bypassing or removing the <RelativeLayout>.

    So the xml becomes like this.

        <android.support.design.widget.CoordinatorLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".MainActivity">
    
            <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/primary_color">
    
            <android.support.design.widget.FloatingActionButton
                android:id="@+id/searchfab"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentBottom="true"
                android:layout_alignParentRight="true"
                android:layout_marginBottom="20dp"
                android:layout_marginRight="20dp"
                android:src="@drawable/ic_add_black_24dp"
                app:fabSize="normal">
    
            </android.support.design.widget.FloatingActionButton>
    
        </android.support.design.widget.CoordinatorLayout>
    

    and the <RelativeLayout> is completely removed. So instead of using </android.support.design.widget.CoordinatorLayout> just for FAB, we use it for the whole activity. As CoordinatorLayout focuses on making child views work coordinated, isn't it better if all elements work in coordination with one another? What are the advantages and disadvantages of doing it either ways?


    Solution 1:

    CoordinatorLayout is relatively new and it resolves a lot of issues with FloatingActionButton and NavDrawer. So if you must have FAB or NavDrawer I would definitely recommend using CoordinatorLayout as your top level layout from now on (your last code snippet) and inside it you can have RelativeLayout or LinearLayout for more refinement.

  7. Eclipse Not Showing Graphical Layout for Android XML files
  8. Question:

    I had a HD hardware failure the otherday and have been trying to recreate my Android programming environment.

    I have installed Eclipse and the Android SDK. I have updated the SDK to the latest version.

    I then imported my project from my backup folder. When I look at my layout files in eclipse I cannot view the Grphical.layout as its not an option. I get the following tab options for the page (Design or Source).

    However my old environmet which i have a copy of in a virtual machine gives me following tab options for the layout file (Graphical Layout or filename.xml)

    Any ideas why this is occuring? I assume it must be something to do with eclipse not realising that its menat to be looking at android xml layout files.

    Please help,

    Iain


    Solution 1:

    comic if graphical layout is not showing by opening the xml file try using OpenWith ->Layout Editor on the xml file witch u want to open from project explorer under res folder

    Solution 2:

    If the above answer doesn't work and if you cannot see the option of 'Layout Editor' on right click, restart eclipse. Worked for me.

    Solution 3:

    sometime graphical layout show.but nothing showing.only blank.this is happen because the manifest minimum sdk is not support to view the layout.to resolve that change the api level which display in the right corner of layout display area.

  9. android - Use XML Layout as view for View Subclass?
  10. Question:

    I feel as though I used to know how to do this, but I'm currently drawing a blank. I have a class that extends from View (Card) and I wrote a layout for it in XML. What I want to do is set the View of Card to be the XML View in the constructor, so I can use the methods in Card to set TextViews and whatnot. Any suggestions? Code below:

    Card.java: (I have View.inflate(context, R.layout.card_layout, null); there as an example of what I want to do, but it's not working. I basically want the class to be the interface for the View, and in order to do that I need to somehow assign the XML layout to the View. Do I use something along the lines of setContentView(View view)? There is no such method in the View class, but is there something like it?)

    public class Card extends View {
    
        TextView tv;
    
        public Card(Context context) {
            super(context);
            View.inflate(context, R.layout.card_layout, null);
            tv = (TextView) findViewById(R.id.tv);
        }
    
        public Card(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            View.inflate(context, R.layout.card_layout, null);
            tv = (TextView) findViewById(R.id.tv);
        }
    
        public Card(Context context, AttributeSet attrs) {
            super(context, attrs);
            View.inflate(context, R.layout.card_layout, null);
            tv = (TextView) findViewById(R.id.tv);
        }
    
        public void setText(String text) {
            tv.setText(text);
        }
    
    }
    

    card_layout.xml:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="336dp"
        android:layout_height="280dp"
        android:layout_gravity="center"
        android:background="@drawable/card_bg"
        android:orientation="vertical" >
    
    
        <TextView
            android:id="@+id/tv"
            android:layout_height="fill_parent"
            android:layout_width="wrap_content"
            android:textSize="24dp"
        />
    
    </LinearLayout>
    


    Solution 1:

    What you're trying to do is not possible with the current setup. A View(or a direct subclass of it) represent a single view it doesn't have the notion of child views, what you're trying to do. The LayoutInflater can't be used with a simple View because the simple View class doesn't have the methods to actually add the child to it(like the addView() method).

    On the other hand, the correct class to use to be able to have children is the ViewGroup(or one of the direct subclasses like LinearLayout, FrameLayout etc) which accept adding Views or other ViewGroups to it, by supplying the addView methods. In the end your class should be:

    public class Card extends ViewGroup {
    
        TextView tv;
    
        public Card(Context context) {
            super(context);
            View.inflate(context, R.layout.card_layout, this);
            tv = (TextView) findViewById(R.id.tv);
        }
    
        public Card(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            View.inflate(context, R.layout.card_layout, this);
            tv = (TextView) findViewById(R.id.tv);
        }
    
        public Card(Context context, AttributeSet attrs) {
            super(context, attrs);
            View.inflate(context, R.layout.card_layout, this);
            tv = (TextView) findViewById(R.id.tv);
        }
    
        public void setText(String text) {
            tv.setText(text);
        }
    
    }
    

    If I recall you have to override onLayout if you extend ViewGroup, so instead(and because of your layout file), you should look at extending LinearLayout and replace the LinearLayout from the xml layout with a merge tag.

    Solution 2:

    You should be able to use your class name in the layout. Something like:

    <your.package.name.Card 
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="336dp"
        android:layout_height="280dp"
        ...
    

    Just call findViewById to get child views.

    To use your Card class, you use the inflator to get an instance, then attach it to a parent view.

    LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
    Card card = (Card) inflater.inflate(R.layout.card_layout, null);
    parentView.addView(card);
    

    Have a look at the docs for more info.