android如何显示多个View
setcontentview(view1);setcontentview(view2);只能显示后面那个view,如何能显示两个啊,求助...
setcontentview(view1);setcontentview(view2);只能显示后面那个view,如何能显示两个啊,求助
展开
展开全部
关系型数据库SQLite3,它是一个支持SQL轻量级的嵌入式数据库,在嵌入式操作上有很广泛的,WM采用的也是SQLite3
关于过于、原理方面的东西在这篇文章里不会提到,但是如果你想能够快速的学会操作SQLite3,那这就是你要找的文章!
首先,我们看一下api,所有数据库相关的接口、类都在.database和android.database.sqlite两个包下,虽然只有两个包,但是如果你英文不好或是太懒的话也要迷茫一段时间,其实,我们真正用的到的没有几个!
1、SQLiteOpenHelper (android.database.sqlite.SQLiteOpenHelper)
这是一个抽象类,关于抽象类我们都知道,如果要使用它,一定是继承它!
这个类的方法很少,有一个构造方法
SQLiteOpenHelper(android.content.Context context, java.lang.String name,android.database.sqlite.SQLiteDatabase.CursorFactory factory, int version);
参数不做过多的解释,CursorFactory一般直接传null就可以
public void onCreate(SQLiteDatabase db)
此方法在创建数据库是被调用,所以,应该把创建表的操作放到这个方法里面,一会儿在后面我们会再详细的说如何创建表
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
从方法名上我们就能知道这个方法是执行更新的,没错,当version改变是系统会调用这个方法,所以在这个方法里应该执行删除现有表,然后手动调用onCreate的操作
SQLiteDatabase getReadableDatabase()
可读的SQLiteDatabase对象
SQLiteDatabase getWritableDatabase()
获取可写的SQLiteDatabase对象
2、SQLiteDatabase(android.database.sqlite.SQLiteDatabase)
关于操作数据库的工作(增、删、查、改)都在这个类里
execSQL(sql)
执行SQL语句,用这个方法+SQL语句可以非常方便的执行增、删、查、改
除此之外,Android还提供了功过方法实现增、删、查、改
long insert(TABLE_NAME, null, contentValues)添加记录
int delete(TABLE_NAME, where, whereValue)删除记录
int update(TABLE_NAME, contentValues, where, whereValue) 更新记录
Cursor query(TABLE_NAME, null, null, null, null, null, null) 查询记录
除此之外,还有很多方法,如:beginTransaction()开始事务、endTransaction()结束事务...有兴趣的可以自己看api,这里就不多赘述了
3、Cursor(android.database.Cursor)
游标(接口),这个很熟悉了吧,Cursor里的方法非常多,常用的有:
boolean moveToPosition(position)将指针移动到某记录
getColumnIndex(Contacts.People.NAME)按列名获取id
int getCount()获取记录总数
boolean requery()重新查询
boolean isAfterLast()指针是否在末尾
boolean isBeforeFirst()时候是开始位置
boolean isFirst()是否是第一条记录
boolean isLast()是否是最后一条记录
boolean moveToFirst()、 boolean moveToLast()、 boolean moveToNext()同moveToPosition(position)
4、SimpleCursorAdapter(android.widget.SimpleCursorAdapter)
也许你会奇怪了,之前我还说过关于数据库的操作都在database和database.sqlite包下,为什么把一个Adapter放到这里,如果你用过Android的SQLite3,你一定会知道
,这是因为我们对数据库的操作会经常跟列表联系起来
经常有朋友会在这出错,但其实也很简单
SimpleCursorAdapter adapter = new SimpleCursorAdapter(
this,
R.layout.list,
myCursor,
new String[] ,
new int[]);
my.setAdapter(adapter);
一共5个参数,具体如下:
参数1:Content
参数2:布局
参数3:Cursor游标对象
参数4:显示的字段,传入String[]
参数5:显示字段使用的组件,传入int[],该数组中是TextView组件的id
到这里,关于数据库的操作就结束了,但是到目前为止我只做了翻译的工作,有些同学可能还是没有掌握,放心,下面我们一起顺着正常开发的思路理清一下头绪!
前面的只是帮没做过的朋友做下普及,下面才是你真正需要的!
一、写一个类继承SQLiteOpenHelpe
public class DatabaseHelper extends SQLiteOpenHelper
构造方法:
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
在onCreate方法里写建表的操作
public void onCreate(SQLiteDatabase db) {
String sql = "CREATE TABLE tb_test (_id INTEGER DEFAULT '1' NOT NULL PRIMARY KEY AUTOINCREMENT,class_jb TEXT NOT NULL,class_ysbj TEXT NOT NULL,title TEXT NOT NULL,content_ysbj TEXT NOT NULL)";
db.execSQL(sql);//需要异常捕获
}
在onUpgrade方法里删除现有表,然后手动调用onCtreate创建表
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
String sql = "drop table "+tbname;
db.execSQL(sql);
onCreate(db);
}
对表增、删、查、改的方法,这里用的是SQLiteOpenHelper提供的方法,也可以用sql语句实现,都是一样的
关于获取可读/可写SQLiteDatabase,我不说大家也应该会想到,只有查找才会用到可读的SQLiteDatabase
/**
* 添加数据
*/
public long insert(String tname, int tage, String ttel){
SQLiteDatabase db= getWritableDatabase();//获取可写SQLiteDatabase对象
//ContentValues类似map,存入的是键值对
ContentValues contentValues = new ContentValues();
contentValues.put("tname", tname);
contentValues.put("tage", tage);
contentValues.put("ttel", ttel);
return db.insert(tbname, null, contentValues);
}
/**
* 删除记录
* @param _id
*/
public void delete(String _id){
SQLiteDatabase db= getWritableDatabase();
db.delete(tbname,
"_id=?",
new String[]);
}
/**
* 更新记录的,跟插入的很像
*/
public void update(String _id,String tname, int tage, String ttel){
SQLiteDatabase db= getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("tname", tname);
contentValues.put("tage", tage);
contentValues.put("ttel", ttel);
db.update(tbname, contentValues,
"_id=?",
new String[]);
}
/**
* 查询所有数据
* @return Cursor
*/
public Cursor select(){
SQLiteDatabase db = getReadableDatabase();
return db.query(
tbname,
new String[],
null,
null, null, null, "_id desc");
}
关于db.query方法的参数,有很多,为了防止大家弄乱,我简单说一下
参数1:表名
参数2:返回数据包含的列信息,String数组里放的都是列名
参数3:相当于sql里的where,sql里where后写的内容放到这就行了,例如:tage>?
参数4:如果你在参数3里写了?(知道我为什么写tage>?了吧),那个这里就是代替?的值 接上例:new String[]
参数5:分组,不解释了,不想分组就传null
参数6:having,想不起来的看看SQL
参数7:orderBy排序
到这里,你已经完成了最多的第一步!我们来看看都用到了那些类:
SQLiteOpenHelper我们继承使用的
SQLiteDatabase增删查改都离不开它,即使你直接用sql语句,也要用到execSQL(sql)
二、这里无非是对DatabaseHelper类定义方法的调用,没什么可说的,不过我还是对查询再唠叨几句吧
Android查询出来的结果一Cursor形式返回
cursor = sqLiteHelper.select();//是不是很简单?
查询出来的cursor一般会显示在listView中,这就要用到刚才提到的SimpleCursorAdapter
SimpleCursorAdapter adapter = new SimpleCursorAdapter(
this,
R.layout.list_row,
cursor,
new String[],
new int[]
);
里面带有实例。自己好好学习吧!
关于过于、原理方面的东西在这篇文章里不会提到,但是如果你想能够快速的学会操作SQLite3,那这就是你要找的文章!
首先,我们看一下api,所有数据库相关的接口、类都在.database和android.database.sqlite两个包下,虽然只有两个包,但是如果你英文不好或是太懒的话也要迷茫一段时间,其实,我们真正用的到的没有几个!
1、SQLiteOpenHelper (android.database.sqlite.SQLiteOpenHelper)
这是一个抽象类,关于抽象类我们都知道,如果要使用它,一定是继承它!
这个类的方法很少,有一个构造方法
SQLiteOpenHelper(android.content.Context context, java.lang.String name,android.database.sqlite.SQLiteDatabase.CursorFactory factory, int version);
参数不做过多的解释,CursorFactory一般直接传null就可以
public void onCreate(SQLiteDatabase db)
此方法在创建数据库是被调用,所以,应该把创建表的操作放到这个方法里面,一会儿在后面我们会再详细的说如何创建表
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
从方法名上我们就能知道这个方法是执行更新的,没错,当version改变是系统会调用这个方法,所以在这个方法里应该执行删除现有表,然后手动调用onCreate的操作
SQLiteDatabase getReadableDatabase()
可读的SQLiteDatabase对象
SQLiteDatabase getWritableDatabase()
获取可写的SQLiteDatabase对象
2、SQLiteDatabase(android.database.sqlite.SQLiteDatabase)
关于操作数据库的工作(增、删、查、改)都在这个类里
execSQL(sql)
执行SQL语句,用这个方法+SQL语句可以非常方便的执行增、删、查、改
除此之外,Android还提供了功过方法实现增、删、查、改
long insert(TABLE_NAME, null, contentValues)添加记录
int delete(TABLE_NAME, where, whereValue)删除记录
int update(TABLE_NAME, contentValues, where, whereValue) 更新记录
Cursor query(TABLE_NAME, null, null, null, null, null, null) 查询记录
除此之外,还有很多方法,如:beginTransaction()开始事务、endTransaction()结束事务...有兴趣的可以自己看api,这里就不多赘述了
3、Cursor(android.database.Cursor)
游标(接口),这个很熟悉了吧,Cursor里的方法非常多,常用的有:
boolean moveToPosition(position)将指针移动到某记录
getColumnIndex(Contacts.People.NAME)按列名获取id
int getCount()获取记录总数
boolean requery()重新查询
boolean isAfterLast()指针是否在末尾
boolean isBeforeFirst()时候是开始位置
boolean isFirst()是否是第一条记录
boolean isLast()是否是最后一条记录
boolean moveToFirst()、 boolean moveToLast()、 boolean moveToNext()同moveToPosition(position)
4、SimpleCursorAdapter(android.widget.SimpleCursorAdapter)
也许你会奇怪了,之前我还说过关于数据库的操作都在database和database.sqlite包下,为什么把一个Adapter放到这里,如果你用过Android的SQLite3,你一定会知道
,这是因为我们对数据库的操作会经常跟列表联系起来
经常有朋友会在这出错,但其实也很简单
SimpleCursorAdapter adapter = new SimpleCursorAdapter(
this,
R.layout.list,
myCursor,
new String[] ,
new int[]);
my.setAdapter(adapter);
一共5个参数,具体如下:
参数1:Content
参数2:布局
参数3:Cursor游标对象
参数4:显示的字段,传入String[]
参数5:显示字段使用的组件,传入int[],该数组中是TextView组件的id
到这里,关于数据库的操作就结束了,但是到目前为止我只做了翻译的工作,有些同学可能还是没有掌握,放心,下面我们一起顺着正常开发的思路理清一下头绪!
前面的只是帮没做过的朋友做下普及,下面才是你真正需要的!
一、写一个类继承SQLiteOpenHelpe
public class DatabaseHelper extends SQLiteOpenHelper
构造方法:
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
在onCreate方法里写建表的操作
public void onCreate(SQLiteDatabase db) {
String sql = "CREATE TABLE tb_test (_id INTEGER DEFAULT '1' NOT NULL PRIMARY KEY AUTOINCREMENT,class_jb TEXT NOT NULL,class_ysbj TEXT NOT NULL,title TEXT NOT NULL,content_ysbj TEXT NOT NULL)";
db.execSQL(sql);//需要异常捕获
}
在onUpgrade方法里删除现有表,然后手动调用onCtreate创建表
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
String sql = "drop table "+tbname;
db.execSQL(sql);
onCreate(db);
}
对表增、删、查、改的方法,这里用的是SQLiteOpenHelper提供的方法,也可以用sql语句实现,都是一样的
关于获取可读/可写SQLiteDatabase,我不说大家也应该会想到,只有查找才会用到可读的SQLiteDatabase
/**
* 添加数据
*/
public long insert(String tname, int tage, String ttel){
SQLiteDatabase db= getWritableDatabase();//获取可写SQLiteDatabase对象
//ContentValues类似map,存入的是键值对
ContentValues contentValues = new ContentValues();
contentValues.put("tname", tname);
contentValues.put("tage", tage);
contentValues.put("ttel", ttel);
return db.insert(tbname, null, contentValues);
}
/**
* 删除记录
* @param _id
*/
public void delete(String _id){
SQLiteDatabase db= getWritableDatabase();
db.delete(tbname,
"_id=?",
new String[]);
}
/**
* 更新记录的,跟插入的很像
*/
public void update(String _id,String tname, int tage, String ttel){
SQLiteDatabase db= getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("tname", tname);
contentValues.put("tage", tage);
contentValues.put("ttel", ttel);
db.update(tbname, contentValues,
"_id=?",
new String[]);
}
/**
* 查询所有数据
* @return Cursor
*/
public Cursor select(){
SQLiteDatabase db = getReadableDatabase();
return db.query(
tbname,
new String[],
null,
null, null, null, "_id desc");
}
关于db.query方法的参数,有很多,为了防止大家弄乱,我简单说一下
参数1:表名
参数2:返回数据包含的列信息,String数组里放的都是列名
参数3:相当于sql里的where,sql里where后写的内容放到这就行了,例如:tage>?
参数4:如果你在参数3里写了?(知道我为什么写tage>?了吧),那个这里就是代替?的值 接上例:new String[]
参数5:分组,不解释了,不想分组就传null
参数6:having,想不起来的看看SQL
参数7:orderBy排序
到这里,你已经完成了最多的第一步!我们来看看都用到了那些类:
SQLiteOpenHelper我们继承使用的
SQLiteDatabase增删查改都离不开它,即使你直接用sql语句,也要用到execSQL(sql)
二、这里无非是对DatabaseHelper类定义方法的调用,没什么可说的,不过我还是对查询再唠叨几句吧
Android查询出来的结果一Cursor形式返回
cursor = sqLiteHelper.select();//是不是很简单?
查询出来的cursor一般会显示在listView中,这就要用到刚才提到的SimpleCursorAdapter
SimpleCursorAdapter adapter = new SimpleCursorAdapter(
this,
R.layout.list_row,
cursor,
new String[],
new int[]
);
里面带有实例。自己好好学习吧!
展开全部
setcontentview(view1);
view1.addview(view2);
1.对于控制事件今天我们只处理按键事件onKeyDown,
2.刷新view的方法这里主要有
invalidate(int l,int t,int r,int b) 刷新局部,四个参数分别为左、上、右、下
整个view刷新 invalidate()
刷新一个矩形区域invalidate(Rect dirty)
刷新一个特性DrawableinvalidateDrawable(Drawable drawable)
执行invalidate类的方法将会设置view为无效,最终导致onDraw方法被重新调用。
今天的view比较简单,大家如果在线程中刷新,除了使用handler方式外,可以在Thread中直接使用postInvalidate方法来实现。
3. 绘制View主要是onDraw()中通过形参canvas来处理,相关的绘制主要有drawRect、drawLine、drawPath等等。
view方法内部还重写了很多接口,其回调方法可以帮助我们判断出view的位置和大小,比如onMeasure(int, int) Called to determine the size requirements for this view and all of its children。 、onLayout(boolean, int, int, int, int) Called when this view should assign a size and position to all of its children 和onSizeChanged(int, int, int, int) Called when the size of this view has changed。 具体的作用,大家可以用Logcat获取当view变化时每个形参的变动。
view1.addview(view2);
1.对于控制事件今天我们只处理按键事件onKeyDown,
2.刷新view的方法这里主要有
invalidate(int l,int t,int r,int b) 刷新局部,四个参数分别为左、上、右、下
整个view刷新 invalidate()
刷新一个矩形区域invalidate(Rect dirty)
刷新一个特性DrawableinvalidateDrawable(Drawable drawable)
执行invalidate类的方法将会设置view为无效,最终导致onDraw方法被重新调用。
今天的view比较简单,大家如果在线程中刷新,除了使用handler方式外,可以在Thread中直接使用postInvalidate方法来实现。
3. 绘制View主要是onDraw()中通过形参canvas来处理,相关的绘制主要有drawRect、drawLine、drawPath等等。
view方法内部还重写了很多接口,其回调方法可以帮助我们判断出view的位置和大小,比如onMeasure(int, int) Called to determine the size requirements for this view and all of its children。 、onLayout(boolean, int, int, int, int) Called when this view should assign a size and position to all of its children 和onSizeChanged(int, int, int, int) Called when the size of this view has changed。 具体的作用,大家可以用Logcat获取当view变化时每个形参的变动。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
其实在android里面一个你说的view相当于一个窗口
android不是电脑它只能同时显示一个窗口
所以你的想法是不可能的。。。
android不是电脑它只能同时显示一个窗口
所以你的想法是不可能的。。。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
setcontentview(view1);
view1.addview(view2);
view1.addview(view2);
追问
不行啊,我说的是view1和view2显示在屏幕的不同地方,如果addview,应该是view2显示在view1上面吧,不过addview也不行
追答
那你可以先用一个RelativeLayout作为contentview,然后将view1,view2分别add进去,再通过layout params调整位置
本回答被提问者和网友采纳
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
如果很平常的两个listview组件竖直放在linearLayout布局中,结果是:
两个listview 很独立,中间似乎有个分割线,完全吧他们分离了,各自独立滚动,如果上面的listview把整个屏幕占据了,那么下面的listview永远滚不上来了,看不到了。
网上关于这个话题大约有两种方法解决:
(1)有多少个listview就用多少个listview组件,然后放在一个LinearLayout布局里面,linearLayout布局在放入Scrollview中。
这样做,必须先计算出每个listview被对应的adapter适配之后的实际高度,然后设置listview为这个高度。再放入scrollview中ok了。
(2)不管有多少个listview,都放在一个listview,用一个adapter适配,在listview组件对应的数据存储结构list中,设置flag标志位,在adapter中再对不同的flag做不同的适配。
一开始,项目中使用的第一种方法,随着项目的进行,发现第一种方法会在很多种情况下不适应,最严重的问题,就是第一种方法非常耗时,已经到了一种无可忍受的地步了。
一个很常见的例子,城市列表,有两个list:热门城市、全部城市
假如用第一种方法,先计算两个listview在对应的adapter适配后的高度:
[java] view plaincopy
public static void setListViewHeightBasedOnChildren(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);
}
[java] view plaincopy
public static void setListViewHeightBasedOnChildren(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);
}
其实从这段代码中,和上面这个需求,问题已经可以看出来了。
adapter有一个方法getView,这个方法是如果这个listview的某行将要在屏幕上显示了,系统就会自动调用getview得到这个布局,然后显示。
也就是每次被调用的次数,只是屏幕上能显示的条数,最多也就是10条左右。
而一次计算高度就要对每一条调用getview,for循环里面:
[java] view plaincopy
View listItem = listAdapter.getView(i, null, listView);
[java] view plaincopy
View listItem = listAdapter.getView(i, null, listView);
是非常耗时的,尤其对于全部城市,几百条,3~4秒肯定是要的。所以面对这个需求,第一种方法是不可行。
除了耗时,第一种方法,维护性也不好。就比如,一个页面中,listview的数据是不定的,是动态计算得到的。用第一种方法分散到多个listview,对于一些事件监听,不好操作。
下面讲解下第二种方法的具体实现
拿上面城市列表具体
分两块:
1、数据dataList
2、adapter
1、datalist填充:
主要以一个flag标记,对于城市列表共有两种布局:
一个是头信息
一个是具体的城市
代码:
[java] view plaincopy
cityList.clear();
Map<String, Object> map1 = new HashMap<String, Object>();
map1.put("city", new City(0, "热门城市", '#'));
cityList.add(map1);
List<City> cities = getHotCity();
for (City city : cities) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("is_selected", false);
map.put("city", city);
cityList.add(map);
}
Map<String, Object> map2 = new HashMap<String, Object>();
map2.put("city", new City(0, "全部城市", '$'));
cityList.add(map2);
index++;
cities = getAllCity();
for (City city : cities) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("is_selected", false);
map.put("city", city);
cityList.add(map);
}
[java] view plaincopy
cityList.clear();
Map<String, Object> map1 = new HashMap<String, Object>();
map1.put("city", new City(0, "热门城市", '#'));
cityList.add(map1);
List<City> cities = getHotCity();
for (City city : cities) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("is_selected", false);
map.put("city", city);
cityList.add(map);
}
Map<String, Object> map2 = new HashMap<String, Object>();
map2.put("city", new City(0, "全部城市", '$'));
cityList.add(map2);
index++;
cities = getAllCity();
for (City city : cities) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("is_selected", false);
map.put("city", city);
cityList.add(map);
}
哦~这个好像没用到flag标记,直接判断city的name了~~~
2、adapter适配:
[java] view plaincopy
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
City city = (City) listData.get(position).get("city");
String nameString = city.getName();
if (nameString.compareTo("热门城市") == 0) {
convertView = mInflater.inflate(headResource, null);
((TextView) convertView.findViewById(R.id.label)).setText("热门城市");
return convertView;
}
if (nameString.compareTo("全部城市") == 0) {
convertView = mInflater.inflate(headResource, null);
((TextView) convertView.findViewById(R.id.label)).setText("全部城市");
return convertView;
}
convertView = mInflater.inflate(listResource, null);
((TextView) convertView.findViewById(R.id.label)).setText(nameString);
ImageView isSelectedImageView = (ImageView) convertView.findViewById(R.id.is_selected);
// boolean isSelected = (Boolean) listData.get(position).get("is_selected");
int whichIsSelected = (Integer) listData.get(getCount() - 1).get("which_is_selected");
if (city.getId() == whichIsSelected)
isSelectedImageView.setBackgroundResource(R.drawable.is_selected_yes);
else
isSelectedImageView.setBackgroundResource(R.drawable.is_selected_no);
return convertView;
}
[java] view plaincopy
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
City city = (City) listData.get(position).get("city");
String nameString = city.getName();
if (nameString.compareTo("热门城市") == 0) {
convertView = mInflater.inflate(headResource, null);
((TextView) convertView.findViewById(R.id.label)).setText("热门城市");
return convertView;
}
if (nameString.compareTo("全部城市") == 0) {
convertView = mInflater.inflate(headResource, null);
((TextView) convertView.findViewById(R.id.label)).setText("全部城市");
return convertView;
}
convertView = mInflater.inflate(listResource, null);
((TextView) convertView.findViewById(R.id.label)).setText(nameString);
ImageView isSelectedImageView = (ImageView) convertView.findViewById(R.id.is_selected);
// boolean isSelected = (Boolean) listData.get(position).get("is_selected");
int whichIsSelected = (Integer) listData.get(getCount() - 1).get("which_is_selected");
if (city.getId() == whichIsSelected)
isSelectedImageView.setBackgroundResource(R.drawable.is_selected_yes);
else
isSelectedImageView.setBackgroundResource(R.drawable.is_selected_no);
return convertView;
}
对于各行的点击操作也可以根据flag统一处理。维护起来非常方便。
两个listview 很独立,中间似乎有个分割线,完全吧他们分离了,各自独立滚动,如果上面的listview把整个屏幕占据了,那么下面的listview永远滚不上来了,看不到了。
网上关于这个话题大约有两种方法解决:
(1)有多少个listview就用多少个listview组件,然后放在一个LinearLayout布局里面,linearLayout布局在放入Scrollview中。
这样做,必须先计算出每个listview被对应的adapter适配之后的实际高度,然后设置listview为这个高度。再放入scrollview中ok了。
(2)不管有多少个listview,都放在一个listview,用一个adapter适配,在listview组件对应的数据存储结构list中,设置flag标志位,在adapter中再对不同的flag做不同的适配。
一开始,项目中使用的第一种方法,随着项目的进行,发现第一种方法会在很多种情况下不适应,最严重的问题,就是第一种方法非常耗时,已经到了一种无可忍受的地步了。
一个很常见的例子,城市列表,有两个list:热门城市、全部城市
假如用第一种方法,先计算两个listview在对应的adapter适配后的高度:
[java] view plaincopy
public static void setListViewHeightBasedOnChildren(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);
}
[java] view plaincopy
public static void setListViewHeightBasedOnChildren(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);
}
其实从这段代码中,和上面这个需求,问题已经可以看出来了。
adapter有一个方法getView,这个方法是如果这个listview的某行将要在屏幕上显示了,系统就会自动调用getview得到这个布局,然后显示。
也就是每次被调用的次数,只是屏幕上能显示的条数,最多也就是10条左右。
而一次计算高度就要对每一条调用getview,for循环里面:
[java] view plaincopy
View listItem = listAdapter.getView(i, null, listView);
[java] view plaincopy
View listItem = listAdapter.getView(i, null, listView);
是非常耗时的,尤其对于全部城市,几百条,3~4秒肯定是要的。所以面对这个需求,第一种方法是不可行。
除了耗时,第一种方法,维护性也不好。就比如,一个页面中,listview的数据是不定的,是动态计算得到的。用第一种方法分散到多个listview,对于一些事件监听,不好操作。
下面讲解下第二种方法的具体实现
拿上面城市列表具体
分两块:
1、数据dataList
2、adapter
1、datalist填充:
主要以一个flag标记,对于城市列表共有两种布局:
一个是头信息
一个是具体的城市
代码:
[java] view plaincopy
cityList.clear();
Map<String, Object> map1 = new HashMap<String, Object>();
map1.put("city", new City(0, "热门城市", '#'));
cityList.add(map1);
List<City> cities = getHotCity();
for (City city : cities) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("is_selected", false);
map.put("city", city);
cityList.add(map);
}
Map<String, Object> map2 = new HashMap<String, Object>();
map2.put("city", new City(0, "全部城市", '$'));
cityList.add(map2);
index++;
cities = getAllCity();
for (City city : cities) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("is_selected", false);
map.put("city", city);
cityList.add(map);
}
[java] view plaincopy
cityList.clear();
Map<String, Object> map1 = new HashMap<String, Object>();
map1.put("city", new City(0, "热门城市", '#'));
cityList.add(map1);
List<City> cities = getHotCity();
for (City city : cities) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("is_selected", false);
map.put("city", city);
cityList.add(map);
}
Map<String, Object> map2 = new HashMap<String, Object>();
map2.put("city", new City(0, "全部城市", '$'));
cityList.add(map2);
index++;
cities = getAllCity();
for (City city : cities) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("is_selected", false);
map.put("city", city);
cityList.add(map);
}
哦~这个好像没用到flag标记,直接判断city的name了~~~
2、adapter适配:
[java] view plaincopy
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
City city = (City) listData.get(position).get("city");
String nameString = city.getName();
if (nameString.compareTo("热门城市") == 0) {
convertView = mInflater.inflate(headResource, null);
((TextView) convertView.findViewById(R.id.label)).setText("热门城市");
return convertView;
}
if (nameString.compareTo("全部城市") == 0) {
convertView = mInflater.inflate(headResource, null);
((TextView) convertView.findViewById(R.id.label)).setText("全部城市");
return convertView;
}
convertView = mInflater.inflate(listResource, null);
((TextView) convertView.findViewById(R.id.label)).setText(nameString);
ImageView isSelectedImageView = (ImageView) convertView.findViewById(R.id.is_selected);
// boolean isSelected = (Boolean) listData.get(position).get("is_selected");
int whichIsSelected = (Integer) listData.get(getCount() - 1).get("which_is_selected");
if (city.getId() == whichIsSelected)
isSelectedImageView.setBackgroundResource(R.drawable.is_selected_yes);
else
isSelectedImageView.setBackgroundResource(R.drawable.is_selected_no);
return convertView;
}
[java] view plaincopy
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
City city = (City) listData.get(position).get("city");
String nameString = city.getName();
if (nameString.compareTo("热门城市") == 0) {
convertView = mInflater.inflate(headResource, null);
((TextView) convertView.findViewById(R.id.label)).setText("热门城市");
return convertView;
}
if (nameString.compareTo("全部城市") == 0) {
convertView = mInflater.inflate(headResource, null);
((TextView) convertView.findViewById(R.id.label)).setText("全部城市");
return convertView;
}
convertView = mInflater.inflate(listResource, null);
((TextView) convertView.findViewById(R.id.label)).setText(nameString);
ImageView isSelectedImageView = (ImageView) convertView.findViewById(R.id.is_selected);
// boolean isSelected = (Boolean) listData.get(position).get("is_selected");
int whichIsSelected = (Integer) listData.get(getCount() - 1).get("which_is_selected");
if (city.getId() == whichIsSelected)
isSelectedImageView.setBackgroundResource(R.drawable.is_selected_yes);
else
isSelectedImageView.setBackgroundResource(R.drawable.is_selected_no);
return convertView;
}
对于各行的点击操作也可以根据flag统一处理。维护起来非常方便。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询