第四章 ListView使用技巧

ListView的使用範圍非常廣泛,儘管RecycleView在很多地方取代了ListView,但是ListView的地位還是難以撼動的。
那麼這一章節的知識點,將通過代碼的方式展示出來:

ListView的重要屬性

    <com.why.a4_listview.MyListView
        android:id="@+id/lv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        /**
         * 這兩個屬性控制分割線和分割線的高度,
         * android:divider="null"是把分割線設置爲了透明,也就是去掉了分割線
         **/
        android:divider="@android:color/darker_gray"
        /**
         * 取消進度條
         **/
        android:scrollbars="none"
        /**
         * 設置點擊listview的item的點擊效果,下面是使得點擊效果爲透明狀態,也就是取消了點擊效果
         **/
        android:listSelector="@android:color/transparent"
        >

    </com.why.a4_listview.MyListView>

ListView的使用

public class MainActivity extends Activity {

    private List<ChatItemListViewBean> mChatData;;

    private MyListView listView;
    private List<String> mData;
    private Toolbar mToolbar;
    private int mTouchSlop;
    private boolean mShow = true;
    private float mFirstY;
    private int direction;
    private Animator mAnimator;
    private View.OnTouchListener myTouchListener = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()){
                case MotionEvent.ACTION_DOWN:
                    Log.i("test", "ACTION_DOWN: ");
                    mFirstY = event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    Log.i("test", "ACTION_MOVE: ");
                    float currentY = event.getY();
                    if (currentY - mFirstY > 0){
                        //向下滑動
                        direction = 0;
                    }else if (mFirstY - currentY > 0){
                        //向上滑動
                        direction = 1;
                    }

                    if (direction == 1){
                        if (mShow){
                            toolbarAnim(0);//隱藏
                            mShow = !mShow;
                        }
                    }else if (direction == 0){
                        if (!mShow){
                            toolbarAnim(1);//顯示
                            mShow = !mShow;
                        }
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    Log.i("test", "ACTION_UP: ");
                    break;
            }
            return false;
        }
    };

    private void toolbarAnim(int flag) {
        if (mAnimator != null && mAnimator.isRunning()){
            mAnimator.cancel();
        }
        if (flag == 0){ //隱藏
            //效果一樣
            //mAnimator = ObjectAnimator.ofFloat(mToolbar, "translationY", 0, -mToolbar.getHeight());
            mAnimator = ObjectAnimator.ofFloat(mToolbar, "translationY", mToolbar.getTranslationY(), -mToolbar.getHeight());
        }else {  //顯示
            //mAnimator = ObjectAnimator.ofFloat(mToolbar, "translationY", -mToolbar.getHeight(), 0);
            mAnimator = ObjectAnimator.ofFloat(mToolbar, "translationY", mToolbar.getTranslationY(), 0);
        }
        mAnimator.start();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initChat();
    }

    private void initChat() {
        initToolBar();
        mToolbar.setVisibility(View.GONE);
        initChatData();
        listView = (MyListView) findViewById(R.id.lv);
        listView.setAdapter(new ChatListViewAdapter(getApplicationContext(), mChatData));
    }

    private void initText() {
        initToolBar();
        initData();
        textListView();
        initText();
    }


    private void initToolBar() {
        mToolbar = findViewById(R.id.toolbar);
    }

    private void initData() {
        mData = new ArrayList<>();
        for (int i=0; i<20; i++){
            mData.add(String.valueOf(i));
        }

        /**
         * 獲得系統認爲的最低的滑動距離
         */
        mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
    }

    private void textListView() {
        listView = (MyListView) findViewById(R.id.lv);
        listView.setAdapter(new ViewHolderAdapter(getApplicationContext(), mData));
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                /**
                 * 瞬間移動到 position 爲11的item上,position 爲11的item出現在第一行
                 */
                //listView.setSelection(11);
                /**
                 * 平滑移動到position爲20的item上,
                 *   但是當從上向下滑動的時候,20出現在屏幕的最後一行
                 *   從下向上滑動的時候,20出現在屏幕的第一行
                 */
                //listView.smoothScrollToPosition(20);
                /**
                 * -25是指向上移動25個item, 25是指向下移動25個item
                 */
                //listView.smoothScrollByOffset(25);
                /**
                 * 在2秒內向下移動500個px
                 */
                //listView.smoothScrollBy(500, 2000);
                /**
                 * 獲取第20個子view
                 */
                //View childView = listView.getChildAt(20);
            }
        });

        /**
         * 當listview爲空數據的時候,要顯示的佈局
         */
        if (mData.size() == 0){
            listView.setEmptyView(findViewById(R.id.iv_empty));
        }

        listView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                /**
                 * 可以根據用戶滑動的方向,並在不同的事件中進行相應的;邏輯處理
                 */
                switch (event.getAction()){
                    case MotionEvent.ACTION_DOWN:
                        break;
                    case MotionEvent.ACTION_MOVE:
                        break;
                    case MotionEvent.ACTION_UP:
                        break;
                }
                return false;
            }
        });

        listView.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                switch (scrollState){
                    /**
                     * 滑動停止
                     */
                    case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:
                        Log.i("test", "滑動停止---SCROLL_STATE_IDLE: ");
                        break;
                    /**
                     * 正在滑動
                     */
                    case SCROLL_STATE_TOUCH_SCROLL:
                        Log.i("test", "正在滑動---SCROLL_STATE_TOUCH_SCROLL: ");
                        break;
                    /**
                     * 手指用力滑動屏幕導致形成慣性的時候,此時手指離開屏幕後,listview由於慣性繼續滑動的時候走這裏
                     *  如果手指力道不能形成慣性,那麼當前方法只會調用兩次
                     *  如果足以形成慣性,會調用三次,而不是一直調用走這裏
                     */
                    case SCROLL_STATE_FLING:
                        Log.i("test", "慣性滑動---SCROLL_STATE_FLING: ");
                        break;
                }
            }

            /**
             * 滾動時一直調用該方法
             *   firstVisibleItem 當前能看到的第一個item的id(從0開始)
             *   visibleItemCount 當前能看到的item的總數(沒有顯示完全的item也包含在內)
             *   totalItemCount 整個listview的item總數
             */
            int lastVisibleItem;
            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                Log.i("test", "onScroll: ");
                /**
                 * 判斷是否到了最後一行
                 */
                if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0){
                    Log.i("test", "到底了: ");
                }

                if (firstVisibleItem > lastVisibleItem){
                    Log.i("test", "向上滑動: ");
                }else if (firstVisibleItem < lastVisibleItem){
                    Log.i("test", "向下滑動: ");
                }
                lastVisibleItem = firstVisibleItem;
            }
        });

        /**
         * 獲取可視區域內第一個item的position
         * 不滑動獲取到的值爲0
         */
        int firstVisiblePosition = listView.getFirstVisiblePosition();
        Log.i("test", "firstVisiblePosition: "+firstVisiblePosition);

        /**
         * 獲取可視區域內最後一個item的position
         * 沒有滑動的時候,得到的值爲-1,原因getChildCount()獲取到的值爲0
         */
        int lastVisiblePosition = listView.getLastVisiblePosition();
        Log.i("test", "最後一個item: "+lastVisiblePosition);

        addHeaderView();

        listView.setOnTouchListener(myTouchListener);
    }

    /**
     * 爲防止第一個元素被toolbar遮擋,應該添加頭部
     */
    private void addHeaderView() {
        View header = new View(this);
        header.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT,
                (int) getResources().getDimension(R.dimen.abc_action_bar_default_height_material)));
        listView.addHeaderView(header);
    }
}

ListView彈性效果的設置

當上滑到頭或者下滑到底的時候,需要有個彈性效果,下面自定義的 ListView 能夠達到一個簡易的彈性效果。

public class MyListView extends ListView {
    private int mMaxOverDistance = 300;

    public MyListView(Context context) {
        this(context, null);
    }

    public MyListView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initData(context);
    }

    /**
     * 滿足多分辨率的要求,根據屏幕density來計算具體的值
     * @param context
     */
    private void initData(Context context) {
        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
        float density = displayMetrics.density;
        mMaxOverDistance = (int) (density*mMaxOverDistance);
    }

    /**
     * 重寫該方法,在listview中maxOverScrollY的值默認爲0;
     *   我將修改爲mMaxOverDistance。使得listview滑動到邊界的時候,能夠有mMaxOverDistance長的彈性效果
     *
     *   這是比較簡單的一種增加彈性效果的方式
     */
    @Override
    protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
        return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, mMaxOverDistance, isTouchEvent);
    }
}
發佈了32 篇原創文章 · 獲贊 7 · 訪問量 4912
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章