listview的显示问题 header

ListView:public void addFooterView()  public voidaddHeaderView()

上面的两个方法是在ListView增加尾部View和头部View的方法。 此addFooterView方法可以被调用多次, 新增的尾部View会按照他们添加的顺序显示在页面上(HeaderView同理).上述两种方法调用之后,listView的数据记录总数也会相应地增加。

 

上述两个方法新增的View可以获得焦点,所以应该重写listView的setOnItemClickListener方法中的new OnItemClickListener()接口的public void onItemClick(AdapterView<?> parent, View view,
                        int position, long id)方法,对不需要获得焦点的HeaderView或者FooterView进行相应的处理。


还有另外一种方法:不要使用listView.addHeaderView(headerView),而是使用listView.addHeaderView(headerView,null,false);即可。这样header就不能点击





在开发新浪微博的时候我使用了android中的ListView中的FootView来增加一个更多项来动态添加数据。但是我在开发的时候却遇到这个问题就是我添加了这个FootView的时候我通过在后台去下载数据比如:图片和一下文字信息的时候当后台有了数据过个通过消息机制来通知主线程去刷新UI(这里需要注意的是我们在开发当中所有的UI刷新必须在主线程去刷新界面,因为android中UI线程是不安全的其他我也不多说了网上有许多的资料啦...)回到问题当接收到了后台的消息过后我们要去刷新界面(主线程中)这是我们会调用
:((homeActivityBaseAdapter)listView.getAdapter
()).notifyDataSetChanged();这个方法去刷新界面。简单的介绍一下homeActivityBaseAdapter这个是我自定义的继承于BaseAdapter的适配器,这是系统会跑出异常:java.lang.ClassCastException:android.widget.HeaderViewListAdapter这时我们可以看到这个.HeaderViewListAdapter这个关键词,通过这个可以知道
:android.widget.HeaderViewListAdapter不能强转为listview的异常信息,这是因为当向listview中加入headerview或者footviwer时,调用ListView的setAdapter方法会将adapter转化为headerviewlistadapter
解决方法:
HeaderViewListAdapterlistAdapter=(HeaderViewListAdapter)listView.getAdapter();
homeActivityBaseAdapteradapter=(homeActivityBaseAdapter)listAdapter.getWrappedAdapter();
adapter.notifyDataSetChanged();


因为ListView的getAdapter方法返回的是HeaderViewListAdapter的实例,而将其转换成BaseAdapter的子类的实例,肯定是不对的。
由于ListView添加了headerView或者footerView,所以就相当于给ListView的数据添加了两项,加了个headerView,所以其他的view在界面上的位置position都增长了1,所以当用户点击界面上的第二项的时候,实际上点的是第三项,这就涉及到了ListView中的position和自定义Adapter中的position的对应关系问题了,将onItemClick改成下面的写法就好了。
private OnItemClickListener mItemClickListener = new OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView parent, View view, int position,
                long id) {
           HeaderViewListAdapter ha = (HeaderViewListAdapter) parent.getAdapter();
            JobsAdapter ad = (JobsAdapter) ha.getWrappedAdapter();
            ad.toggle(position-1);
        }
    };


   添加:关于addHeaderView方法文档上有这么一句话,“Call this before calling setAdapter”,在调用这个方法之前,先要设定ListView的Adapter。addFooterView方法同样
      移除:用到了系统提供的removeHeaderView或者removeFooterView方法,虽然文档上没有说明,但是调用这个方法应该在setAdapter之后。实例验证,不知道为什么,应该好好看看。


使用listView或者gridView时,当列表为空时,有时需要显示一个特殊的empty view来提示用户,一般情况下,如果你是继承ListActivity,只要 
<ListView android:id="@id/android:list".../> 
<TextView android:id="@id/android:empty.../> 
当列表为空时就会自动显示TextView 

但是,如果继承Activity的话,想出现上面的效果,就需要手动 

<ListView android:id="@+id/list" .../> 
<TextView android:id="@+id/empty" .../> 

ListView list= (ListView)findViewById(R.id.mylist); 
TextView tv= (TextView)findViewById(R.id.myempty); 

list.setEmptyView(tv); 

误区: 
setEmptyView(View)这个函数很有误导性,有时可能会在代码中写EmptyView,像下面这样: 

TextView tv= new TextView(this); 
tv.setText("this is a empty view") 
setEmptyView(tv); 
这样是不行的。。。 

但是后来我在老外的网上说下面这样是可行的,注意第4,5行: 
Java代码  复制代码  收藏代码
  1. TextView emptyView = new TextView(context);   
  2. emptyView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));   
  3. emptyView.setText(“This appears when the list is empty”);   
  4. emptyView.setVisibility(View.GONE);   
  5. ((ViewGroup)list.getParent()).addView(emptyView);   
  6. list.setEmptyView(emptyView);  
  7. 1
    2
    3
    4
    inflater = getLayoutInflater(); 
    emptyView = inflater.inflate(R.layout.empty_view, null); 
    addContentView(emptyView, new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT)); 
    list.setEmptyView(emptyView);  
    
     
                 

    注意:

    1.不要让提示的View在不改显示的时候显示出来了

    1
    emptyView.setVisibility(View.GONE);   
    

    2.setEmptyView()这个方法是有限制的,这个View必须在当前的View hierarchy的节点上,我们可以自己写在当前布局文件里面,也可以写在外面,但是需要把View添加到当前的View hierarchy的节点上。、

    1
    2
    3
    ((ViewGroup)list.getParent()).addView(emptyView);   
    //或者
    addContentView(emptyView, new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT)); 
    
    
                       
                       
    
                       
                       

    empty_view_layout.xml:

    <RelativeLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:orientation="vertical"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      android:id="@+id/empty_view_layout">
        <TextView
        style="@android:style/TextAppearance.Large"
        android:id="@+id/empty_view_textview"
        android:layout_width = "fill_parent"
        android:layout_height="fill_parent"
        android:text="@string/no_items_in_list" 
        android:layout_centerInParent="true"/>
    </RelativeLayout>




<LinearLayout
android:id="@+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/layoutTitlebar">

<ListView
android:id="@+id/listViewFriends"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:background="@color/friendBGColor"
android:cacheColorHint="#00000000">
</ListView>

<TextView
android:id="@+id/empty"
android:text="@string/strNoRecordsFound"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
style="@android:style/TextAppearance.Large"
android:gravity="center">
</TextView>
</LinearLayout>
java代码:
复制内容到剪贴板
代码:
ListView listViewFriends = (ListView) findViewById(R.id.listViewFriends);
// set your adapter here
// set your click listener here
// or whatever else
listViewFriends.setEmptyView(findViewById(R.id.empty));


嘿嘿这个方法还是不错的,不过也不是万用的,如果你有headerview的话,正常情况下。headerview时会显示出来的,但是用setEmptyView的话,就会把那些全部覆盖了。只会显示emptyeview的内容!所以这个东西要根据具体场景来用。


第一次用这个方法,如果是覆盖全部的话,也可以直接 写个View,然后GONE掉,如果没有数据,直接让他在指定的位置 Visible就可以了



今天在做项目的时候用了自定义listview以及自定义的item、adapter。现在把其中需要注意的地方记录下来:

1、item内如果有button等控件时,在监听listview的onitemclick事件时,焦点会被item内的button、imagebutton等控件抢走,从而导致在listview设置了onitemclick事件后不会被触发。解决方法是在初始化item的时候屏蔽掉其内部button等控件的焦点获取,具体方法可以在自定义item的根控件中调用:

[java]  view plain copy
  1. setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);   


这样就能阻塞字控件抢夺焦点,listview的onitemclick就能被正确触发,同时对item内部的button等控件也没有影响,他们在被点击时照样可以触发自身的点击事件。

2、当listview需要添加headerview时,可以通过调用listview的addHeaderView(headView, null, false) 方法,该方法还有一个重载方法 addHeaderView(headView);这两个方法的区别是前一个方法可以控制header是否可以被selected,如果不想被selected则将第三个参数设置成false;

3、接着上面说的添加header,添加header时调用的addHeaderView方法必须放在listview.setadapter前面,意思很明确就是如果想给listview添加头部则必须在给其绑定adapter前添加,否则会报错。原因是当我们在调用setAdapter方法时会android会判断当前listview是否已经添加header,如果已经添加则会生成一个新的tempadapter,这个新的tempadapter包含我们设置的adapter所有内容以及listview的header和footer。所以当我们在给listview添加了header后在程序中调用listview.getadapter时返回的是tempadapter而不是我们通过setadapter传进去的adapter。如果没有设置adapter则tempadapter与我们自己的adapter是一样的。listview.getadapter().getcount()方法返回值会比我们预期的要大,原因是添加了header。

4、接着上面的tempadapter说,我们自定义adapter里面的getitem方法里面返回的position是不包括header的,是我们自定义adapter中数据position编号从0开始,也就是说与我们传进去的list的位置是一样的。

[java]  view plain copy
  1. @Override  
  2. public View getView(int position, View convertView, ViewGroup parent) {  
  3. // TODO Auto-generated method stub  
  4. Log.i("adapter""position:"+position);   //这个position就是我们数据的真实位置  
  5.   }  

而listview的onitemclick方法中:

[java]  view plain copy
  1. public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3)   

arg2是当前click的位置,这个位置是指在tempadapter中的位置,从0开始如果listview中添加了header则0代表header
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值