您的位置:首页 > 移动开发 > Android开发

Android 自定义 ListView 上下拉动“刷新最新”和“加载更多”歌曲列表

2014-07-09 16:46 573 查看

本文内容

环境测试数据项目结构演示参考资料
本文演示,上拉刷新最新的歌曲列表,和下拉加载更多的歌曲列表。所谓“刷新最新”和“加载更多”是指日期。演示代码太多,点击此处下载,自己调试一下。

下载Demo

环境

Windows2008R264位EclipseADTV22.6.2,Android4.4.3SAMSUNGGT-I9008L,AndroidOS2.2.2

测试数据

本演示的歌曲信息,共有20条,包括歌手名、歌曲名、时长、缩略图,为了简单起见都存在本地,你当然也可以通过网络获得。同时,当下拉刷新最新或上拉加载更多时,为了简单,20条歌曲信息是取模运算循环使用的。

packagecom.my.android.app.data;
importcom.my.android.app.R;
publicclassTestData{
publicstaticString[]title=newString[]{"SomeoneLikeYou",
"SpaceBound","StrangerInMoscow","LoveTheWayYouLie",
"KhwajaMereKhwaja","AllMyDays","LifeForRent",
"LoveToSeeYouCry","TheGood,TheBadAndTheUgly",
"Showmethemeaning","SomeoneLikeYou","SpaceBound",
"StrangerInMoscow","LoveTheWayYouLie","KhwajaMereKhwaja",
"AllMyDays","LifeForRent","LoveToSeeYouCry",
"TheGood,TheBadAndTheUgly","Showmethemeaning"};
publicstaticString[]artist=newString[]{"Adele","Eminem",
"MichaelJackson","Rihanna","ARRehman","AlexiMurdoch",
"Dido","EnriqueIglesias","EnnioMorricone","BackstreetBoys",
"Adele","Eminem","MichaelJackson","Rihanna","ARRehman",
"AlexiMurdoch","Dido","EnriqueIglesias","EnnioMorricone",
"BackstreetBoys"};
publicstaticint[]thumb=newint[]{R.drawable.adele,
R.drawable.eminem,R.drawable.mj,R.drawable.rihanna,
R.drawable.arrehman,R.drawable.alexi_murdoch,R.drawable.dido,
R.drawable.enrique,R.drawable.ennio,R.drawable.backstreet_boys,
R.drawable.adele,R.drawable.eminem,R.drawable.mj,
R.drawable.rihanna,R.drawable.arrehman,R.drawable.alexi_murdoch,
R.drawable.dido,R.drawable.enrique,R.drawable.ennio,
R.drawable.backstreet_boys};
publicstaticString[]duration=newString[]{"4:47","4:38","5:44",
"4:23","6:58","4:47","3:41","4:07","2:42","3:56","4:47",
"4:38","5:44","4:23","6:58","4:47","3:41","4:07","2:42",
"3:56"};
}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

项目结构





图1项目结构

com.my.android.app.activit包,是主程序和三个演示的界面后台;
com.my.android.app.activit.data包,是测试数据;
com.my.android.app.activit.view包,是实现下拉上拉“刷新最新”和“加载更多”。

演示

本程序主界面,如图2所示。包含三个演示,“example1:SimplePushandPull”是上拉下拉刷新最新和加载更多的演示,刷新或加载的内容只是当前时间而已;“example2:CustomMusicList”是显示歌曲列表。

当点击第三个按钮“Combineexample1and2”时,就是本文想要达到的效果,如图3所示。

初始状态为图3左边,加载20个音乐;
当用手指向下拉动时,获得最新的10个,如图3中间所示;
当向上拉动时,加载之前的10个,如图3右边所示。





图2主程序





图3本文想要达到的效果:下拉或上拉,刷新最新或加载更多的歌曲列表


刚开始,若想实现这个功能,着实不易,主要是没思路。疑问在于,如何实现下拉和上拉?如何显示歌曲列表?又如何刷新最近、加载更多的歌曲列表?可你要是研究一下本程序前面的两个演示:example1和example2,这两个示例在网上很容易找到,那么,以上所有的问题,都迎刃而解了。






图4简单的下拉或上拉,刷新最新或加载更多

图4演示的核心代码如下所示:

packagecom.my.android.app.activity;
importjava.util.ArrayList;
importjava.util.Date;
importandroid.annotation.SuppressLint;
importandroid.app.Activity;
importandroid.os.Bundle;
importandroid.os.Handler;
importandroid.os.Message;
//importandroid.util.Log;
importandroid.view.View;
importandroid.widget.AdapterView;
importandroid.widget.AdapterView.OnItemClickListener;
importandroid.widget.ArrayAdapter;
importandroid.widget.RelativeLayout;
importandroid.widget.Toast;
importcom.my.android.app.R;
importcom.my.android.app.view.PushPullList;
importcom.my.android.app.view.PushPullListListener;
@SuppressLint("HandlerLeak")
publicclassPushPullListTestextendsActivityimplementsPushPullListListener{
PushPullListlist;
ArrayList<String>data;
ArrayAdapter<String>adapter;
//刷新控件状态
Handlerhandler=newHandler(){
@Override
publicvoidhandleMessage(Messagemsg){
if(msg.what==0){//刷新最新
adapter.notifyDataSetChanged();
list.doneRefresh();
Toast.makeText(PushPullListTest.this,
"新加载"+msg.arg1+"条数据!",Toast.LENGTH_LONG).show();
}elseif(msg.what==1){//加载更多
adapter.notifyDataSetChanged();
list.doneMore();
}else{
super.handleMessage(msg);
}
}
};
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pushpulllist);
//添加自定义控件
list=newPushPullList(this);
RelativeLayoutroot=(RelativeLayout)findViewById(R.id.root_a);
root.addView(list);
data=newArrayList<String>();
for(inti=1;i<10;++i){
data.add(newDate().toLocaleString());
}
adapter=newArrayAdapter<String>(this,
android.R.layout.simple_expandable_list_item_1,data);
list.setAdapter(adapter);
list.setOnItemClickListener(newOnItemClickListener(){
@Override
publicvoidonItemClick(AdapterView<?>arg0,Viewarg1,intarg2,
longarg3){
Toast.makeText(PushPullListTest.this,data.get(arg2-1),
Toast.LENGTH_LONG).show();
//Log.i("",data.get(arg2-1));
}
});
list.setDoMoreWhenBottom(false);//滚动到低端的时候不自己加载更多
list.setOnRefreshListener(this);//刷新最新的监听
list.setOnMoreListener(this);//加载更多的监听
}
@Override
publicbooleanonRefreshOrMore(PushPullListdynamicListView,
booleanisRefresh){
if(isRefresh){
newThread(r_refresh).start();
}else{
newThread(r_more).start();
}
returnfalse;
}
//刷新最新,插入前边
Runnabler_refresh=newRunnable(){
@Override
publicvoidrun(){
//下拉,刷新最新
ArrayList<String>temp=newArrayList<String>();
for(inti=0;i<3;++i){
temp.add(0,newDate().toLocaleString());
try{
Thread.sleep(1000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
synchronized(data){
data.addAll(0,temp);
}
Messagemessage=newMessage();
message.what=0;
message.arg1=temp.size();
handler.sendMessage(message);
}
};
//加载更多,插入末尾
Runnabler_more=newRunnable(){
@Override
publicvoidrun(){
//上拉,加载更多
ArrayList<String>temp=newArrayList<String>();
for(inti=0;i<3;++i){
temp.add(newDate().toLocaleString());
try{
Thread.sleep(1000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
synchronized(data){
data.addAll(temp);
}
handler.sendEmptyMessage(1);
}
};
}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}


图4主要是自定义了一个Listview,并继承android.widget.AbsListView.OnScrollListener接口,至于如何定义PushPullListListener和PushPullList,请自行下载源代码,这样就能实现上拉或下拉功能。通过上面代码,你就能了解基本的运行情况。

[align=left]onCreate方法,创建一个自定义ListView——PushPullList,并添加到页面,然后创建一个Adapter,用list.setAdapter设置该Adaper;[/align]

[align=left]onRefreshOrMore方法,是分别利用两个线程,下拉或上拉后,刷新最新或加载更多。[/align]





图5歌曲列表

图5核心代码如下所示:

packagecom.my.android.app.activity;
importjava.util.ArrayList;
importjava.util.HashMap;
importjava.util.List;
importjava.util.Map;
importandroid.app.Activity;
importandroid.os.Bundle;
importandroid.view.View;
importandroid.widget.AdapterView;
importandroid.widget.AdapterView.OnItemClickListener;
importandroid.widget.AdapterView.OnItemSelectedListener;
importandroid.widget.ListView;
importandroid.widget.SimpleAdapter;
importandroid.widget.Toast;
importcom.my.android.app.data.TestData;
importcom.my.android.app.R;
publicclassCustomListTestextendsActivity{
ListViewlist;
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_customlist);
//创建一个List集合,List集合的元素是Map
List<Map<String,Object>>listItems=newArrayList<Map<String,Object>>();
for(inti=0;i<TestData.artist.length;i++){
Map<String,Object>listItem=newHashMap<String,Object>();
listItem.put("thumb",TestData.thumb[i]);
listItem.put("artist",TestData.artist[i]);
listItem.put("title",TestData.title[i]);
listItem.put("duration",TestData.duration[i]);
listItems.add(listItem);
}
//创建一个SimpleAdapter
SimpleAdaptersimpleAdapter=newSimpleAdapter(this,listItems,
R.layout.list_row,newString[]{"artist","title","thumb",
"duration"},newint[]{R.id.artist,R.id.title,
R.id.imagethumb,R.id.duration});
list=(ListView)findViewById(R.id.mylist_a);
//为ListView设置Adapter
list.setAdapter(simpleAdapter);
//为ListView的列表项单击事件绑定事件监听器
list.setOnItemClickListener(newOnItemClickListener(){
//第position项被单击时激发该方法。
@Override
publicvoidonItemClick(AdapterView<?>parent,Viewview,
intposition,longid){
Toast.makeText(getApplicationContext(),
TestData.artist[position]+"被单击了",Toast.LENGTH_SHORT)
.show();
}
});
list.setOnItemSelectedListener(newOnItemSelectedListener(){
//第position项被选中时激发该方法。
@Override
publicvoidonItemSelected(AdapterView<?>parent,Viewview,
intposition,longid){
Toast.makeText(getApplicationContext(),
TestData.artist[position]+"被选中了",Toast.LENGTH_SHORT)
.show();
}
@Override
publicvoidonNothingSelected(AdapterView<?>parent){
}
});
/*
*list=(ListView)findViewById(R.id.mylist);adapter=new
*ComplexAdapter(this,TestData.thumb_url);list.setAdapter(adapter);
*/
/*
*Buttonb=(Button)findViewById(R.id.btn_clear_a);
*b.setOnClickListener(newOnClickListener(){
*
*@OverridepublicvoidonClick(Viewarg0){
*adapter.imageLoader.clearCache();adapter.notifyDataSetChanged();}
*});
*/
}
@Override
publicvoidonDestroy(){
list.setAdapter(null);
super.onDestroy();
}
}


注意上面代码段中Adapter。图5的目的是如何利用android.widget.SimpleAdapter在android.widget.ListView显示歌曲列表。



因此,若将图5的android.widget.ListView改为图4的自定义ListView,就能实现想要的功能,而且修改起来相当容易,只改一个地方。如果想实现更强大的功能,还可以继承android.widget.BaseAdapter自定义Adpater,本文只是使用SimpleAdapter。核心代码如下所示:


packagecom.my.android.app.activity;


importjava.util.ArrayList;

importjava.util.Date;

importjava.util.HashMap;

importjava.util.List;

importjava.util.Map;


importcom.my.android.app.R;

importcom.my.android.app.data.TestData;

importcom.my.android.app.view.PushPullList;

importcom.my.android.app.view.PushPullListListener;


importandroid.app.Activity;

importandroid.os.Bundle;

importandroid.os.Handler;

importandroid.os.Message;

importandroid.view.View;

importandroid.widget.AdapterView;

importandroid.widget.ArrayAdapter;

importandroid.widget.RelativeLayout;

importandroid.widget.SimpleAdapter;

importandroid.widget.Toast;

importandroid.widget.AdapterView.OnItemClickListener;

importandroid.widget.AdapterView.OnItemSelectedListener;


publicclassComplexListTestextendsActivityimplementsPushPullListListener{


PushPullListlist;

List<Map<String,Object>>listItems=null;

SimpleAdaptersimpleAdapter=null;

//ArrayAdapter<String>adapter;

intlen=TestData.artist.length;

intstep=10;


//刷新控件状态

Handlerhandler=newHandler(){

@Override

publicvoidhandleMessage(Messagemsg){

if(msg.what==0){//刷新最新

simpleAdapter.notifyDataSetChanged();

list.doneRefresh();

Toast.makeText(ComplexListTest.this,"新加载"+msg.arg1+"条数据!",

Toast.LENGTH_LONG).show();

}elseif(msg.what==1){//加载更多

simpleAdapter.notifyDataSetChanged();

list.doneMore();

}else{

super.handleMessage(msg);

}

}

};


@Override

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_complexlist);


//添加自定义控件

list=newPushPullList(this);

RelativeLayoutroot=(RelativeLayout)findViewById(R.id.root_b);

root.addView(list);


//创建一个List集合,List集合的元素是Map

listItems=newArrayList<Map<String,Object>>();

for(inti=0;i<TestData.artist.length;i++){

Map<String,Object>listItem=newHashMap<String,Object>();

listItem.put("thumb",TestData.thumb[i]);

listItem.put("artist",TestData.artist[i]);

listItem.put("title",TestData.title[i]);

listItem.put("duration",TestData.duration[i]);

listItems.add(listItem);

}

//创建一个SimpleAdapter

simpleAdapter=newSimpleAdapter(this,listItems,R.layout.list_row,

newString[]{"artist","title","thumb","duration"},

newint[]{R.id.artist,R.id.title,R.id.imagethumb,

R.id.duration});

//为ListView设置Adapter

list.setAdapter(simpleAdapter);


list.setOnItemClickListener(newOnItemClickListener(){

@Override

publicvoidonItemClick(AdapterView<?>arg0,Viewarg1,intarg2,

longarg3){

Toast.makeText(ComplexListTest.this,

listItems.get(arg2-1).toString(),Toast.LENGTH_LONG)

.show();

//Log.i("",data.get(arg2-1));

}

});


list.setDoMoreWhenBottom(false);//滚动到低端的时候不自己加载更多

list.setOnRefreshListener(this);//刷新最新的监听

list.setOnMoreListener(this);//加载更多的监听

}


@Override

publicvoidonDestroy(){

list.setAdapter(null);

super.onDestroy();

}


@Override

publicbooleanonRefreshOrMore(PushPullListdynamicListView,

booleanisRefresh){

if(isRefresh){

newThread(r_refresh).start();

}else{

newThread(r_more).start();

}

returnfalse;

}


//刷新最新,插入前边

Runnabler_refresh=newRunnable(){

@Override

publicvoidrun(){

//下拉,刷新最新

intpos=0;

List<Map<String,Object>>temp=newArrayList<Map<String,Object>>();

for(inti=len+1;i<=len+step;++i){

pos=i%TestData.artist.length;

Map<String,Object>item=newHashMap<String,Object>();

item.put("thumb",TestData.thumb[pos]);

item.put("artist",TestData.artist[pos]);

item.put("title",TestData.title[pos]);

item.put("duration",TestData.duration[pos]);

temp.add(item);

try{

Thread.sleep(1000);

}catch(InterruptedExceptione){

e.printStackTrace();

}

}

synchronized(listItems){

listItems.addAll(0,temp);

}

len=len+step;

Messagemessage=newMessage();

message.what=0;

message.arg1=temp.size();

handler.sendMessage(message);

}

};

//加载更多,插入末尾

Runnabler_more=newRunnable(){

@Override

publicvoidrun(){

//上拉,加载更多

intpos=0;

List<Map<String,Object>>temp=newArrayList<Map<String,Object>>();

for(inti=len+1;i<=len+step;++i){

pos=i%TestData.artist.length;

Map<String,Object>item=newHashMap<String,Object>();

item.put("thumb",TestData.thumb[pos]);

item.put("artist",TestData.artist[pos]);

item.put("title",TestData.title[pos]);

item.put("duration",TestData.duration[pos]);

temp.add(item);

try{

Thread.sleep(1000);

}catch(InterruptedExceptione){

e.printStackTrace();

}

}

synchronized(listItems){

listItems.addAll(0,temp);

}


len=len+step;

handler.sendEmptyMessage(1);

}

};

}


除了改变了Adapter外,其他代码都没有变化。



参考资料

Android自定义ListView上下拉动刷新最新和加载更多
AndroidListView和***Adapter从本地/网络获取歌曲列表
Android自定义ListView显示网络上JSON格式歌曲列表

下载Demo

下载Demov.1.1
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: