日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
玩轉(zhuǎn)仿探探卡片式滑動效果

講起本篇博客講起本篇博客的歷史起源,估計有一段“歷史”了。的歷史起源,估計有一段“歷史”了。

成都創(chuàng)新互聯(lián)公司堅持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:網(wǎng)站建設(shè)、做網(wǎng)站、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時代的阜新網(wǎng)站設(shè)計、移動媒體設(shè)計的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

最早可以追溯到我試玩探探這個 APP 。***次進(jìn)入軟件界面,就被這種通過卡片式滑動來選擇“喜歡/不喜歡”的設(shè)計所吸引了。當(dāng)時就非常想通過自己來實現(xiàn)這種仿探探式的效果,然而卻沒什么思路。不過毋庸置疑的是,這種效果的原理肯定和 ListView / RecyclerView 類似,涉及到 Item View 的回收和重用,否則早就因為大量的 Item View 而 OOM 了。

再到后來,看到許多大神也推出了同樣仿探探效果的博客,從頭到尾閱讀下來,寫得通俗易懂,基本上沒什么問題。于是,實現(xiàn)仿探探效果的想法再次出現(xiàn)在腦海中。那么,還猶豫什么,趁熱來一發(fā)吧!就這么愉快地決定了。

首先面臨的問題就是關(guān)于實現(xiàn) View 上的考慮。毫無疑問。

RecyclerView 是***選擇!

RecyclerView 是***選擇!

RecyclerView 是***選擇!

重要的話講三遍!!!

究其原因,***,RecyclerView 是自帶 Item View 回收和重用功能的,就不需要我們考慮這個問題了;第二,RecyclerView 的布局方式是通過設(shè)置 LayoutManager 來實現(xiàn)的,這樣就充分地把布局和 RecyclerView “解耦”開來了。而 LayoutManager 是可以通過自定義的方式來實現(xiàn)的。這恰恰是我們想要的!!!再說一點,這也正是不選用 ListView 的原因之一。

下面,我們就開始動手了。帶你見證奇跡的時刻。

CardLayoutManager

創(chuàng)建 CardLayoutManager 并繼承自 RecyclerView.LayoutManager 。需要我們自己實現(xiàn) generateDefaultLayoutParams() 方法:

 
 
 
 
  1. @Override
  2. public RecyclerView.LayoutParams generateDefaultLayoutParams() {
  3.     return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

一般情況下,像上面這樣寫即可。

下面這個方法就是我們的重點了。 onLayoutChildren(final RecyclerView.Recycler recycler, RecyclerView.State state) 方法就是用來實現(xiàn) Item View 布局的:

  1. @Override
  2. public void onLayoutChildren(final RecyclerView.Recycler recycler, RecyclerView.State state) {
  3.     super.onLayoutChildren(recycler, state);
  4.     // 先移除所有view
  5.     removeAllViews();
  6.     // 在布局之前,將所有的子 View 先 Detach 掉,放入到 Scrap 緩存中
  7.     detachAndScrapAttachedViews(recycler);
  8.     int itemCount = getItemCount();
  9.     // 在這里,我們默認(rèn)配置 CardConfig.DEFAULT_SHOW_ITEM = 3。即在屏幕上顯示的卡片數(shù)為3
  10.     // 當(dāng)數(shù)據(jù)源個數(shù)大于***顯示數(shù)時
  11.     if (itemCount > CardConfig.DEFAULT_SHOW_ITEM) {
  12.         // 把數(shù)據(jù)源倒著循環(huán),這樣,第0個數(shù)據(jù)就在屏幕最上面了
  13.         for (int position = CardConfig.DEFAULT_SHOW_ITEM; position >= 0; position--) {
  14.             final View view = recycler.getViewForPosition(position);
  15.             // 將 Item View 加入到 RecyclerView 中
  16.             addView(view);
  17.             // 測量 Item View
  18.             measureChildWithMargins(view, 0, 0);
  19.             // getDecoratedMeasuredWidth(view) 可以得到 Item View 的寬度
  20.             // 所以 widthSpace 就是除了 Item View 剩余的值
  21.             int widthSpace = getWidth() - getDecoratedMeasuredWidth(view);
  22.             // 同理
  23.             int heightSpace = getHeight() - getDecoratedMeasuredHeight(view);
  24.             // 將 Item View 放入 RecyclerView 中布局
  25.             // 在這里默認(rèn)布局是放在 RecyclerView 中心
  26.             layoutDecoratedWithMargins(view, widthSpace / 2, heightSpace / 2,
  27.                     widthSpace / 2 + getDecoratedMeasuredWidth(view),
  28.                     heightSpace / 2 + getDecoratedMeasuredHeight(view));
  29.             // 其實屏幕上有四張卡片,但是我們把第三張和第四張卡片重疊在一起,這樣看上去就只有三張
  30.             // 第四張卡片主要是為了保持動畫的連貫性
  31.             if (position == CardConfig.DEFAULT_SHOW_ITEM) {
  32.                 // 按照一定的規(guī)則縮放,并且偏移Y軸。
  33.                 // CardConfig.DEFAULT_SCALE 默認(rèn)為0.1f,CardConfig.DEFAULT_TRANSLATE_Y 默認(rèn)為14
  34.                 view.setScaleX(1 - (position - 1) * CardConfig.DEFAULT_SCALE);
  35.                 view.setScaleY(1 - (position - 1) * CardConfig.DEFAULT_SCALE);
  36.                 view.setTranslationY((position - 1) * view.getMeasuredHeight() / CardConfig.DEFAULT_TRANSLATE_Y);
  37.             } else if (position > 0) {
  38.                 view.setScaleX(1 - position * CardConfig.DEFAULT_SCALE);
  39.                 view.setScaleY(1 - position * CardConfig.DEFAULT_SCALE);
  40.                 view.setTranslationY(position * view.getMeasuredHeight() / CardConfig.DEFAULT_TRANSLATE_Y);
  41.             } else {
  42.                 // 設(shè)置 mTouchListener 的意義就在于我們想讓處于頂層的卡片是可以隨意滑動的
  43.                 // 而第二層、第三層等等的卡片是禁止滑動的
  44.                 view.setOnTouchListener(mOnTouchListener);
  45.             }
  46.         }
  47.     } else {
  48.         // 當(dāng)數(shù)據(jù)源個數(shù)小于或等于***顯示數(shù)時,和上面的代碼差不多
  49.         for (int position = itemCount - 1; position >= 0; position--) {
  50.             final View view = recycler.getViewForPosition(position);
  51.             addView(view);
  52.             measureChildWithMargins(view, 0, 0);
  53.             int widthSpace = getWidth() - getDecoratedMeasuredWidth(view);
  54.             int heightSpace = getHeight() - getDecoratedMeasuredHeight(view);
  55.             layoutDecoratedWithMargins(view, widthSpace / 2, heightSpace / 2,
  56.                     widthSpace / 2 + getDecoratedMeasuredWidth(view),
  57.                     heightSpace / 2 + getDecoratedMeasuredHeight(view));
  58.             if (position > 0) {
  59.                 view.setScaleX(1 - position * CardConfig.DEFAULT_SCALE);
  60.                 view.setScaleY(1 - position * CardConfig.DEFAULT_SCALE);
  61.                 view.setTranslationY(position * view.getMeasuredHeight() / CardConfig.DEFAULT_TRANSLATE_Y);
  62.             } else {
  63.                 view.setOnTouchListener

    本文題目:玩轉(zhuǎn)仿探探卡片式滑動效果
    網(wǎng)頁路徑:http://www.dlmjj.cn/article/dhphdoh.html