本文用ListView實(shí)現(xiàn)了一個(gè)可以展示文本和圖片的類似聊天消息的界面组砚。包括ListView的優(yōu)化,ListView下拉到底部自動(dòng)刷新以及ListView常用屬性等知識(shí)。主要參考為網(wǎng)易微專業(yè)課程。其中布局文件都已經(jīng)省略。
效果如下:
IMG_20161013_092308.png
創(chuàng)建TextMessage類和ImageMessage類:
public class TextMessage {
private String text;
public TextMessage(String content) {
this.text = content;
}
public String getText() {
return text;
}
public class ImageMessage {
private int imgResId;
public ImageMessage(int imgResId) {
this.imgResId = imgResId;
}
public int getImgResId() {
return imgResId;
}
}
Adapter類
public class MainAdapter extends BaseAdapter {
private static final int VIEW_TYPE_COUNT = 2;
private interface ViewType {
// 必須從0開(kāi)始蒿叠,因?yàn)長(zhǎng)istView內(nèi)部是用一個(gè)數(shù)組維護(hù)ViewType的。
int TEXT = 0;
int IMAGE =1;
}
private ArrayList<Object> list;
private Context context;
public MainAdapter(Context context,ArrayList<Object> list) {
this.context = context;
this.list = list;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(context);
ViewHolder holder = null;
// 如果是文本消息
if (getItemViewType(position) == ViewType.TEXT){
if (convertView == null){
holder = new ViewHolder();
convertView=inflater.inflate(R.layout.text_item,parent,false);
holder.text = (TextView) convertView.findViewById(R.id.text);
convertView.setTag(holder);
}else {
holder = (ViewHolder) convertView.getTag();
}
TextMessage textMessage = (TextMessage) list.get(position);
holder.text.setText(textMessage.getText());
}else { //如果是圖片消息蚣常。
if (convertView==null){
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.image_item,parent,false);
holder.image = (ImageView) convertView.findViewById(R.id.image);
convertView.setTag(holder);
}else {
holder = (ViewHolder) convertView.getTag();
}
ImageMessage imageMessage = (ImageMessage) list.get(position);
holder.image.setImageResource(imageMessage.getImgResId());
}
return convertView;
}
@Override
public int getViewTypeCount() {
return VIEW_TYPE_COUNT ;
}
@Override
public int getItemViewType(int position) {
if (getItem(position) instanceof TextMessage){
return ViewType.TEXT;
}else {
return ViewType.IMAGE;
}
}
private static class ViewHolder{
ImageView image;
TextView text;
}
}
主界面
public class MainActivity extends AppCompatActivity {
Context context;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
ListView listView = (ListView) findViewById(R.id.list);
final ArrayList<Object> list = new ArrayList<>();
// 模擬數(shù)據(jù)市咽。
for (int i=0; i<100;i++){
if (i%2==0){
TextMessage textMessage = new TextMessage("我是文本消息");
list.add(textMessage);
}else {
ImageMessage imageMessage = new ImageMessage(R.drawable.image);
list.add(imageMessage);
}
}
final MainAdapter adapter = new MainAdapter(context,list);
listView.setAdapter(adapter);
// 為L(zhǎng)istView設(shè)置點(diǎn)擊事件
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String str = "item "+ position;
Toast.makeText(context,str, Toast.LENGTH_SHORT).show();
}
});
// 為L(zhǎng)istView設(shè)置滑動(dòng)監(jiān)聽(tīng)事件
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
Log.d("listener","onScrollStateChange scrollState: " + scrollState);
}
@Override
/**
* @param firstVisibleItem: the index of the first visible cell (ignore if visibleItemCount == 0)
* @param visibleItemCount: the number of visible cells
*/
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
// 如果滑到最底部,自動(dòng)加載新數(shù)據(jù)抵蚊。
if(firstVisibleItem+visibleItemCount == totalItemCount){
Toast.makeText(context, "加載新的數(shù)據(jù)", Toast.LENGTH_SHORT).show();
for (int i = 0 ; i< 100; i++){
TextMessage textMessage = new TextMessage("我是文本消息");
list.add(textMessage);
}
adapter.notifyDataSetChanged();
}
}
});
// 增加數(shù)據(jù)
Button add = (Button) findViewById(R.id.add_view);
add.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String time = Calendar.getInstance().getTime().toString();
list.add(0,new TextMessage(time));
// 通知adapter刷新數(shù)據(jù)施绎。
adapter.notifyDataSetChanged();
}
});
// 刪除數(shù)據(jù)
Button delete = (Button) findViewById(R.id.delete_view);
delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (list.size() > 0){
list.remove(0);
adapter.notifyDataSetChanged();
}
}
});
}
}
補(bǔ)充
- ListView 可以添加FootView、HeadView和EmptyView贞绳。此時(shí)要注意怎樣才能獲得正確的item(
parent.getItemAtPosition(position)
). - OnScrollListener監(jiān)聽(tīng)ListView三種狀態(tài)谷醉,分別是:
-
SCROLL_STATE_IDLE = 0
, 表示ListView停止滑動(dòng)。 -
SCROLL_STATE_TOUCH_SCROLL = 1
,表示ListView隨手指而滑動(dòng)冈闭。 -
SCROLL_STATE_FLING = 2
,表示手指已經(jīng)離開(kāi)屏幕俱尼,ListView隨慣性而滑動(dòng)。
注意 在ListView中萎攒,如果有一個(gè)focusable
屬性為true的控件(例如Button)遇八,會(huì)使onItemClickListenter
的點(diǎn)擊事件失效矛绘。通過(guò)以下方法就可以使點(diǎn)擊事件傳遞到子控件上。
- 在item的根布局里設(shè)置
android:descendantFocusability = "blocksDescendants"
屬性刃永。 - 在5.0以上的系統(tǒng)货矮,可以設(shè)置
android:touchscreenBlocksFoucus = true
屬性。 - 在該按鈕里設(shè)置
android:focusable = "false"
屬性斯够。
ListView其他屬性:
- 設(shè)置分隔條:
android:divider = "@android:color/darker_gray"
- 去除分隔條:
android:divider = "@null"
- 隱藏ListView滾動(dòng)條:
android:scrollbars = "none"
- 取消ListView的點(diǎn)擊效果:
android:listSelector = "@android:color/transparent"
- 設(shè)置ListView 顯示在第幾頁(yè):
listView.setSelection(n); //"n"表示第幾個(gè)item.
listView.smoothScrollBy(distance,duration);
listView.smoothScrollByOffset(offset);
listView.smoothScrollToPosition(index);
- 動(dòng)態(tài)修改ListView:
mData.add(newData);
mAdapter.notifyDataSetChanged();
- 設(shè)置ListView頂部和底部滑動(dòng)背景拉伸效果:
android:overScrollHeader = "@android:coloer/red"
android:overScrollFooter = "@android:coloer/red"
- 設(shè)置ListView頂部和底部漸變效果:
android:requireFadingEade = "vertical"
android:fadingEdgeLength = "100dp"
- 設(shè)置ListView從底部開(kāi)始布局:
android:stackFromBottom = "true"
- 設(shè)置ListView增加消息自動(dòng)滾動(dòng)到底部:
android:transcriptMode = "alwaysSrcoll"
源碼地址.