Android ListView 페이지 기능 구현 방법

이번 데 모 를 통 해 배 웠 습 니 다.
1.ListView 의 작은 페이지 기능
2.사용자 정의 컨트롤 에 대한 이 해 를 강화 했다.
3.ListView 에 대한 최적화
4.BaseAdapter 사용
5.사용자 정의 어댑터
6.인터페이스의 반전
다음 효 과 를 실현 하려 면 ListView 의 끝까지 끌 때 ProgressBar 와'불 러 오 는 중...'의 TextView 를 표시 합 니 다.그리고 2 초 후에 아래 에 새로운 데 이 터 를 불 러 옵 니 다.프로젝트 의 디 렉 터 리 구조 와 프로그램 이 실현 하고 자 하 는 효 과 는 다음 과 같다.
                  
우선 레이아웃 부분:
이 효 과 를 실현 하기 위해 서 먼저 레이아웃 파일 에 footer 를 새로 만 들 었 습 니 다.layot.xml 레이아웃 파일:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical" >
 <LinearLayout 
  android:id="@+id/load_layout"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:orientation="horizontal"
  android:paddingTop="10dip"
  android:paddingBottom="10dip"
  android:gravity="center"
  >
  <ProgressBar 
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   style="?android:attr/progressBarStyleSmall"
   android:background="#ff0000"
   />
  <TextView 
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="    ..."
   />
  
 </LinearLayout>

</LinearLayout>
그리고 ListView 의 하위 항목 으로 사용 할 item.xml 을 새로 만 들 었 습 니 다:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical" >

 <TextView
  android:id="@+id/tv1"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="   " />
 <TextView 
  android:id="@+id/tv2"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="     "
 />
</LinearLayout>

마지막 으로 홈 레이아웃 파일 에 사용자 정의 ListView 컨트롤 을 추가 하 였 습 니 다.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 >

 <com.lx.loadListView.LoadListView
  android:id="@+id/list"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:layout_alignParentTop="true"
  android:layout_centerHorizontal="true"
  android:cacheColorHint="#00000000" >
 </com.lx.loadListView.LoadListView>

</RelativeLayout>
그리고 ListView 의 이러한 효 과 를 실현 하기 위해 서 는 사용자 정의 ListView 가 필요 합 니 다.위의 레이아웃 파일 에서 사용자 정의 ListView 를 참조 하 십시오.코드 는 다음 과 같 습 니 다.

package com.lx.loadListView;

import com.example.listviewloaddemo.R;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AbsListView;
import android.widget.ListView;
import android.widget.AbsListView.OnScrollListener;

public class LoadListView extends ListView implements OnScrollListener {

 View footer;
 int lastVisiableItem;//        Item
 int totalItemCount;// Item    
 boolean isLoading; //     
 ILoadListener iLoadListener;

 public LoadListView(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
  // TODO            
  initView(context);
 }

 public LoadListView(Context context, AttributeSet attrs) {
  super(context, attrs);
  // TODO            
  initView(context);
 }

 public LoadListView(Context context) {
  super(context);
  // TODO            
  initView(context);
 }

 /***
  *            listView
  * 
  * @param context
  */
 public void initView(Context context) {
  LayoutInflater inflater = LayoutInflater.from(context);
  footer = inflater.inflate(R.layout.footer_layout, null);
  //             
  footer.findViewById(R.id.load_layout).setVisibility(View.GONE);
  this.addFooterView(footer);
  this.setOnScrollListener(this);
 }

 @Override
 public void onScrollStateChanged(AbsListView view, int scrollState) {
  // TODO          
  //     Item        Item   ,       
  if (totalItemCount == lastVisiableItem
    && scrollState == SCROLL_STATE_IDLE) {
   if (!isLoading) {
    isLoading = true;
    footer.findViewById(R.id.load_layout).setVisibility(
      View.VISIBLE);
    //    
    iLoadListener.onLoad();
   }
  }
 }
 
 /**
 *firstVisibleItem      Item   
 *visibleItemCount    Item   
 *totalItemCount  Item    
 **/
 @Override
 public void onScroll(AbsListView view, int firstVisibleItem,
   int visibleItemCount, int totalItemCount) {
  // TODO          
  this.lastVisiableItem = firstVisibleItem + visibleItemCount;
  this.totalItemCount = totalItemCount;
 }

 //     footer  
 public void loadComplete(){
  isLoading=false;
  footer.findViewById(R.id.load_layout).setVisibility(View.GONE);
 }
 
 public void setInterface(ILoadListener iLoadListener) {
  this.iLoadListener = iLoadListener;
 }

 //          
 public interface ILoadListener {
  public void onLoad();
 }

}

사용자 정의 ListView 는 ListView 에서 계승 되 고 그 중의 부모 클래스 의 세 가지 구조 방법 을 실현 합 니 다.아래 에 우리 가 원 하 는 레이아웃 을 ListView 에 불 러 오기 위해 initView 방법 을 사용자 정의 하여 footer 를 찾 고 예화 하 는 데 사용 합 니 다.layot.xml 를 ListView 아래쪽 에 추가 합 니 다.부모 클래스 의 세 가지 구조 방법 에 초기 화 방법 인 initView()를 추가 하고,initView 방법의 마지막 에 ListView 의 addFooterView(View)방법 을 호출 하여 밑 에 있 는 레이아웃 을 추가 합 니 다.ListView 가 처음 불 러 왔 을 때 이 footer 를 표시 하고 싶 지 않 기 때문에 Visible 을 GONE 로 설정 해 야 합 니 다.ListView 를 끝까지 끌 어 올 리 려 면 footer 를 표시 합 니 다.ListView 의 OnScrollListener 인 터 페 이 스 를 실현 하고 부모 클래스 의 두 가지 방법 을 실현 해 야 합 니 다.OnScroll State Changed()방법 에서 끝까지 굴 러 갈 지 여 부 를 판단 합 니 다.STATE_IDLE)。
ListView 에 데 이 터 를 추가 하기 위해 실체 클래스 APK 를 정 의 했 습 니 다.Entity:

package com.lx.entity;

public class ApkEntity {

 private String name;
 private String info;
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getInfo() {
  return info;
 }
 public void setInfo(String info) {
  this.info = info;
 }
 
}

그 후에 저 희 는 ListView 에 데이터 어댑터 MyAdapter 를 정 의 했 습 니 다.BaseAdapter 에서 계승 하고 그 중의 네 가지 방법 을 실현 합 니 다.그 중에서 저 희 는 주로 데이터 의 충전 을 실현 합 니 다.

package com.lx.adapter;

import java.util.ArrayList;

import com.example.listviewloaddemo.R;
import com.lx.entity.ApkEntity;


import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class MyAdapter extends BaseAdapter {

 ArrayList<ApkEntity> list;
 LayoutInflater inflater;
 
 
 //        list       LayoutInflater
 public MyAdapter(Context context,ArrayList<ApkEntity> list) {
  this.list=list;
  this.inflater=LayoutInflater.from(context);
 }

 //  list   (         UI        ,         ListView     )
 @Override
 public int getCount() {
  // TODO          
  return list.size();
 }

 //  list      data(  ListView       View)
 @Override
 public Object getItem(int position) {
  // TODO          
  return list.get(position);
 }
 
 //  ListView           ID
 @Override
 public long getItemId(int position) {
  // TODO          
  return position;
 }

 //***   ,  ListView     
 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
  // TODO          
  // list     
  ApkEntity entity=list.get(position);
  //  ViewHolder          getView        findViewById()       
  ViewHolder holder;
  /**
   * convertView:The old View to reuses
   *              ,        
   */
  //          ,   convertView        LayoutInflate    
  if(convertView==null){
   holder=new ViewHolder();
   //    layout   View
   convertView=inflater.inflate(R.layout.item, null);
   holder.tv_name=(TextView) convertView.findViewById(R.id.tv1);
   holder.tv_info=(TextView) convertView.findViewById(R.id.tv2);
   convertView.setTag(holder);
  }else{
   holder=(ViewHolder) convertView.getTag();
  }
  holder.tv_name.setText(entity.getName());
  holder.tv_info.setText(entity.getInfo());
  return convertView;
 }
 
 class ViewHolder{
  TextView tv_name,tv_info;
 }
 
 //         ListView
 public void onDateChanged(ArrayList<ApkEntity> list){
  this.list=list;
  this.notifyDataSetChanged();
 }

}
이 사용자 정의 Adapter 에서 가장 중요 한 것 은 getView()방법 입 니 다.ListView 의 모든 레이아웃(어떻게 생 겼 는 지)을 결정 합 니 다.getView()방법 에서 ListView 의 운행 효율 을 최적화 시 키 기 위해 Item 이 생 성 될 때마다 findView ById()가 아 닌 컨트롤 을 예화 합 니 다.저 희 는 ViewHolder 의 내부 클래스 를 정의 하여 컨트롤 의 인 스 턴 스 를 캐 시 합 니 다.클래스 에서 Item 레이아웃 의 레이아웃 컨트롤 을 설명 합 니 다.getView()방법 은 매번 레이아웃 을 다시 불 러 오기 때문에 ListView 가 빠르게 굴 러 갈 때 성능 의 병목 이 됩 니 다.그래서 getView()방법 중의 convertView 인 자 를 사 용 했 습 니 다.이 인 자 는 이전에 불 러 온 레이아웃 을 캐 시 하여 나중에 다시 사용 할 수 있 도록 합 니 다.위의 코드 를 통 해 알 수 있 듯 이 convertView 가 비어 있 을 때 Layout Inflate 로 레이아웃 을 불 러 오고 Item 의 컨트롤 을 예화 하 며 View 의 setTag()방법 을 호출 하여 View Holder 대상 을 convertViewu 에 저장 합 니 다.이렇게 하면 convertView 가 비어 있 지 않 을 때 View 의 getTag()방법 을 직접 호출 하여 ViewHolder 를 직접 꺼 냅 니 다.그러면 모든 컨트롤 의 인 스 턴 스 가 ViewHolder 에 캐 시 되 어 매번 컨트롤 에 findViewById()를 할 필요 가 없습니다.
1.convertView 매개 변 수 를 사용 합 니 다.레이아웃 을 중복 불 러 오 는 것 을 피하 고 이전에 불 러 온 레이아웃 을 캐 시 합 니 다.
2.ViewHolder 사용:getView()를 사용 할 때마다 컨트롤 을 예화 하 는 것 을 피하 고 이 클래스 로 컨트롤 을 예화 하 는 캐 시 를 완성 합 니 다.
그리고 MainActivity 에서 LoadListView 에 대한 실례 화 와 Mydapter 의 실례 화 를 완성 하고 실체 클래스 에 데 이 터 를 추가 하여 adapter 와 ListView 가 데 이 터 를 채 울 수 있 도록 해 야 합 니 다.

package com.example.listviewloaddemo;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.lx.adapter.MyAdapter;
import com.lx.entity.ApkEntity;
import com.lx.loadListView.LoadListView;
import com.lx.loadListView.LoadListView.ILoadListener;

import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;

public class MainActivity extends Activity implements ILoadListener {

 private LoadListView lv;
 private ArrayList<ApkEntity> list=new ArrayList<ApkEntity>();
 private MyAdapter myAdapter;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  getDate();
  showListView(list);
  
 }

 private void getDate() {
  // TODO          
  for (int i = 0; i < 10; i++) {
   ApkEntity entity=new ApkEntity();
   entity.setName("  ");
   entity.setInfo("    pig");
   list.add(entity);
  } 
 }
 
 private void getOnLoadDate() {
  // TODO          
  for (int i = 0; i < 2; i++) {
   ApkEntity entity=new ApkEntity();
   entity.setName("  ");
   entity.setInfo("    dog");
   list.add(entity);
  } 
 }

 private void showListView(ArrayList<ApkEntity> list) { 
  if(myAdapter==null){ 
   lv = (LoadListView) findViewById(R.id.list);
   lv.setInterface(this);
   Log.d("SetInterface--->>", this.toString());
   myAdapter=new MyAdapter(this, list);
   lv.setAdapter(myAdapter);
  }else{
   myAdapter.onDateChanged(list);
  }
 }

 @Override
 public void onLoad() {
  // TODO          
  //                 ,     ListView (         ,              )
  Handler handler=new Handler();
  handler.postDelayed(new Runnable() { 
   @Override
   public void run() {
    // TODO          
    getOnLoadDate();
    showListView(list);
    //  ListView    
    lv.loadComplete();
   }
  }, 2000); 
 }

}
MainActivity 에서 주의해 야 할 것 은 바로 showListView()방법 입 니 다.이 방법 에서 adapter 가 비어 있 는 지 판단 하 였 습 니 다.adapter 가 비어 있 으 면 listview,정례 화 adapter 등 일련의 조작 을 예화 하 였 습 니 다.그렇지 않 으 면 MyAdapter 의 onDateChanged()방법 을 호출 합 니 다.(이 방법 은 Adapter 의 notifyDataSetChanged()방법 을 호출 합 니 다.이 방법 은 ListView 가 변 경 될 때 UI 를 업데이트 하 는 데 사 용 됩 니 다.)ListView 아래로 미 끄 러 지 는 것 을 감청 할 때 새로운 데 이 터 를 불 러 오기 때문에 LoadListView 클래스 에서 한 팀 의 MainActivity 리 셋 을 실현 하고 LoadListView 에 리 셋 인터페이스 ILoadListener()를 쓰 고 그 중에서 하나의 onLoad()방법 을 실현 하 며 MainActivity 에서 이 인 터 페 이 스 를 실현 하고 onLoad()방법 을 다시 쓰 며 그 중에서 실현 하고 자 하 는 다른 방법 을 실현 합 니 다.예 를 들 어 새 데이터 의 불 러 오기 와 UI 의 새로 고침 전시,마지막 으로 새로 고침 이 새 데 이 터 를 불 러 온 후 footer 를 숨 기 려 면 LoadListView 의 loadComplete()방법 을 실행 합 니 다.
이로써 전체 데모 의 학습 은 기본적으로 완성 되 었 고 그 중에서 일부 지식 은 잘 모른다.예 를 들 어 인터페이스의 리 셋,사용자 정의 컨트롤 부분 등 은 연습 을 깊이 해 야 한다.

좋은 웹페이지 즐겨찾기