今天在做一个小项目用到了ListView去加载头布局,头布局用的是ViewPager,发现了一些问题。
一、加载头布局时报ClassCastException
MainActivity文件
package com.example.shawn.listviewandviewpagerdemo;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private List<String> listData;//ListView中的数据集合
private ListView listView;
private List<View> views;//ViewPager中的View集合
private ViewPager viewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.lv_test);
//给ListView使用的数据
listData=new ArrayList<>();
for (int i = 0; i < 30; i++) {
listData.add("测试数据"+i);
}
//加载ViewPager的布局
View view = LayoutInflater.from(this).inflate(R.layout.layout_view_pager, null);
initViews();
//找到ViewPager
viewPager = (ViewPager) view.findViewById(R.id.vp_test);
//给ViewPager设置自定义的适配器
viewPager.setAdapter(new MyPagerAdaper(views));
//**给ListView添加头布局,注意这行代码必须在setAdapter()之前调用。**
listView.addHeaderView(viewPager);
listView.setAdapter(new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,listData));
}
/**
* 初始化ViewPager中加载的内容
*/
private void initViews() {
views = new ArrayList<>();
View view1 = getLayoutInflater().inflate(R.layout.page1_layout, null);
View view2 = getLayoutInflater().inflate(R.layout.page2_layout, null);
View view3 = getLayoutInflater().inflate(R.layout.page3_layout, null);
View view4 = getLayoutInflater().inflate(R.layout.page4_layout, null);
views.add(view1);
views.add(view2);
views.add(view3);
views.add(view4);
}
}
ViewPager的适配器
package com.example.shawn.listviewandviewpagerdemo;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;
import java.util.List;
public class MyPagerAdaper extends PagerAdapter {
private List<View> views;
public MyPagerAdaper(List<View> views) {
this.views = views;
}
@Override
public int getCount() {
return views.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view==object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
container.addView(views.get(position));
return views.get(position);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
当我在initViews() 方法中使用上面这种方式去添加ViewPager中的内容时,就会报java.lang.ClassCastException: android.widget.LinearLayoutLayoutParamscannotbecasttoandroid.widget.AbsListViewLayoutParams,查了资料后才知道原因。要将一个View添加到另一个布局中,必须设定该View的布局参数为其父类所使用的布局参数类型,即要在代码中动态改变某组件的高度,其布局参数类型应该是其父类所使用的布局参数类型。
修改onCreate()方法中代码如下:
**viewPager.setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 500));**
这样修改后就不会报错了。但是当我把ViewPager要添加的View改成ImageView时,居然不会报ClassCastException,这时我就懵圈了,原因是啥正在研究。
private void initViews() {
views = new ArrayList<>();//注意此时的List泛型为ImageView
ImageView imageView1 = new ImageView(this);
imageView1.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView1.setImageResource(R.mipmap.aaa);
ImageView imageView2 = new ImageView(this);
imageView2.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView2.setImageResource(R.mipmap.bbb);
ImageView imageView3 = new ImageView(this);
imageView3.setImageResource(R.mipmap.aaa);
imageView3.setScaleType(ImageView.ScaleType.CENTER_CROP);
ImageView imageView4 = new ImageView(this);
imageView4.setImageResource(R.mipmap.bbb);
imageView4.setScaleType(ImageView.ScaleType.CENTER_CROP);
mlistpic.add(imageView1);
mlistpic.add(imageView2);
mlistpic.add(imageView3);
mlistpic.add(imageView4);
}
layout_page1
四个layout_page都一样,只是背景色不同。
二、滑动冲突
ListView和ViewPager的滑动方向不一样,在滑动时可能造成冲突。处理方式:
方法一:自定义MyListView继承ListView,重写onInterceptTouchEvent方法。在activity_main.xml文件中引入自定义的MyListView,MainActivity中listview的类型改为MyListView。这样在viewPage里面去上下滑动,listview不会响应。
package com.example.shawn.listviewandviewpagerdemo;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ListView;
public class MyListView extends ListView {
public MyListView(Context context) {
super(context);
}
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
}
因为ViewPager是加载到父容器ListView中的,返回false表示父容器把点击事件丢给子控件去处理。
方法二:自定义MyViewPager继承ViewPager,重写onInterceptTouchEvent方法。之后的操作与上面的方法类似。
package com.example.shawn.listviewandviewpagerdemo;
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
public class MyViewPager extends ViewPager {
public MyViewPager(Context context) {
super(context);
}
public MyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
getParent().requestDisallowInterceptTouchEvent(true);
break;
}
return super.onInterceptTouchEvent(ev);
}
}
在ViewPager内部去拦截点击事件,自己处理。MotionEvent.ACTION_UP一般可以不用去判断。