自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Android仿知乎創(chuàng)意廣告 廣告還能這么玩?

移動開發(fā) Android
貌似前段時間刷知乎看到的一種非常有特色的廣告展現(xiàn)方式,即在列表頁,某一個Item顯示背后部分廣告圖,隨著列表滾動,會逐漸展示全部圖片。今天來給大家講解下,當然了,目前一些自定義View已經(jīng)不算難題,所以本文的講解會做一些實現(xiàn)思路引導,相信不會是那么枯燥的文章,希望對大家有一定的幫助。

一、概述

貌似前段時間刷知乎看到的一種非常有特色的廣告展現(xiàn)方式,即在列表頁,某一個Item顯示背后部分廣告圖,隨著列表滾動,會逐漸展示全部圖片。

剛看到的時候就想實現(xiàn)一哈,一直比較懶,公眾號后臺也有人問如何實現(xiàn),今天來給大家講解下,當然了,目前一些自定義View已經(jīng)不算難題,所以本文的講解會做一些實現(xiàn)思路引導,相信不會是那么枯燥的文章,希望對大家有一定的幫助。

恩,現(xiàn)在知乎上已經(jīng)找不到該效果了,試了多個歷史版本也沒找到,那只能貼實現(xiàn)的效果圖了~

效果圖如下:

 

 

2選1,你喜歡哪個效果圖呢~~

二、思路

好了,拋開別的,確定下本文的目標:

實現(xiàn)在列表中展示某張圖片:

  • 往上滾動:在圖片剛出現(xiàn)時展示頂部部分,隨著滾動部分展示全部
  • 往下滾動:在圖片剛出現(xiàn)時展示底部部分,隨著滾動部分展示全部

換句話說,我們需要在列表滾動時,改變圖片顯示的部分。

兩個點:

  • 捕獲列表滾動的dy,不管是ListView還是RecyclerView相信這一點都能做到
  • 圖片顯示部分變化,我們可以利用canvas.translate

結合一下,就是,監(jiān)聽列表的滾動dy,傳給我們的圖片控件,設置translate,然后繪制。

到這里,思路非常清晰,這個東西肯定能做了。

初步方案:自定義一個View,自己去繪制bitmap,對外暴露setDy(dy),然后根據(jù)dy做canvas偏移重繪即可。

有了初步方案,基本不慌了,那么再想想?

能否利用已有的控件,比如ImageView呢?

肯定可以,這樣省去了我們?nèi)ヂ暶饕粋€接受圖片的屬性,我們編寫一個子類,依然是通過設置src去使用。

那繼承ImageView實現(xiàn)一波再說。

三、實現(xiàn)

首先我們先寫個假的列表,鑒于RV用的越來越多,就用RecyclerView吧。

布局

主布局文件,一個RecyclerView即可:

 

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <android.support.v7.widget.RecyclerView 
  3.     xmlns:android="http://schemas.android.com/apk/res/android" 
  4.     xmlns:app="http://schemas.android.com/apk/res-auto" 
  5.     android:id="@+id/id_recyclerview" 
  6.     android:layout_width="match_parent" 
  7.     android:layout_height="match_parent" 
  8.  /> 

item布局文件:

 

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  3.     android:layout_width="match_parent" 
  4.     android:layout_height="wrap_content" 
  5.     android:background="@drawable/item_bg" 
  6.     android:gravity="center"
  7.  
  8.     <com.imooc.rvimageads.AdImageViewVersion1 
  9.         android:id="@+id/id_iv_ad" 
  10.         android:layout_width="match_parent" 
  11.         android:layout_height="180dp" 
  12.         android:scaleType="matrix" 
  13.         android:src="@mipmap/grsm" 
  14.         android:visibility="gone" /> 
  15.  
  16.     <TextView 
  17.         android:layout_margin="12dp" 
  18.         android:id="@+id/id_tv_title" 
  19.         android:layout_width="wrap_content" 
  20.         android:layout_height="wrap_content" 
  21.         android:text="這是title" 
  22.         android:textSize="16dp" 
  23.         android:textStyle="bold" /> 
  24.  
  25.     <TextView 
  26.         android:id="@+id/id_tv_desc" 
  27.         android:layout_width="wrap_content" 
  28.         android:layout_height="wrap_content" 
  29.         android:layout_below="@id/id_tv_title" 
  30.         android:layout_marginLeft="12dp" 
  31.         android:layout_marginRight="12dp" 
  32.         android:layout_marginBottom="12dp" 
  33.         android:text="這是描述" /> 
  34.  
  35. </RelativeLayout> 

很簡單,先不用管 AdImageViewVersion1 類,這將是我們具體的實現(xiàn)類。

通過布局文件,可以看到,我們只使用了一個item布局文件,然后通過visible,gone控制展示不同形態(tài)。

Activity

 

  1. public class MainActivity extends AppCompatActivity { 
  2.  
  3.     private RecyclerView mRecyclerView; 
  4.     private LinearLayoutManager mLinearLayoutManager; 
  5.  
  6.     @Override 
  7.     protected void onCreate(Bundle savedInstanceState) { 
  8.         super.onCreate(savedInstanceState); 
  9.         setContentView(R.layout.activity_main); 
  10.  
  11.         mRecyclerView = findViewById(R.id.id_recyclerview); 
  12.  
  13.         List<String> mockDatas = new ArrayList<>(); 
  14.         for (int i = 0; i < 100; i++) { 
  15.             mockDatas.add(i + ""); 
  16.         } 
  17.  
  18.         mRecyclerView.setLayoutManager(mLinearLayoutManager = new LinearLayoutManager(this)); 
  19.  
  20.         mRecyclerView.setAdapter(new CommonAdapter<String>(MainActivity.this, 
  21.                 R.layout.item, 
  22.                 mockDatas) { 
  23.             @Override 
  24.             protected void convert(ViewHolder holder, String o, int position) { 
  25.                 if (position > 0 && position % 6 == 0) { 
  26.                     holder.setVisible(R.id.id_tv_title, false); 
  27.                     holder.setVisible(R.id.id_tv_desc, false); 
  28.                     holder.setVisible(R.id.id_iv_ad, true); 
  29.                 } else { 
  30.                     holder.setVisible(R.id.id_tv_title, true); 
  31.                     holder.setVisible(R.id.id_tv_desc, true); 
  32.                     holder.setVisible(R.id.id_iv_ad, false); 
  33.                 } 
  34.             } 
  35.         }); 

僅僅是設置數(shù)據(jù)了,Adapter這里用了

  1. compile 'com.zhy:base-rvadapter:3.0.3' 

你可以隨便用一個你自己喜歡的Adapter封裝類。

到這里,一個列表頁就顯示出來了,并且每隔6個會顯示成圖片。

不截圖了,腦補下…

現(xiàn)在才正式開始實現(xiàn)。

自定義AdImageView

 

  1. public class AdImageViewVersion1 extends AppCompatImageView { 
  2.     public AdImageViewVersion1(Context context, @Nullable AttributeSet attrs) { 
  3.         super(context, attrs); 
  4.     } 
  5.  
  6.     private RectF mBitmapRectF; 
  7.     private Bitmap mBitmap; 
  8.  
  9.     private int mMinDy; 
  10.  
  11.     @Override 
  12.     protected void onSizeChanged(int w, int h, int oldw, int oldh) { 
  13.         super.onSizeChanged(w, h, oldw, oldh); 
  14.  
  15.         mMinDy = h; 
  16.         Drawable drawable = getDrawable(); 
  17.  
  18.         if (drawable == null) { 
  19.             return
  20.         } 
  21.  
  22.         mBitmap = drawableToBitamp(drawable); 
  23.         mBitmapRectF = new RectF(0, 0, 
  24.                 w, 
  25.                 mBitmap.getHeight() * w / mBitmap.getWidth()); 
  26.  
  27.     } 
  28.  
  29.  
  30.     private Bitmap drawableToBitamp(Drawable drawable) { 
  31.         if (drawable instanceof BitmapDrawable) { 
  32.             BitmapDrawable bd = (BitmapDrawable) drawable; 
  33.             return bd.getBitmap(); 
  34.         } 
  35.         int w = drawable.getIntrinsicWidth(); 
  36.         int h = drawable.getIntrinsicHeight(); 
  37.         Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 
  38.         Canvas canvas = new Canvas(bitmap); 
  39.         drawable.setBounds(0, 0, w, h); 
  40.         drawable.draw(canvas); 
  41.         return bitmap; 
  42.     } 
  43.  
  44.     // ... 省略一些代碼 

因為我們要繪制,所以這里我們把drawable轉(zhuǎn)成bitmap,然后我們默認要顯示***部,所以需要一個最小的偏移,即控件高度。

這些事情,我們都在onSizeChanged做了。

并且我們根據(jù)當前控件寬度,對bitmap進行了縮放,并將縮放后的尺寸存在了mBitmapRectF中,以便于繪制。

那么接下來就是繪制了,還記得繪制過程中,我們主要利用translate來控制繪制的區(qū)域,所以我們還要對外暴露一個setDy方法,so,我們的代碼大致是這樣的:

 

  1. private int mDy; 
  2.  
  3. public void setDy(int dy) { 
  4.  
  5.     if (getDrawable() == null) { 
  6.         return
  7.     } 
  8.     mDy = dy - mMinDy; 
  9.     if (mDy <= 0) { 
  10.         mDy = 0; 
  11.     } 
  12.     if (mDy > mBitmapRectF.height() - mMinDy) { 
  13.         mDy = (int) (mBitmapRectF.height() - mMinDy); 
  14.     } 
  15.     invalidate(); 
  16.  
  17. @Override 
  18. protected void onDraw(Canvas canvas) { 
  19.     if (mBitmap == null) { 
  20.         return
  21.     } 
  22.     canvas.save(); 
  23.     canvas.translate(0, -mDy); 
  24.     canvas.drawBitmap(mBitmap, null, mBitmapRectF, null); 
  25.     canvas.restore(); 

setDy的時候,我們做了一個邊界判斷,最小的情況,我們偏移-mMinDy,顯示圖片的底部。

***的時候,我們便宜圖片高度-mMinDy,顯示頂部部分。

所以我們對傳入的值做了最小與***值判斷。

那么在繪制的時候,就簡單了,先translate dy距離,然后繪制即可。

到這里我們的自定義View部分就結束了,代碼很少~

結合RecyclerView

接下來就是在RecyclerView滾動時,給我們傳入dy即可。

 

  1. mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { 
  2.     @Override 
  3.     public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 
  4.         super.onScrolled(recyclerView, dx, dy); 
  5.  
  6.         int fPos = mLinearLayoutManager.findFirstVisibleItemPosition(); 
  7.         int lPos = mLinearLayoutManager.findLastCompletelyVisibleItemPosition(); 
  8.         for (int i = fPos; i <= lPos; i++) { 
  9.             View view = mLinearLayoutManager.findViewByPosition(i); 
  10.             AdImageViewVersion1 adImageView = view.findViewById(R.id.id_iv_ad); 
  11.             if (adImageView.getVisibility() == View.VISIBLE) { 
  12.                 adImageView.setDy(mLinearLayoutManager.getHeight() - view.getTop()); 
  13.             } 
  14.         } 
  15.     } 
  16. }); 

通過addOnScrollListener監(jiān)聽,當滾動時,拿到所有可見的Item,找出正在顯示圖片的Item。然后調(diào)用setDy,dy的值為 mLinearLayoutManager.getHeight() - view.getTop() ,當View從***部出現(xiàn)的時候為0,當View到達最頂部的時候為當前rv的高度。

你可以合理的利用setDy傳入的值,做移動差,顯示區(qū)域從上到下等,都可以。

這樣就完成了~~

 

一句話實現(xiàn):即滾動時不斷改變dy,然后translate繪制即可。

四、再想想

看著這個代碼,好像 drawableToBitamp 看起來非常不爽,也是比較耗內(nèi)存的部分。我們再想想:

本身Drawable就是能繪制的,為什么我們要轉(zhuǎn)成bitmap呢?

好像有道理,ImageView本身繪制的就是Drawable,我們需要控制的就是這個Drawable的繪制范圍要足夠大,不能被控件本身的寬高所影響,導致圖片被壓扁。

好像有那么一個方法:

  1. drawable.setBounds(); 

那就簡單了,去除drawable2bitmap的代碼,直接利用原本的繪制即可,我們唯一要做的就是設置bounds,做一個translate dy即可。

完整代碼:

 

  1. public class AdImageView extends AppCompatImageView { 
  2.     // 刪除構造方法 
  3.  
  4.     private int mDx; 
  5.     private int mMinDx; 
  6.  
  7.     public void setDx(int dx) { 
  8.         if (getDrawable() == null) { 
  9.             return
  10.         } 
  11.         mDx = dx - mMinDx; 
  12.         if (mDx <= 0) { 
  13.             mDx = 0; 
  14.         } 
  15.         if (mDx > getDrawable().getBounds().height() - mMinDx) { 
  16.             mDx = getDrawable().getBounds().height() - mMinDx; 
  17.         } 
  18.         invalidate(); 
  19.     } 
  20.  
  21.     @Override 
  22.     protected void onSizeChanged(int w, int h, int oldw, int oldh) { 
  23.         super.onSizeChanged(w, h, oldw, oldh); 
  24.         mMinDx = h; 
  25.     } 
  26.  
  27.     public int getDx() { 
  28.         return mDx; 
  29.     } 
  30.  
  31.     @Override 
  32.     protected void onDraw(Canvas canvas) { 
  33.  
  34.         Drawable drawable = getDrawable(); 
  35.         int w = getWidth(); 
  36.         int h = (int) (getWidth() * 1.0f / drawable.getIntrinsicWidth() * drawable.getIntrinsicHeight()); 
  37.         drawable.setBounds(0, 0, w, h); 
  38.         canvas.save(); 
  39.         canvas.translate(0, -getDx()); 
  40.         super.onDraw(canvas); 
  41.         canvas.restore(); 
  42.     } 

短短的代碼就實現(xiàn)了,這樣看起來順眼多了~~

再貼下效果圖:

 

效果圖主要看字,你懂的!

好了,本篇總結:

  • 看到當看一個效果,可以先對它進行拆分,找出關鍵點,針對每個關鍵點,考慮可行性。
  • 如果確定每個點都可行,那么基本的方案就出來了。
  • 有了基本的方案,不要著急寫,再想想還有無改善空間。

例子比較簡單,have a nice day ~~

責任編輯:未麗燕 來源: Hongyang
相關推薦

2022-10-31 08:47:21

人臉識別按鍵鍵盤

2020-05-09 16:45:56

ping命令Linux

2011-10-12 09:35:59

移動應用互動廣告手機游戲

2024-10-28 07:10:00

scroll標記前端網(wǎng)格布局

2024-03-25 08:03:32

技術面試ShowMeBug協(xié)同編程

2019-07-08 17:54:47

惠普

2020-12-02 15:22:30

版本成本Playturbo

2015-07-21 15:22:20

點贊仿知乎按鈕動畫

2014-11-03 16:27:58

鷹目

2014-01-23 10:07:31

移動廣告廣告商banner

2021-04-01 05:40:53

分庫分表數(shù)據(jù)庫MySQL

2020-08-14 08:19:25

Shell命令行數(shù)據(jù)

2022-01-04 08:00:48

前端技術Esbuild

2017-03-07 09:49:18

存儲

2013-03-04 12:58:09

原生廣告移動廣告

2011-12-14 21:24:55

水果忍者

2022-11-28 16:16:06

2020-01-07 10:35:21

QQQQ群手機QQ

2013-01-08 12:51:15

移動廣告聲音聲盟

2014-12-23 14:28:58

廣告家
點贊
收藏

51CTO技術棧公眾號