Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> ListView的私人訂制

ListView的私人訂制

編輯:關於Android編程

現在開發中Android RecyclerView可能用的比較多,不過ListView作為常用控件學習它的使用和擴展也是十分重要的。簡單封裝了一個下拉刷新和上拉加載的ListView,你是否也想有個私人訂制的ListView呢?或許這篇文章能夠幫到你,如有問題懇請指正!歡迎評論哦!

效果圖:

 

由於電腦和模擬器的原因可能不太清晰及略卡頓,真機上則很清晰及流暢。

1、自定義ListView

直接上代碼

/**
 * Created by magic on 2016年5月12日.帶下拉刷新/上拉加載的listview
 */
public class PullDownRefurbishLoadListView extends ListView implements
        OnScrollListener, OnClickListener {

    /**
     * head view
     */
    private View headView;
    /**
     * head view height
     */
    private int headViewHeight;
    /**
     * 是否可以下滑刷新
     */
    private boolean isPullDownRefurbish = false;
    /**
     * 文本狀態描述
     */
    private TextView tev_status;
    /**
     * 進度條
     */
    private ImageView progressBar;
    /**
     * foot view
     */
    private View footView;
    /**
     * foot view height
     */
    private int footViewHeight;
    /**
     * 是否可以上拉加載
     */
    private boolean isPullHighLoad = false;
    /**
     * 底部布局
     */
    LinearLayout layout_listviewFoot;
    /**
     * 底部文本狀態描述
     */
    private TextView tev_status_foot;
    /**
     * 進度條
     */
    ImageView progressBar_foot;
    /**
     * 按下後的初始Y位置
     */
    private float beginY = 0;
    /**
     * 移動的距離
     */
    private int moveY = 0;
    /**
     * 正常狀態
     */
    private final static int NONE = 0;
    /**
     * 下拉/上拉狀態
     */
    private final static int PULL = 1;
    /**
     * 釋放刷新狀態
     */
    private final static int RELEASE = 2;
    /**
     * 刷新狀態
     */
    private final static int REFURBISH = 3;
    /**
     * 狀態
     */
    private static int STATUS;
    /**
     * 是否允許下拉刷新
     */
    private boolean isRefurbishAble = true;
    /**
     * 是否允許上拉加載
     */
    private boolean isLoadAble = true;
    /**
     * context
     */
    private Context context;
    /**
     * 動畫
     */
    private RotateAnimation rotateAnimation, rotateAnimation2;
    /**
     * 接口
     */
    private IPullDownRefurbishLoadListView refurbishLoadListView;

    public PullDownRefurbishLoadListView(Context context) {
        super(context);
        init(context);
    }

    public PullDownRefurbishLoadListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public PullDownRefurbishLoadListView(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    /**
     * 添加head/foot布局
     * 
     * @param context
     */
    private void init(Context context) {
        headView = LayoutInflater.from(context).inflate(R.layout.listview_head,
                null);
        this.addHeaderView(headView);
        // 設置滑動監聽
        this.setOnScrollListener(this);
        headView.measure(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
        headViewHeight = headView.getMeasuredHeight();
        // 設置headView 偏移出屏幕
        headView.setPadding(0, -headViewHeight, 0, 0);

        tev_status = (TextView) findViewById(R.id.tev_listviewHead_status);
        progressBar = (ImageView) findViewById(R.id.prb_listviewHead_refurbish);

        footView = LayoutInflater.from(context).inflate(
                R.layout.listview_footer, null);
        this.addFooterView(footView);
        footView.measure(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
        footViewHeight = footView.getMeasuredHeight();

        layout_listviewFoot = (LinearLayout) footView
                .findViewById(R.id.layout_listviewFoot);
        tev_status_foot = (TextView) footView
                .findViewById(R.id.tev_listviewFoot_state);
        progressBar_foot = (ImageView) findViewById(R.id.prb_listviewFoot_load);
        tev_status_foot.setOnClickListener(this);
        this.context = context;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:

            beginY = ev.getY();

            if (STATUS == REFURBISH) {
                // 不消耗事件
                return false;
            }

        case MotionEvent.ACTION_MOVE:

            this.moveY = (int) (ev.getY() - beginY);

            if (isRefurbishAble && isPullDownRefurbish && moveY >= 0) {
                if (moveY > 0) {
                    if (moveY > headViewHeight) {
                        STATUS = RELEASE;
                        if (moveY >= (headViewHeight + dp2px(20, context))) {
                            moveY = headViewHeight + dp2px(20, context);
                        }
                    } else if (moveY > 0 && moveY <= headViewHeight) {
                        STATUS = PULL;
                    } else {
                        STATUS = NONE;
                    }
                    setRefurbishByStatus((int) moveY);
                }
            }

            if (isLoadAble && isPullHighLoad && moveY < 0) {
                tev_status_foot.setVisibility(View.GONE);
                progressBar_foot.setVisibility(View.VISIBLE);
                if (Math.abs(moveY) > footViewHeight) {
                    STATUS = RELEASE;
                } else if (Math.abs(moveY) > 0
                        && Math.abs(moveY) <= footViewHeight) {
                    STATUS = PULL;
                } else {
                    STATUS = NONE;
                }
            }

            break;

        case MotionEvent.ACTION_UP:
            if (isRefurbishAble && isPullDownRefurbish && moveY >= 0) {
                switch (STATUS) {
                case PULL:
                    moveY = 0;
                    setRefurbishByStatus(-headViewHeight);
                    break;
                case RELEASE:
                    STATUS = REFURBISH;
                    setRefurbishByStatus((int) moveY);
                    if (refurbishLoadListView != null) {
                        refurbishLoadListView.refurbish();
                    }
                    break;

                }
            }

            if (isLoadAble && isPullHighLoad && moveY < 0) {
                switch (STATUS) {
                case PULL:
                    moveY = 0;
                    STATUS = NONE;
                    tev_status_foot.setVisibility(View.VISIBLE);
                    progressBar_foot.setVisibility(View.GONE);
                    break;
                case RELEASE:
                    STATUS = REFURBISH;
                    progressBar_foot.clearAnimation();
                    if (rotateAnimation2 != null) {
                        rotateAnimation2.cancel();
                    }
                    setAnimationToProgressBarFoot();
                    break;
                }
            }
            break;
        }
        return super.onTouchEvent(ev);
    }

    /**
     * 設置head布局的上內邊距
     * 
     * @param size
     */
    private void setHeadPaddingTop(int size) {
        size = size + (-headViewHeight);
        headView.setPadding(0, size, 0, 0);
    }

    /**
     * 根據狀態設置刷新HeadView顯示的內容
     */
    private void setRefurbishByStatus(int moveY) {
        switch (STATUS) {
        case NONE:
            tev_status.setText("下拉刷新");
            progressBar.setImageResource(R.drawable.ic_ptr_pull);
            setHeadPaddingTop(-headViewHeight);
            break;
        case PULL:
            tev_status.setText("下拉刷新");
            progressBar.setImageResource(R.drawable.ic_ptr_pull);
            setHeadPaddingTop(moveY);
            break;
        case RELEASE:
            tev_status.setText("釋放刷新");
            progressBar.setImageResource(R.drawable.ic_ptr_release);
            setHeadPaddingTop(moveY);
            break;
        case REFURBISH:
            tev_status.setText("刷新中");
            progressBar.setImageResource(R.drawable.ic_ptr_loading);
            setHeadPaddingTop(headViewHeight);

            if (rotateAnimation == null) {
                rotateAnimation = new RotateAnimation(0.0f, 180.0f,
                        Animation.RELATIVE_TO_SELF, 0.5f,
                        Animation.RELATIVE_TO_SELF, 0.5f);
                rotateAnimation.setDuration(150);
                rotateAnimation.setRepeatCount(-1);
            }
            progressBar.setAnimation(rotateAnimation);
            rotateAnimation.start();
            break;
        }
    }

    /**
     * 設置對外公開接口
     * 
     * @param pullDownRefurbish
     */
    public void setIPullDownRefurbish(
            IPullDownRefurbishLoadListView refurbishLoadListView) {
        this.refurbishLoadListView = refurbishLoadListView;
    }

    /**
     * 刷新完成執行
     */
    public void setPullDownRefurbishFinish() {
        moveY = 0;
        STATUS = NONE;
        setRefurbishByStatus((int) moveY);
        progressBar.clearAnimation();
        rotateAnimation.cancel();
    }

    /**
     * 加載完成執行
     */
    public void setPullDownLoadFinish() {
        moveY = 0;
        STATUS = NONE;
        progressBar_foot.clearAnimation();
        rotateAnimation2.cancel();
        progressBar_foot.setVisibility(View.GONE);
        tev_status_foot.setVisibility(View.VISIBLE);
    }

    /**
     * 設置是否允許下拉刷新
     * 
     * @param isRefurbishAble
     */
    public void setRefurbishAble(boolean isRefurbishAble) {
        this.isRefurbishAble = isRefurbishAble;
    }

    /**
     * 設置是否可以上拉加載
     * 
     * @param isLoadAble
     */
    public void setLoadAble(boolean isLoadAble) {
        this.isLoadAble = isLoadAble;
        if (!isLoadAble) {
            layout_listviewFoot.setVisibility(View.GONE);
        }
    }

    @Override
    public void onScroll(AbsListView arg0, int arg1, int arg2, int arg3) {
        // 參數:
        // 查看其滾動狀態的視圖
        // firstvisibleitem -第一個可見的細胞指數(忽略如果visibleitemcount = = 0)
        // visibleitemcount -可見細胞數
        // totalitemcount -在列表適配器項目數

        // arg1為0時 列表在最頂部
        isPullDownRefurbish = arg1 == 0 ? true : false;
        // arg1為最後一個時arg1==arg3
        isPullHighLoad = (arg1 + arg2) == arg3 ? true : false;
    }

    @Override
    public void onScrollStateChanged(AbsListView arg0, int arg1) {
    }

    /**
     * dp轉px
     */
    private int dp2px(float value, Context context) {
        final float scale = context.getResources().getDisplayMetrics().densityDpi;
        return (int) (value * (scale / 160) + 0.5f);
    }

    /**
     * 為progressBar_foot設置動畫
     */
    private void setAnimationToProgressBarFoot() {
        if (rotateAnimation2 == null) {
            rotateAnimation2 = new RotateAnimation(0.0f, 180.0f,
                    Animation.RELATIVE_TO_SELF, 0.5f,
                    Animation.RELATIVE_TO_SELF, 0.5f);
            rotateAnimation2.setDuration(150);
            rotateAnimation2.setRepeatCount(-1);
        }
        progressBar_foot.setAnimation(rotateAnimation2);
        rotateAnimation2.start();
        if (refurbishLoadListView != null) {
            refurbishLoadListView.load();
        }
    }

    @Override
    public void onClick(View v) {
        // 點擊查看更多
        tev_status_foot.setVisibility(View.GONE);
        progressBar_foot.setVisibility(View.VISIBLE);
        setAnimationToProgressBarFoot();
    }

    /**
     * 接口
     */
    interface IPullDownRefurbishLoadListView {
        /**
         * 刷新事件回調
         */
        void refurbish();

        /**
         * 加載回調
         */
        void load();
    }

}

以上代碼主要步驟:

初始化的時候添加HeadView、FootView。 繼承ListView實現OnScrollListener接口,重寫onScroll方法,因為onScroll方法在ListView滑動的時候會一直回調,因此在onScroll方法中判斷是否處於ListView的頂部/底部,從而處理下拉刷新/上拉加載的展現時機。 重寫onTouchEvent方法,在按下、滑動、抬起的時候動態處理HeadView、FootView的展現。

添加回調接口,設置回調方法。

注釋比較清楚,不在贅述。

2、xml文件

主布局




    

layout/listview_head.xml




    

        

        
    

listview_footer.xml




    

        

        
    

3、Activity中使用

/**
 * Created by magic on 2016年5月12日.帶下拉刷新/上拉加載的listview
 */
public class MainActivity extends Activity implements OnItemClickListener {

    PullDownRefurbishLoadListView listView;
    MyAdapter adapter;
    List list = new ArrayList();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        listView = (PullDownRefurbishLoadListView) findViewById(R.id.listview);
        list.add("a");
        adapter = new MyAdapter(this, list);
        listView.setAdapter(adapter);
        listView.setOnItemClickListener(this);
        //設置是否可以下拉刷新,默認為true
        listView.setRefurbishAble(true);
        //設置是否可以上拉加載,默認為true
        listView.setLoadAble(true);

        listView.setIPullDownRefurbish(new IPullDownRefurbishLoadListView() {

            @Override
            public void refurbish() {
                new Handler().postDelayed(new Runnable() {

                    @Override
                    public void run() {
                        list.add(0, "c");
                        adapter.notifyDataSetChanged();
                        listView.setPullDownRefurbishFinish();
                    }
                }, 2000);
            }

            @Override
            public void load() {
                new Handler().postDelayed(new Runnable() {

                    @Override
                    public void run() {
                        list.add("b");
                        adapter.notifyDataSetChanged();
                        listView.setPullDownLoadFinish();
                    }
                }, 2000);
            }
        });
    }

    @Override
    public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) {
        Toast.makeText(this, "Hello  " + arg2, Toast.LENGTH_SHORT).show();
    }
}

Adapter比較簡單就不寫了!

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved