GridView focus handling on changing screen orientation

Put problem concerning Views, Layouts and other XML-Resources (like AndroidManifest) here.

GridView focus handling on changing screen orientation

Postby satishkumar_lskin » Sun May 03, 2009 11:01 am

Hi all ,
Iam using Android SDK 1.0 r 2. I have a problem in GridView focus handling on changing screen orientation. The GridView that I use has two types of child views - one type representing a button and another type ,an imageView that represents space-filler . Say for example, in a GridView with total child count = 9 , the positions 1, 3,4, 5, 7 contain buttons that are clickable , the remaining positions 0, 2,6, 8 contain imageViews that represent space-fillers.
When the GridView is rendered , I use requestFocus() to set focus to the first of the clickable buttons. The problem is when i change the screen orientation to landscape , the focus shifts to the imageView that is a space-filler. This is highly undesirable for me because the user should not be even aware that there is a space-filler being used. On using log statements, I find that the focus always shifts to the first child view of the GridView on changing orientation. Since the data and the child views for the GridView come from an Adapter class , handling GridView focus on orientation-change has been an intricate task for me.
I want to ensure that on orientation-change , the focus always shifts to the first of the clickable buttons. How can i acheive this ? Can anybody help ? (By the way , I override onConfigurationChanged() for orientation-change and it works fine for all other views ).

Thanks,
Satish
satishkumar_lskin
Developer
Developer
 
Posts: 32
Joined: Mon Oct 20, 2008 8:15 am
Location: Coimbatore , TamilNadu, India

Top

Postby padde » Sun May 03, 2009 1:05 pm

At first i have to admit that i have no clue why you are using images as space-filler.. padding and margin should help avoid this.
But to fix the focus problem i would suggest you call requestFocus on the button again when the orientation changes.
Now it depends on your code.. if you watch configuration changes in your activity like this:
Syntax: [ Download ] [ Hide ]
Using xml Syntax Highlighting
  1.  
  2. android:configChanges="keyboardHidden|orientation"
  3.  
  4.  
Parsed in 0.000 seconds, using GeSHi 1.0.8.4

you have to add the requestFocus line in the onConfigurationChanged method.. if not your activity gets restarted on orientation change so the requestFocus line should be placed in onStart or onCreate.

Greets
Padde
padde
Master Developer
Master Developer
 
Posts: 443
Joined: Wed Apr 08, 2009 4:52 pm

Reply

Postby satishkumar_lskin » Mon May 04, 2009 1:32 pm

Hi padde,
Thanks for ur thoughts. The contents ( child views ) of my GridView are not static . The child views and their positions in the GridView are variable at run time. The child views may take different positions in the GridView at different times. Say for example, the GridView may have three rows and three columns and the child count may be five . In this case , the child views may be positioned such that they represent a "diamond" shape in a GridView. The remaining areas have to be filled with space-filler imageViews.
If I can use padding and margins for this case, then the logic becomes complex because for the "diamond" shaped layout , padding and margins will differ for each row. Also , for another layout where one row has two child views and another has three child views and another none, padding and margins will vary. That's why I use space-filler imageViews.
I had tried using requestFocus() in a similar manner u had mentioned but it doesn't work. The difficulty stems from the fact that on changing screen orientation , GridView tries to give focus to the first child View always ( which in my case is a space-filler) . An extra info is that I change the height of the GridView on changing screen orientation. The same kind of change is done for LinearLayout and it works fine because for such a layout , the views are added straight-forward using addView() unlike GridView that needs setAdapter() to get its child views.
Can urself and others shed light to overcome my problem ?
satishkumar_lskin
Developer
Developer
 
Posts: 32
Joined: Mon Oct 20, 2008 8:15 am
Location: Coimbatore , TamilNadu, India

Postby padde » Mon May 04, 2009 3:03 pm

In that case i would try to disable focus of the imageviews with setFocusable(false).
Or use a global int that represents the index of the childview that should gain focus
on orientation change and then use getChild(index) method from the gridview to get
the correct childview to set focus.

Greets
Padde
padde
Master Developer
Master Developer
 
Posts: 443
Joined: Wed Apr 08, 2009 4:52 pm

Reply

Postby satishkumar_lskin » Tue May 05, 2009 6:35 am

Hi ,
Thanks again for timely responses. I have already made my imageViews non-focusable . This is the code snippet :
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2.                                 imageView.setEnabled(false);
  3.  
  4.                                 imageView.setFocusable(false);
  5.  
  6.                                 imageView.setFocusableInTouchMode(false);
  7.  
  8.                                 imageView.setClickable(false);
Parsed in 0.031 seconds, using GeSHi 1.0.8.4


When the GridView gains focus, it always tries to give focus to the first of its child views. I have used this code-snippet :
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2.                         gridView.setFocusable(true);
  3.  
  4.                         gridView.setFocusableInTouchMode(true);
  5.  
  6.                         gridView                        .setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
Parsed in 0.031 seconds, using GeSHi 1.0.8.4


Regardless of this , if the first child is a space-filler and it always gains focus. So to overcome this , I use a method getFirstFocusableView() in my Adapter class to retrieve the first focusable view and give it the focus.
But on orientation-change , getView() method in Adapter class is called to render each child view of the GridView ( just like how a GridView is rendered for the first time when setAdapter() is invoked ) . Even if I try to give focus to the first focusable view by calling the corresponding method as the last statement in onConfigurationChanged(), that doesn't work. This is because getView() in Adapter class is invoked by GridView internally to render its child views at indeterminate times. This is my Adapter class :
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2. public class MyAdapter extends BaseAdapter {
  3.  
  4.  
  5.  
  6.         private List<View> views;
  7.  
  8.  
  9.  
  10.         public MyAdapter(List<View> views) {
  11.  
  12.                 super();
  13.  
  14.                 // TODO Auto-generated constructor stub
  15.  
  16.                 this.views = new ArrayList<View>(views);
  17.  
  18.         }
  19.  
  20.  
  21.  
  22.         public int getCount() {
  23.  
  24.                 // TODO Auto-generated method stub
  25.  
  26.                
  27.  
  28.                 return views.size();
  29.  
  30.         }
  31.  
  32.  
  33.  
  34.         public Object getItem(int position) {
  35.  
  36.                 // TODO Auto-generated method stub
  37.  
  38.                
  39.  
  40.                 return views.get(position);
  41.  
  42.         }
  43.  
  44.  
  45.  
  46.         public long getItemId(int position) {
  47.  
  48.                 // TODO Auto-generated method stub
  49.  
  50.                 return position;
  51.  
  52.         }
  53.  
  54.  
  55.  
  56.         public View getView(int position, View convertView, ViewGroup parent) {
  57.  
  58.                 // TODO Auto-generated method stub
  59.  
  60.                
  61.  
  62.                 return views.get(position);
  63.  
  64.         }
  65.  
  66.  
  67.  
  68.         public boolean areAllItemsEnabled() {
  69.  
  70.                 // TODO Auto-generated method stub
  71.  
  72.                
  73.  
  74.                 return false;
  75.  
  76.         }
  77.  
  78.  
  79.  
  80.         @Override
  81.  
  82.         public boolean isEnabled(int position) {
  83.  
  84.                 // TODO Auto-generated method stub
  85.  
  86.                 if (views.get(position) instanceof ImageButton) {
  87.  
  88.                        
  89.  
  90.                         return true;
  91.  
  92.                 }
  93.  
  94.                
  95.  
  96.                 return false;
  97.  
  98.         }
  99.  
  100.  
  101.  
  102.         @Override
  103.  
  104.         public int getViewTypeCount() {
  105.  
  106.                 // TODO Auto-generated method stub
  107.  
  108.                
  109.  
  110.                 return 2;
  111.  
  112.         }
  113.  
  114.  
  115.  
  116.         public List<View> getViews() {
  117.  
  118.                 return views;
  119.  
  120.         }
  121.  
  122.  
  123.  
  124.        
  125.  
  126.  
  127.  
  128.         public View getFirstFocusableView() {
  129.  
  130.                 // TODO Auto-generated method stub
  131.  
  132.                 for (View v : views) {
  133.  
  134.                         if (v.isEnabled() && v.isFocusable() && v.isClickable()
  135.  
  136.                                         && v instanceof ImageButton) {
  137.  
  138.                                 return v;
  139.  
  140.                         }
  141.  
  142.                 }
  143.  
  144.                 return null;
  145.  
  146.         }
  147.  
  148.  
  149.  
  150. }
Parsed in 0.040 seconds, using GeSHi 1.0.8.4


Can u give me some internals on how GridView uses setAdapter() to render its child views or is there any other method to solve my problem ?

Thanks
Satish
satishkumar_lskin
Developer
Developer
 
Posts: 32
Joined: Mon Oct 20, 2008 8:15 am
Location: Coimbatore , TamilNadu, India

Help

Postby satishkumar_lskin » Wed May 06, 2009 8:01 am

Can anybody help me out on this issue ?

Thanks
Satish
satishkumar_lskin
Developer
Developer
 
Posts: 32
Joined: Mon Oct 20, 2008 8:15 am
Location: Coimbatore , TamilNadu, India

Top

Help please

Postby satishkumar_lskin » Mon May 11, 2009 1:28 pm

Hi All,
Can anybody help me on this problem ? Is there any other method to handling focus of GridView such as setSelection() ? I doubt if a method like setSelection() would meet my requirement. :cry:
Experts here, please help me. Iam going :x
Thanks
Satish
satishkumar_lskin
Developer
Developer
 
Posts: 32
Joined: Mon Oct 20, 2008 8:15 am
Location: Coimbatore , TamilNadu, India

Solved

Postby satishkumar_lskin » Sat May 30, 2009 1:30 pm

Hi all,
The problem is solved. On orientation change , after changing the layout params (width and height ) of the GridView , use
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. setSelection(index);
Parsed in 0.035 seconds, using GeSHi 1.0.8.4


Here index is the position of the item in the GridView that needs to be focused.
Here is the additional method that I have added in the Adapter class to get the first focusable view position.

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. public int getFirstFocusableViewPosition() {
  2.  
  3.                 // TODO Auto-generated method stub
  4.  
  5.                 for (int i = 0 ; i< views.size() ; i++) {
  6.  
  7.                         View v = views.get(i);
  8.  
  9.                         if (v.isEnabled() && v.isFocusable() && v.isClickable()
  10.  
  11.                                         && v instanceof ImageButton) {
  12.  
  13.                                 return i;
  14.  
  15.                         }
  16.  
  17.                 }
  18.  
  19.                 return 0;
  20.  
  21.         }
Parsed in 0.037 seconds, using GeSHi 1.0.8.4


Then in my overridden onConfigurationChanged() method , I have used setSelection() as follows:

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. public void onConfigurationChanged(Configuration newConfig) {
  2.  
  3.                 // TODO Auto-generated method stub
  4.  
  5.                 super.onConfigurationChanged(newConfig);
  6.  
  7.               //Change the width and height of GridView.
  8.  
  9.                ................................................
  10.  
  11.               ..................................................
  12.  
  13.             //If needed, use gridView.setAdapter(myAdapter) ; here again.
  14.  
  15.  
  16.  
  17.             int position = myAdapter.getFirstFocusableViewPosition() ;
  18.  
  19.             gridView.setSelection(position);
  20.  
  21. }
Parsed in 0.037 seconds, using GeSHi 1.0.8.4


I hope that this solution helps every one in need. Thanks to padde and others who helped.

Regards,
Satish.
satishkumar_lskin
Developer
Developer
 
Posts: 32
Joined: Mon Oct 20, 2008 8:15 am
Location: Coimbatore , TamilNadu, India

Top

Return to View, Layout & Resource Problems

Who is online

Users browsing this forum: Exabot [Bot] and 4 guests