之前写了一篇文章
android ListView/GridView与ScrollView嵌套的滑动冲突解决
介绍了如何解决ScrollView与AdapterView的嵌套,但是没有给出demo,那是因为那些代码比较多,而且是在手头的项目里,业务逻辑代码比较多,所以第一时间没有分享给大家。
今天终于有空把这些代码全部抽离了出来,并且去掉了业务代码和不必要的内容,以便大家能够更好的学习这个知识。
先贴一个效果图吧:
之前项目里我是使用复写ScrollView的onInterceptTouchEvent方法来接管滑动事件的,而有小伙伴@liu告诉我可以使用
android:focusable="true"
android:focusableInTouchMode="true"
来设置ScrollView接管事件。于是本Demo就使用了这个方法,结果与前一种方法效果上没有发现区别。
前一篇文章只写了滑动冲突解决的问题,本文也不再多赘述了,而ListView与ListView的嵌套里面还有其他的一些极易出错之处。
其中ListView中数据混乱(不是指图片)的问题应该来说是最重要也是比较烦人的bug
我的第一层ListView 的Adapter:
public class QuestionCLAdapter extends MyBaseAdapter<QuestionCL> {
//将下级Adapter放到上级Adapter中维护起来,防止new多个Adapter导致数据错乱
private HashMap<Integer,QuestionCLOptionAdapter> ads = new HashMap<Integer, QuestionCLOptionAdapter>();
public QuestionCLAdapter(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
@Override
public void setItems(List<QuestionCL> itemList) {
// TODO Auto-generated method stub
super.setItems(itemList);
for (int i = 0; i < itemList.size(); i++) {
ads.put(i,new QuestionCLOptionAdapter(context,itemList.get(i)));
}
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder holder = null;
if(convertView == null){
convertView = inflater.inflate(R.layout.item_error_question_detail_c, null);
holder = new ViewHolder();
holder.ansysLayout = (LinearLayout) convertView.findViewById(R.id.layout_question_ansys);
holder.questionTitleNum = (TextView) convertView.findViewById(R.id.tv_error_questioncl_titlenum);
holder.questionclTxt = (TextView) convertView.findViewById(R.id.tv_error_questioncl_text);
holder.questionRightTxt = (TextView) convertView.findViewById(R.id.tv_question_rightTxt);
holder.questionansysTxt = (TextView) convertView.findViewById(R.id.txt_question_ansys);
holder.questionclOptionsLv = (ListView) convertView.findViewById(R.id.lv_error_detail_c_option);
convertView.setTag(holder);
}else{
holder = (ViewHolder)convertView.getTag();
}
final QuestionCL item = itemList.get(position);
//初始化界面与监听器......
if (item.isSubmit()) {
holder.ansysLayout.setVisibility(View.VISIBLE);
int temp = 65;
for (int i = 0; i < item.getItems().size(); i++) {
if (item.getItems().get(i).getIsTrue() == 1) {
temp += i;
}
}
holder.questionRightTxt.setText((char)temp +"");
Log.i(TAG, (char)temp +"");
if (null != item.getAnalysis()) {
holder.questionansysTxt.setText(Html.fromHtml(item.getAnalysis()));
}
}else {
holder.ansysLayout.setVisibility(View.GONE);
}
holder.questionTitleNum.setText(item.getQustionid());
holder.questionclTxt.setText(Html.fromHtml(item.getQustiontext()));
if (null != ads.get(position)) {
holder.questionclOptionsLv.setAdapter(ads.get(position));
}
return convertView;
}
public class ViewHolder{
LinearLayout ansysLayout;
TextView questionTitleNum;
TextView questionRightTxt;
TextView questionansysTxt;
TextView questionclTxt;
ListView questionclOptionsLv;
}
}
应该来说是一个很经典很常规的自定义Adapter实现吧,继承的是自定义的虚基类。
可以看到我用一个容器作为类变量去管理其下级Adapter,在每次getView的时候都确保用的是它自己的数据而不是 重新new一个Adapter出来。
虚基类:
public abstract class MyBaseAdapter<T> extends BaseAdapter {
protected Context context;
protected String TAG = null;
protected LayoutInflater inflater;
protected List<T> itemList = new ArrayList<T>();
public MyBaseAdapter(Context context) {
this.context = context;
inflater = LayoutInflater.from(context);
TAG = this.getClass().getName();
}
/**
* 判断数据是否为空
*
* @return 为空返回true,不为空返回false
*/
@Override
public boolean isEmpty() {
return itemList.isEmpty();
}
/**
* 在原有的数据上添加新数据
*
* @param itemList
*/
public void addItems(List<T> itemList) {
this.itemList.addAll(itemList);
notifyDataSetChanged();
}
/**
* 设置为新的数据,旧数据会被清空
*
* @param itemList
*/
public void setItems(List<T> itemList) {
this.itemList.clear();
this.itemList = itemList;
notifyDataSetChanged();
}
/**
* 清空数据
*/
public void clearItems() {
itemList.clear();
notifyDataSetChanged();
}
@Override
public int getCount() {
return itemList.size();
}
@Override
public Object getItem(int position) {
return itemList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
abstract public View getView(int position, View view, ViewGroup viewGroup);
}
下级Adapter:
public class QuestionCLOptionAdapter extends MyBaseAdapter<QuestionOptionInfo> {
/** 当前被选中的位置 -1表示未作答 **/
private int selected;
/** 答案是否已提交 **/
private boolean isSubmmit;
private QuestionCL parentItem;
/** -1未作答,0答错,1答对 **/
private int isrightAnswered;
public QuestionCLOptionAdapter(Context context) {
super(context);
selected = -1;
isSubmmit = false;
isrightAnswered = -1;
}
public QuestionCLOptionAdapter(Context context,QuestionCL parentItem) {
super(context);
selected = -1;
isSubmmit = parentItem.isSubmit();
this.parentItem = parentItem;
this.setItems(parentItem.getItems());
isrightAnswered = -1;
}
@Override
public View getView(final int position, View convertView, final ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder holder = null;
if(convertView == null){
convertView = inflater.inflate(R.layout.item_list_error_question_option, null);
holder = new ViewHolder();
holder.rightImg = (ImageView) convertView.findViewById(R.id.img_question_option_true);
holder.wrongImg = (ImageView) convertView.findViewById(R.id.img_question_option_false);
holder.checkBox = (CheckBox) convertView.findViewById(R.id.cb_question_option_select);
holder.layout = (LinearLayout) convertView.findViewById(R.id.layout_question_option);
holder.optionTitle = (TextView) convertView.findViewById(R.id.tv_question_option_title);
holder.optionTxt = (TextView) convertView.findViewById(R.id.tv_question_option_text);
convertView.setTag(holder);
}else{
holder = (ViewHolder)convertView.getTag();
}
final QuestionOptionInfo item = itemList.get(position);
//初始化界面与监听器......
holder.checkBox.setVisibility(View.VISIBLE);
int num = item.getOptionId()+65;
holder.optionTitle.setText((char)num+".");
holder.optionTxt.setText(Html.fromHtml(item.getOptionText()));
holder.layout.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (isSubmmit) {
return;
}else {
if (position == selected) {
selected = -1;
} else {
selected = position;
isSubmmit = true;
if (null != parentItem && !parentItem.isSubmit() && isSubmmit) {
parentItem.setSubmit(true);
}
QuestionCLOptionAdapter.this.notifyDataSetChanged();
}
}
}
});
if (position == selected) {
holder.checkBox.setChecked(true);
} else {
holder.checkBox.setChecked(false);
}
//判断是否答对
if (isSubmmit) {
if (position == selected && item.getIsTrue() == 1) {
// 答对了
holder.rightImg.setVisibility(View.VISIBLE);
// Log.i(TAG, "true!!!!!!!!!!!!!!!!");
} else if (position == selected) {
// 答错了
holder.wrongImg.setVisibility(View.VISIBLE);
// Log.i(TAG, "false!!!!!!!!!!!!!!!");
} else {
holder.rightImg.setVisibility(View.GONE);
holder.wrongImg.setVisibility(View.GONE);
}
}
return convertView;
}
/** -1未作答,0答错,1答对
* @return the isrightAnswered
*/
public int getIsrightAnswered() {
if (isSubmmit) {
return isrightAnswered;
}else {
return -1;
}
}
/**-1未作答,0答错,1答对
* @param isrightAnswered the isrightAnswered to set
*/
public void setIsrightAnswered(int isrightAnswered) {
if (isSubmmit) {
this.isrightAnswered = isrightAnswered;
}
}
public class ViewHolder{
CheckBox checkBox;
ImageView rightImg;
ImageView wrongImg;
LinearLayout layout;
TextView optionTitle;
TextView optionTxt;
}
}
两个Adapter之间 你可以用类变量进行数据交互,可以通过bean的某一个值进行交互判断。在这里我都有用到。
public class MainActivity extends FragmentActivity {
private Bundle bundle;
private ScrollView sv;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sv = (ScrollView) findViewById(R.id.sv_main);
setFragment(new QuestionFragment(),initData());
//显示在顶端
sv.smoothScrollTo(0,0);
}
private QuestionC initData(){
// 生成测试数据
QuestionC questionC = new QuestionC();
//塞大题题干等信息
questionC.setMaintext("从前有座山,山里有座庙,庙里有个老和尚在讲故事。");
List<QuestionCL> cList = new ArrayList<QuestionCL>();
//2小题
for (int i = 1; i < 3; i++) {
QuestionCL cltemp = new QuestionCL();
//塞小题题干等信息
cltemp.setQustionid(i+"");
cltemp.setQustiontext("老和尚"+i+"是谁?");
cltemp.setRightitem("释永信"+i+i);
List<QuestionOptionInfo> optionList = new ArrayList<QuestionOptionInfo>();
//5选项
for (int j = 1; j < 6; j++) {
QuestionOptionInfo otemp = new QuestionOptionInfo();
//塞选项Id,String等
otemp.setOptionId(j-1);
otemp.setOptionText("释永信"+i+j);
if (otemp.getOptionText().equals(cltemp.getRightitem())) {
otemp.setIsTrue(1);
}else {
otemp.setIsTrue(0);
}
optionList.add(otemp);
}
cltemp.setItems(optionList);
cList.add(cltemp);
}
questionC.setQuestioncls((ArrayList<QuestionCL>) cList);
return questionC;
}
private void setFragment(Fragment fragment,QuestionC question) {
FragmentManager fragManager = getSupportFragmentManager();
FragmentTransaction transaction = fragManager.beginTransaction();
bundle = new Bundle();
bundle.putSerializable("bean", question);
fragment.setArguments(bundle);
transaction.replace(R.id.layout_fragment, fragment);
if (!MainActivity.this.isFinishing()) {
transaction.commitAllowingStateLoss();
}
}
}
public class QuestionFragment extends Fragment{
private Context context;
/** 实体 **/
private QuestionC questionC;
/** 大题干文本 **/
private TextView questionTxt;
/** 小题ListView **/
private ListView xiaotiLv;
private QuestionCLAdapter ad;
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
context = getActivity();
return inflater.inflate(R.layout.fragment_error_detail_c, container,false);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initWidget();
initData();
}
public void onAttach(Activity activity) {
// TODO Auto-generated method stub
super.onAttach(activity);
getIntentData();
}
protected void getIntentData() {
//取得Bean等信息
if (null != getArguments()) {
questionC = (QuestionC) getArguments().get("bean");
};
}
protected void initData() {
ad = new QuestionCLAdapter(context);
if (null == questionC) {
Log.i("questionC", "no data!!!");
} else {
ad.setItems(questionC.getQuestioncls());
xiaotiLv.setAdapter(ad);
questionTxt.setText(Html.fromHtml(questionC.getMaintext()));
}
}
protected void initWidget() {
questionTxt = (TextView) getView().findViewById(R.id.tv_error_question_txt);
xiaotiLv = (ListView) getView().findViewById(R.id.lv_error_detail_c_secondary_question);
}
}
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/sv_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#f3f3f3"
android:scrollbars="none"
android:focusable="true"
android:focusableInTouchMode="true"
tools:context="com.ysdemo.nestdemo.MainActivity" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<FrameLayout
android:id="@+id/layout_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView >
Demo下载地址
积分不够的小伙伴可以留下邮箱,我会另外发。
版权声明:本文为YS尘笑原创文章,未经本人允许不得转载。
ScrollView+Fragment+ListView嵌套ListView,麻麻再也不用担心我不会写嵌套
原文地址:http://blog.csdn.net/yaosongqwe/article/details/48030359