Event handling for nesting ListView in ListView

Keywords: Android xml encoding Mobile

Thank you very much for the author of this post and the comment on the 15th floor, which finally solved my problem. Thank you for the long time that troubled me at https://my.oschina.net/zhibuji/blog/70892.

The day before yesterday, I met Item in ListView, which needed to display the processed content with ListView. Then I met a headache. As Item, ListView could not slide, and the display was not normal, just showing several sub-Items. The reason is that the size of the ListView should be calculated before the control is drawn. To solve the problem of displaying all the sub-ListViews, it is necessary to recalculate the size of the sub-ListView to inform the system. The latter problem is relatively easy to solve. Solutions have been given on the Internet:

The predecessors gave a method to recalculate the size of the sub-ListView, and then run the method after setting up the Adapter of this ListView. The specific code is as follows:

/** 

     * Set the height of Listview 

     */  

    public void setListViewHeight(ListView listView) {   

        ListAdapter listAdapter = listView.getAdapter();    

        if (listAdapter == null) {   

            return;   

        }   

        int totalHeight = 0;   

        for (int i = 0; i < listAdapter.getCount(); i++) {   

            View listItem = listAdapter.getView(i, null, listView);   

            listItem.measure(0, 0);   

            totalHeight += listItem.getMeasuredHeight();   

        }   

        ViewGroup.LayoutParams params = listView.getLayoutParams();   

        params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));   

        listView.setLayoutParams(params);  

    }

However, the Layout of item set by this method must be a control with onMeasure() method, otherwise it will be wrong when calculating. It is recommended to use LinearLayout.

Another idea is the same, but instead of doing extra things to implement the onMeasure() method to calculate the LIstView size, you inherit the ListView, rewrite the onMeasure() method of the ListView, calculate the height of the ListView yourself, and then use the custom ListView directly in xml.

public class MyListView extends ListView { 

    public  MyListView  (Context context, AttributeSet attrs) { 

        super(context, attrs); 

    } 

    public  MyListView  (Context context) { 

        super(context); 

    } 

    public  MyListView  (Context context, AttributeSet attrs, int defStyle) { 

        super(context, attrs, defStyle); 

    } 

    @Override 

    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 

        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, 

                MeasureSpec.AT_MOST); 

        super.onMeasure(widthMeasureSpec, expandSpec); 

    } 

}

This is a solution for displaying the entire content of ListView as Item, but sometimes we want ListView as Item to be able to slide instead of displaying it all. To solve this problem, we need to understand the distribution mechanism of android for events.

My solution is to integrate ListView, rewrite intercept TouchEvent and return it to false to cancel parent ListView's interception of touch events, and distribute touch events to child View for processing. Then, when you use it, use it as the parent ListView, so that the child ListView can slide. The idea comes from the 6th floor of the link below.

http://www.eoeandroid.com/thread-3597-1-1.html

Specifically customize the parent ListView code :

public class ParentListView extends ListView {

public ParentListView(Context context) {

super(context);

// TODO Auto-generated constructor stub

}

public ParentListView(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

// TODO Auto-generated constructor stub

}

public ParentListView(Context context, AttributeSet attrs) {

super(context, attrs);

// TODO Auto-generated constructor stub

}
//Set the return value of onInterceptTouchEvent to false, cancel its handling of touch events, and distribute events to child view s

@Override

public boolean onInterceptTouchEvent(MotionEvent ev) {

// TODO Auto-generated method stub

return false;

}

}

xml file:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
<!-- Do it here demo Use, use directly android Medium ListActivity-->
    <i.test.ParentListView android:id=" @android :id/list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:dividerHeight="2dip"
        android:scrollbars="none"
        />

</LinearLayout>

The activity code is as follows:
public class ListviewActivity extends ListActivity {
    /** Called when the activity is first created. */
private ListView mLv;//This ListView is a custom View
private ParentAdapter adapter;
private final static String[] array = new String[]{"1","2","3","4","5","6","7","8","9","10","11","12","13","14"};
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mLv = getListView();
        adapter = new ParentAdapter();
        mLv.setAdapter(adapter);
        
    }
    private class ParentAdapter extends BaseAdapter{

@Override
public int getCount() {
// TODO Auto-generated method stub
return Array.getLength(array);
}

@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return array[position];
}

@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View view;
if(position == 5){
view = View.inflate(getApplicationContext(), R.layout.item, null);
ListView lv = (ListView) view.findViewById(R.id.lv);
ArrayAdapter<String> mAdapter = new ArrayAdapter<String>(ListviewActivity.this, android.R.layout.simple_list_item_1, new String[]{"a","b",
"c","d","e","f","g"});
lv.setAdapter(mAdapter);
}
else{
TextView  tv = new TextView(getApplicationContext());
tv.setText(array[position]);
tv.setTextSize(30);
view = tv;
}
return view;
}
   
    }
}

The above method is also suitable for nesting slidable views in Scroll View.

Postscript: 2013.04.10
Today, when I log in to oschian, I see someone mention me. When I open the news, I am glad that what I write is helpful to others. Commentator@ jimmy.zhao Thank you for letting me know that I helped you, which is the driving force behind blogging.

This text is a problem that was solved the second day after I graduated. It has been two months since I came to work. After I came here, I filled in this pit. My predecessors said that all the solutions I found on the Internet were given by cowboys. That's all said, but no one said what the solution was, so let me study it. I can't say that this text is the first to solve this nested sliding problem, but if you search for the posts to solve the sliding nesting problem, you are basically proud of yourself after this article.

Now let's talk about the problems I have encountered after using this method to solve this problem. But the siege lion is not afraid of Ha, hoping to attract the attention of later generations:
One month later, according to the project requirements, the external ListView, that is, the entries in the parent ListView display text numbers, needs to add the identification of phone numbers and HTTP links. Namely: if it is a mobile phone number, click and enter the dial interface. As you know, this is very simple, just set a simple property in TextView. Then my problem arises because the touching event of the parent ListView is handed over to the child view. If the TextView in the child view has this implicit click event, it will cause the Karton phenomenon of the parent ListView. And it's quite a carton. So in the project, the fixed child ListView size is used, and the onInterceptTouchEvent event of the parent ListView is no longer rewritten by using the system ListView directly. More will be shown and processed as loads. Another is to avoid using Html.from() to make TextView support simple html tags when using TextView. This is too performance-intensive. Look at it with MAT, but don't say much. I hope it will be helpful for those who have time to read this article.

Life is endless, coding is endless.

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

I also embedded listview in listview, and sub-listview can also click the item to expand, click again and go back, which is equivalent to an expandable ListView. I used View.GONE and View.VISIBLE to implement the components of sub-item. The problem came. After the expansion, you can not see the height of the acquisition is wrong. How can this be solved?


Solution

This problem has been solved for a long time. I haven't been here for a long time.
The reason for this problem is that there is a problem with getheight, and the problem is that the parameters are incorrect.

/**

* Set the height of Listview

*/

public void setListViewHeight(ListView listView) {

ListAdapter listAdapter = listView.getAdapter();

if (listAdapter == null) {

return;

}

int totalHeight = 0;

for (int i = 0; i < listAdapter.getCount(); i++) {

View listItem = listAdapter.getView(i, null, listView);

listItem.measure(0, 0);

totalHeight += listItem.getMeasuredHeight();

}

ViewGroup.LayoutParams params = listView.getLayoutParams();

params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));

listView.setLayoutParams(params);

} 

View listItem = listAdapter.getView(i, null, listView); null cannot be passed in here,
You should get each item of the listview, that is: listView.getChildAt(i)
Hope to help you.

Posted by hdpt00 on Fri, 12 Jul 2019 18:52:32 -0700