偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

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

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

一、概述

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

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

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

效果圖如下:

 

 

2選1,你喜歡哪個(gè)效果圖呢~~

二、思路

好了,拋開別的,確定下本文的目標(biāo):

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

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

換句話說,我們需要在列表滾動(dòng)時(shí),改變圖片顯示的部分。

兩個(gè)點(diǎn):

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

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

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

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

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

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

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

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

三、實(shí)現(xiàn)

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

布局

主布局文件,一個(gè)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 類,這將是我們具體的實(shí)現(xiàn)類。

通過布局文件,可以看到,我們只使用了一個(gè)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è)置數(shù)據(jù)了,Adapter這里用了

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

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

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

不截圖了,腦補(bǔ)下…

現(xiàn)在才正式開始實(shí)現(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.     // ... 省略一些代碼 

因?yàn)槲覀円L制,所以這里我們把drawable轉(zhuǎn)成bitmap,然后我們默認(rèn)要顯示***部,所以需要一個(gè)最小的偏移,即控件高度。

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

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

那么接下來就是繪制了,還記得繪制過程中,我們主要利用translate來控制繪制的區(qū)域,所以我們還要對(duì)外暴露一個(gè)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的時(shí)候,我們做了一個(gè)邊界判斷,最小的情況,我們偏移-mMinDy,顯示圖片的底部。

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

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

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

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

結(jié)合RecyclerView

接下來就是在RecyclerView滾動(dòng)時(shí),給我們傳入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)聽,當(dāng)滾動(dòng)時(shí),拿到所有可見的Item,找出正在顯示圖片的Item。然后調(diào)用setDy,dy的值為 mLinearLayoutManager.getHeight() - view.getTop() ,當(dāng)View從***部出現(xiàn)的時(shí)候?yàn)?,當(dāng)View到達(dá)最頂部的時(shí)候?yàn)楫?dāng)前rv的高度。

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

這樣就完成了~~

 

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

四、再想想

看著這個(gè)代碼,好像 drawableToBitamp 看起來非常不爽,也是比較耗內(nèi)存的部分。我們?cè)傧胂耄?/p>

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

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

好像有那么一個(gè)方法:

  1. drawable.setBounds(); 

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

完整代碼:

 

  1. public class AdImageView extends AppCompatImageView { 
  2.     // 刪除構(gòu)造方法 
  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.     } 

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

再貼下效果圖:

 

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

好了,本篇總結(jié):

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

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

責(zé)任編輯:未麗燕 來源: Hongyang
相關(guān)推薦

2022-10-31 08:47:21

人臉識(shí)別按鍵鍵盤

2020-05-09 16:45:56

ping命令Linux

2011-10-12 09:35:59

移動(dòng)應(yīng)用互動(dòng)廣告手機(jī)游戲

2024-10-28 07:10:00

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

2024-03-25 08:03:32

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

2020-12-02 15:22:30

版本成本Playturbo

2019-07-08 17:54:47

惠普

2025-08-18 07:35:40

2015-07-21 15:22:20

點(diǎn)贊仿知乎按鈕動(dòng)畫

2014-11-03 16:27:58

鷹目

2014-01-23 10:07:31

移動(dòng)廣告廣告商banner

2021-04-01 05:40:53

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

2017-03-07 09:49:18

存儲(chǔ)

2022-01-04 08:00:48

前端技術(shù)Esbuild

2020-08-14 08:19:25

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

2013-03-04 12:58:09

原生廣告移動(dòng)廣告

2025-06-12 10:25:13

Android 16通知欄進(jìn)度條

2011-12-14 21:24:55

水果忍者

2022-11-28 16:16:06

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)