1. 程式人生 > >Android高仿秒拍熱榜的卡片滑動和左右飛出效果--SwipeCardsView

Android高仿秒拍熱榜的卡片滑動和左右飛出效果--SwipeCardsView

來由

之所以做這個效果是因為專案中有這個效果需要實現。

  • 一開始我有在github上找到不少類似的庫,但是發現放在專案中會發現要麼有鋸齒,要麼就是卡頓,總之就是效果不好,其實絕大多數的庫都和Swipecards差不多,做法是重寫了adapterview,然後設定監聽,在監聽裡做移動和縮放。移動用的是設定view的x和y座標,這樣做法的弊端是會頻繁觸發view樹重繪,效率不高。
  • 後來發現這個庫android-card-slide-panel,它的做法是重寫了viewgroup,裡面view的數目是固定的,卡片的滑動是通過viewDragHelper來做的,沒有鋸齒同時也不卡頓了,但是viewDragHelper有問題:
    1、在多個手指同時滑動的時候會有概率出現pointIndex out of range異常,這個問題倒沒什麼,我通過修改viewDragHelper的原始碼已經解決了這個問題;
    2、當用picasso或者glide載入圖片以後,在手指拖動卡片的過程中有時會莫名的收到MotionEvent的UP事件,導致卡片回到了初始位置,這個問題折騰了我半天,後來的解決辦法是棄用了viewDragHelper,直接使用Scroller。
    3、還有一點要吐槽下,這個庫的使用太麻煩了,耦合太重,整合到專案裡比較費事。

效果圖



本來還有幾個效果圖的,但是被csdn給刪了,所以如果想要瀏覽更多,請點我瀏覽更多效果圖

特點

  1. 如絲般順滑,這是同事體驗過後的評價;
  2. 靈活,可以通過設定幾個屬性,很容易就能定製可視卡片的數量和卡片的疊加垂直偏移量、縮放比例,透明度比例;
  3. 使用方便,直接setadapter就可以使用了,資料更新呼叫swipeCardsView.notifyDatasetChanged(mList);就行了,下面有使用說明。

Gradle

dependencies {
   compile 'com.huxq17.android:SwipeCardsView:0.0.5'
//依賴下面的庫 compile 'com.android.support:appcompat-v7:23.0.1' }

Example

xml:

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:card="http://schemas.android.com/apk/res-auto"
    android:layout_width
="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true">
<com.huxq17.swipecardsview.SwipeCardsView android:id="@+id/swipCardsView" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#f3f3f3" card:alphaOffsetStep="40" card:scaleOffsetStep="0.08" card:yOffsetStep="20dp" /> ...省略部分程式碼... </android.support.design.widget.CoordinatorLayout>

對card中屬性的解釋:

<declare-styleable name="SwipCardsView">
        <!-- yOffsetStep定義的是卡片之間在y軸方向上的偏移量,單位是dp,
        舉個例子,可見的卡片有3個,如果步長是20dp,從前往後看,卡片y軸座標會依次增加20dp,表現上就是後面一張卡片底部有20dp會露出來
        如果值是負的,如 -20dp,那麼表現則相反。
         如果不需要對卡片進行y軸方向上的偏移量處理,不設定這個屬性或者設定為0dp就可以了-->
        <attr name="yOffsetStep" format="dimension" />
        <!-- alpha定義的取值範圍是0-100,所以alpha的步長也得在這個範圍之內,
        舉個例子,可見的卡片有3個,如果步長是40,那麼最前面的alpha是100,後面一點的是60,最後面的是20
         如果不需要對卡片進行透明度處理,不設定這個屬性或者設定為0就可以了-->
        <attr name="alphaOffsetStep" format="integer" />
        <!-- scale定義的取值範圍是0-1,所以scale的步長也得在這個範圍之內,
        舉個例子,可見的卡片有3個,如果步長是0.08,那麼最前面的alpha是1,後面一點的是0.92,最後面的是0.84
        值得注意的是 x 和 y同時被縮放了(1 - scaleStep*index)
        如果不需要對卡片進行縮放處理,不設定這個屬性或者設定為0就可以了-->
        <attr name="scaleOffsetStep" format="float" />
    </declare-styleable>

adapter:

1、抽象類

public abstract class BaseCardAdapter<T> {
   /**
        * 獲取卡片的數量
        *
        * @return
     */
     public abstract int getCount();


    /**
     * 獲取卡片view的layout id
     *
     * @return
     */
    public abstract int getCardLayoutId();

    /**
     * 將卡片和資料繫結在一起
     *
     * @param position 資料在資料集中的位置
     * @param cardview 要繫結資料的卡片
     * @param data     資料集中對應位置的資料
     */
    public abstract void onBindData(int position, View cardview, T data);

    /**
     * 獲取可見的cardview的數目,預設是3
     * @return
     */
    public int getVisibleCardCount() {
        return 3;
    }
}

2、實現

public class MeiziAdapter extends BaseCardAdapter {
    private List<ContentBean> datas;
    private Context context;

    public MeiziAdapter(List<ContentBean> datas, Context context) {
        this.datas = datas;
        this.context = context;
    }

    @Override
    public int getCount() {
        return datas.size();
    }

    @Override
    public int getCardLayoutId() {
        return R.layout.card_item;
    }

    @Override
    public void onBindData(int position, View cardview) {
        if (datas == null || datas.size() == 0) {
            return;
        }
        ImageView imageView = (ImageView) cardview.findViewById(R.id.iv_meizi);
        ContentBean meizi = datas.get(position);
        String url = meizi.getUrl();
        Picasso.with(context).load(url).config(Bitmap.Config.RGB_565).into(imageView);
    }

    /**
     * 如果可見的卡片數是3,則可以不用實現這個方法
     * @return
     */
    @Override
    public int getVisibleCardCount() {
        return super.getVisibleCardCount();
    }
}

activity or fragment:

    /**
     * 卡片向左邊飛出
     */
    public void doLeftOut() {
        swipeCardsView.slideCardOut(SwipeCardsView.SlideType.LEFT);
    }

    /**
     * 卡片向右邊飛出
     */
    public void doRightOut() {
        swipeCardsView.slideCardOut(SwipeCardsView.SlideType.RIGHT);
    }

    /**
     * 從頭開始,重新瀏覽
     */
    public void doRetry() {
        //必須先改變adapter中的資料,然後才能由資料變化帶動頁面重新整理
        if (mList != null) {
            adapter.setData(mList);
            swipeCardsView.notifyDatasetChanged(0);
        }

    /**
     * 顯示cardsview
     */
    private void show() {
        if (adapter == null) {
            adapter = new MeiziAdapter(mList, getActivity());
            swipeCardsView.setAdapter(adapter);
        } else {
            //if you want to change the UI of SwipeCardsView,you must modify the data first
           adapter.setData(mList);
           swipeCardsView.notifyDatasetChanged(curIndex);
        }
    }

      ...省略部分程式碼...
        swipeCardsView = (SwipeCardsView) container.findViewById(R.id.swipCardsView);
       //設定滑動監聽
        swipeCardsView.setCardsSlideListener(new SwipeCardsView.CardsSlideListener() {
            @Override
            public void onShow(int index) {
                LogUtils.i("test showing index = "+index);
            }

            @Override
            public void onCardVanish(int index, SwipeCardsView.SlideType type) {
                String orientation = "";
                switch (type){
                    case LEFT:
                        orientation="向左飛出";
                        break;
                    case RIGHT:
                        orientation="向右飛出";
                        break;
                }
            }

            @Override
            public void onItemClick(View cardImageView, int index) {
                toast("點選了 position="+index);
            }
        }); 

經驗總結

  1. 用removeView和addView是會觸發view樹重繪的,而用removeViewInLayout和addViewInLayout則不會。通過設定view的x y座標來移動view不是一個好的選擇,道理也一樣,應該使用offsetTopAndBottom和offsetLeftAndRight;
  2. ViewDragHelper是有問題的,上面有說明,儘量使用Scroller完成任務;
  3. 其實很多經驗都在程式碼裡,挨個拿出來說也不現實,點選獲取SwipeCardsView的原始碼,如果感覺不錯,那就給個star唄,萬分感謝!

相關推薦

Android仿卡片滑動左右效果--SwipeCardsView

來由 之所以做這個效果是因為專案中有這個效果需要實現。 一開始我有在github上找到不少類似的庫,但是發現放在專案中會發現要麼有鋸齒,要麼就是卡頓,總之就是效果不好,其實絕大多數的庫都和Swip

android仿今日頭條小視訊轉場切換效果

可以先看看今日頭條效果 功能分析 點選列表上的一個item,該item會放大,最後直接全屏播放小視訊,剛開始看上去,以為是個共享元素的轉場動畫, 後來想到,共享元素要在android 5.0以上支援,而今日頭條顯然不會只支援5.0版本以上 筆者想到的一種方案就是進入Acti

android仿京東快報(垂直迴圈滾動新聞欄)

京東的垂直滾動新聞欄的實現原理: 就是一個自定義的LinearLayout,並且textView能夠迴圈垂直滾動,而且條目可以點選,顯示區域最多顯示2個條目,並且還有交替的屬性垂直移動的動畫效果,通過執行緒來控制滾動的實現。 不多說看效果:

android仿微信表情輸入與鍵盤輸入詳解-解決跳閃與表情切換問題

private void unlockContentHeightDelayed() { mEditText.postDelayed(new Runnable() { @Override public void run() { ((LinearLa

Android仿京東淘寶商品列表佈局切換效果

商品列表佈局切換效果很常見,因為淘寶京東有的介面下面很多公司都會給風模仿 當然,我們公司也不例外,最近版本更新添加了這個功能; 在專案中直接使用RecyclerView實現切換功能; 如果不瞭解RecyclerView的可以先看下:  RecyclerView使用詳解

Android 仿【優酷】圓盤旋轉選單的實現(轉載)

目前,使用者對安卓應用程式的UI設計要求越來越高,因此,掌握一些新穎的設計很有必要. 比如選單,傳統的選單已經不能滿足使用者的需求. 其中優酷中圓盤旋轉選單的實現就比較優秀,這裡我提供下我的思路及實現,僅供參考. 不過在這裡個人認為點選home圖示關閉

Android 仿 QQ5.0 側滑選單效果 自定義控制元件來襲

上一篇部落格帶大家實現了:Android 自定義控制元件打造史上最簡單的側滑選單 ,有兄弟看了以後說,你這滑動選單過時了呀~QQ5.0的效果還不錯~~嗯,的確,上一篇也承諾過,稍微修改上一篇的程式碼,實現QQ5.0側滑選單~~好了,下面就開始為大家展示寫一個類QQ的側滑有多e

Android 仿74款APP

Github搜尋就有了 ----------------------------------------------------------------------------------------------------------------------------

Android仿QQ下拉重新整理

此次牽扯到的知識點有:Android手勢,Handler,java多執行緒,java聚合,Android幀動畫,屬性動畫; 如果有對上述提到過的知識點不太瞭解,或者程式設計能力較差的小夥伴可以關閉此頁面啦一,因為接下來的裝逼過程 你可能會是一臉懵B 。如果你執意要看也沒事啦,因

android仿抖音、點餐介面、天氣專案、自定義view指示、爬取美女圖片等原始碼

Android精選原始碼 Android優質部落格 簡介最近東西寫的挺多的,這不又要弄一個類似於京東的地址選擇器,然後剛開

Android 仿知乎日報(1)

個人蠻喜歡沒事看看知乎的,前陣子湊巧也在網上搜到了知乎日報的API,詳情見某位開發者在Github上的分享:知乎日報 API 分析 靠著這個,我就做了一個高仿知乎日報的小應用 動態圖看起來不怎麼流暢,其實真機執行的話還是很流程的,畢竟這只是一個純

android仿微信圖片瀏覽器

專案中用到圖片瀏覽 拆分出來 以後方便使用 高仿微信圖片瀏覽器 module使用 rxjava + okhttp3 + fresco 所以專案中引用以後 會增大安裝包體積2m左右 如果你的專案中沒有使用rxjava 和 okhttp3 和fresco

Android仿微信/支付寶 掃一掃(弱光檢測掃一掃自動放大功能)

if (rawResult != null) { // Don't log the barcode contents for security. long end = System.currentTimeMillis(); Log.d(T

根據牛腩老師的mono for android 視訊,自己用vs2017的xamarin for android仿了一個登入介面跳轉主介面的程式

//定義四個控制元件         private Button btn_visit;         private Button btn_login;         private Button btn_cancel;         private EditText txt_name;      

Android 仿QQ空間廣告位 ——— 一個位置來回切換兩張廣告圖

刷動態時無意間發現了這個效果覺得用在打廣告上實在是妙,使用者只需要上下滑動列表就會自動切換廣告圖(感興趣的可以在刷空間的時候留意一下)。一:接下來就來說說這個效果的具體實現思路通過自定義ImageView、繪製兩張圖片在上面。通過刮刮卡原理在ImageView上繪製一個圓不斷

Android 仿微信發朋友圈瀏覽圖片效果

最近一直在高仿微信、高仿微信,今天小編再給大家分享一個仿微信發朋友圈瀏覽圖片的效果.... 好了,先看一下效果吧: 下面就來說一下具體怎麼實現的: 實現思路 1.首先我們要獲取資料來源,資料來源就是我們的每條說說(包括姓名、標題、圖片陣列)

Android仿qq閱讀/微信讀書/掌閱亮選擇文字效果

前言    最近做epub閱讀器,有劃線的需求,即類似於qq閱讀/微信讀書/掌閱那樣的移動選擇文字並高亮劃線等,在這裡記錄下實現的思路供大家參考,功能都還沒有上線,等優化徹底了,我可以考慮抽出這個模組開源下,嘿嘿! 實現的效果圖 可以看到,這個效果還是可

Android仿qq及微信底部選單的幾種實現方式

最近專案沒那麼忙,想著開發app的話,有很多都是重複,既然是重複的,那就沒有必要每次都去寫,所以就想著寫一個app通用的基本框架,這裡說的框架不是什麼MVC,MVP,MVVM這種,而是app開發的通用模式,一般的app都是底部有幾個選單按鈕,類似qq這樣的,只不

Android 仿 頻道管理----網易、今日頭條、騰訊視訊 (可以拖動的GridView)附原始碼DEMO

private void MoveAnim(View moveView, int[] startLocation,int[] endLocation, final ChannelItem moveChannel, final GridView clickGridView) { int[] initL

Android 仿QQ 好友分組列表

本帖最後由 憤怒的小鳥 於 2012-11-4 10:53 編輯實現的效果如下: 用ExpandableListView實現,先看Activity的程式碼: public class BuddyActivity extends Activity {      ExpandableListView exp