Android簡潔的下拉放大刷新

序言

國慶放假過后眼看一年又要過完了,年初指望著已經有一年的經驗本以為自己不是剛出校的學生以為翅膀已經硬了,打算辭職換新工作,一面試才發現自己就是個垃圾,什么oninterceptEvent,dispatchTouchEvent ,Aysnctask都不會。做了一年的項目也是用的Xutils2.6版本 還有一堆不常用不好的不主流不時尚的框架,技術也沒任何長進。還好公司真的輕松(所以也學不到任何東西)可以趁閑下來的時間多學點東西。于是寫了個簡單但也有需求的控件練練手。

首先先看效果圖吧

這個是listview的效果還有一個ScrollView的效果當然使用和實現時一樣的原理這里就一listview來講解,文末傳送門可以看到全部的代碼

效果圖.gif

1、具體使用

項目build.gradle

allprojects {
    repositories {
        jcenter()
        maven { url 'https://jitpack.io' }
    }
}

app model build.gradle

compile 'com.github.xypmhxy:PullZoomLayout:1.1'

布局文件中

<com.ren.pullzoom.widget.PullZoomLayout
        android:id="@+id/pull"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        app:image_height="200dp" 圖片高度
        app:image_res="@mipmap/timg" 圖片資源
        app:refresh_enable="true" 是否開啟刷新
        app:scale_type="center_crop">//圖片縮放方式

        <ListView
            android:id="@+id/listview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@android:color/white" />

    </com.ren.pullzoom.widget.PullZoomLayout>

2、實現思路

其思路很簡單
1.首先在構造方法中動態添加下拉縮放的imageView和刷新的refreshProgress(控件中為實現跟隨手指滑動旋轉因此使用的為imageView)
2.獲取到listview對象,然后監聽listview的滑動事件,判斷滑到頂部后繼續向下滑動的時候將需要放大的ImageView高度增加然后利用ImageView的Scale方法完成縮放。
3.最后放開手指的時候用屬性動畫讓imageView平滑回到最初狀態,并且如果開啟下拉刷新則回調其方法。

3、具體實現

1.動態添加兩個ImageView(下拉放大的和刷新的progress),大致原理就是將這兩個ImageView添加到RelativeLayout中然后將RelativeLayout 添加到自身中。代碼如下

/*實例化頭部布局包含pullZoomImage 和 refreshProgress*/
protected void init(Context context) {
        RelativeLayout head = new RelativeLayout(context);
        ViewGroup.LayoutParams headParams = new ViewGroup.LayoutParams(-1, -2);
        head.setLayoutParams(headParams);
        /*實例化pullZoomImage*/
      ·······
        pullZoomImage.setImageResource(imageRes);
        originalParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, imageHeight);
        pullZoomImage.setLayoutParams(originalParams);
        head.addView(pullZoomImage);
        /*實例化refreshProgress*/
        refreshProgress = new ImageView(context);
        refreshProgress.setVisibility(GONE);
        refreshProgress.setImageResource(R.drawable.refresh);
        RelativeLayout.LayoutParams refreshParams = new RelativeLayout.LayoutParams(dip2px(context, 35), dip2px(context, 35));
        refreshParams.addRule(RelativeLayout.ALIGN_PARENT_END, RelativeLayout.TRUE);
        refreshProgress.setLayoutParams(refreshParams);
        head.addView(refreshProgress);
        /*將頭部添加到此控件中*/
        addView(head, 0);
}

2.是獲取listview對象,因為listview屬于子控件所以不能在構造方法里直接獲取,因為此時控件不一定加載完成所以需要等待子控件加載完成后獲取因此在onFinishInflate方法中獲取

  @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        /*獲取listview*/
        if (getChildAt(1) instanceof ListView) {
            listView = (ListView) getChildAt(1);
            listView.setOnScrollListener(scrollListener);
            listView.setOnTouchListener(touchListener);
        }
    }

3.添加listview滑動監聽判斷是否滑動到頂部,可以開啟下拉放大功能

   /*listview滑動監聽*/
    protected AbsListView.OnScrollListener scrollListener = new AbsListView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            /*判斷是否滑動到頂部*/
            int firstVisibleItem = listView.getFirstVisiblePosition();
            if (firstVisibleItem == 0 && scrollState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
                View firstView = getChildAt(0);
                canZoom = firstView != null && firstView.getTop() == 0;
            } else
                canZoom = false;
        }

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        }
    };

4.實現OnTouchListener根據事件調用放大和縮小動畫,抬手時實現刷新等操作

/*listview touchListener監聽*/
    protected OnTouchListener touchListener = new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent ev) {
            if (pullZoomImage == null) return false;
            switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    pressY = ev.getY();//獲取按下的Y坐標
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (canZoom)//如果已經滑動到頂部并繼續滑動則開始放大pullZoomImage
                        return zoomView(ev);
                    break;
                case MotionEvent.ACTION_CANCEL:
                case MotionEvent.ACTION_UP:
                    if (canZoom)
                        restroe();//還原pullZoomImage動畫
                    if (needRefresh && refreshListener != null) {//達到刷新條件并且實現刷新監聽
                        refreshListener.onRefresh();
                        rotationProgress();//刷新時progress旋轉動畫
                    } else
                        refreshProgress.setVisibility(GONE);
                    //重置變量
                    needRefresh = false;
                    canZoom = false;
                    break;

            }
            return false;
        }
    };

縮放imageview

   /*放大pullZoomImage*/
    protected boolean zoomView(MotionEvent ev) {
        float offY = ev.getY() - pressY;
        if (offY <= 0 || offY < 16)//滑動方向上滑或者滑動距離小于16則不管
            return false;
        /*如果開啟下拉刷新判斷滑動距離是否大于refrshSlop則顯示refreshProgress*/
        if (refreshEnable) {
            needRefresh = offY >= refrshSlop;
            if (needRefresh)
                refreshProgress.setVisibility(VISIBLE);
        }
        ViewGroup.LayoutParams params = pullZoomImage.getLayoutParams();
        float height = originalParams.height + offY / damp;//根據滑動距離增加pullZoomImage的高度
        params.height = (int) height;
        scaleImage(height);//放大圖片
        rotationProgress(offY);//旋轉refreshProgress
        if (params.height >= originalParams.height)
            pullZoomImage.setLayoutParams(params);//為pullZoomImage設置改變后的params
        return true;
    }
    /*縮放imageview*/
    protected void scaleImage(float height) {
//        if (pullZoomImage.getScaleType() == ImageView.ScaleType.CENTER_CROP)
//            return;
        float scale = (height - originalParams.height) / originalParams.height;//根據滑動的大小判斷縮放比例
        pullZoomImage.setScaleX(1 + scale);
        pullZoomImage.setScaleY(1 + scale);
    }

抬手后通過屬性動畫還原pullZoomImage

 /*放開后還原pullZoomImage*/
    protected void restroe() {
        ValueAnimator animator = ValueAnimator.ofFloat(pullZoomImage.getLayoutParams().height, originalParams.height);// 動畫更新的監聽
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator arg0) {
                float height = (float) arg0.getAnimatedValue();// 獲取動畫當前變化的值
                // 根據最新高度,更新布局高度
                ViewGroup.LayoutParams params = pullZoomImage.getLayoutParams();
                params.height = (int) height;
                scaleImage(height);
                pullZoomImage.setLayoutParams(params);
            }
        });
        animator.setDuration(200);// 動畫時間
        animator.start();// 開啟動畫
    }

大致原理就是這樣最后傳送門開啟 PullZoomLayout

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,264評論 25 708
  • 內容抽屜菜單ListViewWebViewSwitchButton按鈕點贊按鈕進度條TabLayout圖標下拉刷新...
    皇小弟閱讀 46,884評論 22 665
  • 六點半,運動的時間,不得已還要在實驗室里等待融化中的RNA. 我脫掉鞋子,躺在空無一人的實驗室,感覺很累,卻睡不著...
    新秋的向日葵屋閱讀 277評論 2 0
  • “喜歡一個人,會卑微到塵埃里,然后開出花來。”———張愛玲 有人說:當你愛上一個人時,那就意味著你把傷害你的權利親...
    Lucky男孩閱讀 504評論 0 0
  • 祖明看著曾經的照片,微微一嘆。這是那場事故的第5個年頭了,看著照片里昔日的親人,曾經的歡聲笑語。仿佛一把刀插入心中...
    雨還是雨閱讀 187評論 0 0