Androidはクリエイティブ広告のように遊ぶことができますか?
19399 ワード
本文はすでに私の公衆番号hongyangAndroidのオリジナルで先発しました.
一、概説
この間、非常に特色のある広告の表現方法を見たようです.つまり、リストページには、あるItemが背後の広告図を表示し、リストがスクロールするにつれて、すべての画像が徐々に表示されます.
ちょうど见た时に実现したいと思って、ずっと怠け者で、公众号の楽屋もどのように実现するかを闻く人がいて、今日みんなに说明して、もちろん、今いくつかのカスタマイズのViewはすでに难题ではありませんて、だから本文の说明はいくつか実现の考え方の导きをして、そんなに退屈な文章ではないと信じて、みんなに対して一定の助けがあることを望みます.
うん、今はもうこの効果が見つからないことを知っていて、いくつかの歴史バージョンを試しても見つからなかったので、実現した効果図を貼るしかありません.
効果図は以下の通りです.
2選1、どの効果図が好きですか~~
二、考え方
では、他のものを捨てて、本稿の目標を確定します.
リストに画像を表示することを実装します.
上へスクロール:画像が現れたばかりの時に上部部分を表示し、スクロール部分がすべて下へスクロールするにつれて:画像が現れたばかりの時に下部部分を表示し、スクロール部分がすべてを表示するにつれて
すなわち、リストをスクロールするときに、画像の表示部分を変更する必要があります.
2つのポイント:リストスクロールのdyをキャプチャし、ListViewでもRecyclerViewでも が可能だと信じています.画像の表示部分の変化はcanvasを利用することができます.translate
結合すると、リストのスクロールdyをリスニングし、私たちの画像コントロールに伝え、translateを設定し、描画します.
ここまで来ると、考えがはっきりしていて、これはきっとできるに違いない.
初歩案:Viewをカスタマイズし、自分でbitmapを描き、setDy(dy)を外部に露出し、dyに基づいてcanvasオフセットを再描画すればよい.
初歩的な案があって、ほとんど慌てないで、それでは更に考えますか?
ImageViewなど、既存のコントロールを利用できますか?
間違いなく、画像を受け入れる属性を宣言するのを省いて、サブクラスを作成して、依然としてsrcを設定することで使用します.
それはImageViewを継承して実現してからにしよう.
コードを開始する前に、私の公衆番号を押してください.
Android関連技術に専念~
三、実現
まず、偽のリストを書きます.RVがますます増えているので、RecyclerViewを使いましょう.
レイアウト
プライマリ・レイアウト・ファイル:RecyclerView 1
itemレイアウトファイル:
簡単ですが、
Activity
データを設定しただけで、Adapterはここで使いました.
自分の好きなAdapterパッケージクラスを勝手に使ってもいいです.
ここまで、1つのリストページが表示され、6つおきに画像として表示されます.
スクリーンショットしないで、脳は...
今から本格的に実現します.
カスタムAdImageView
描画するのでdrawableをbitmapに変換し、デフォルトでは最下部を表示するので、コントロールの高さという最小のオフセットが必要です.
これらのことは、私たちはonSizeChangedでした.
また,現在のコントロール幅に基づいてbitmapをスケーリングし,スケーリング後の寸法をmBitmapRectFに存在させて描画した.
次に描画します.描画中、translateを利用して描画領域を制御していたことを覚えています.そのため、setDyメソッドを外部に暴露しなければなりません.so、私たちのコードは大体次のようになっています.
setDyの時、私たちは境界判断をして、最小の情況、私たちは-mMinDyをオフセットして、画像の底を表示します.最大の場合、画像の高さ-mMinDyをオフセットし、上部を表示します.
そこで,伝達された値について最小値と最大値の判断を行った.
では、描くときは簡単です.まずtranslate dy距離を引いてから描きます.
ここまでカスタマイズしたView部分が終わり、コードが少ない~
RecyclerViewと組み合わせる
次は、RecyclerViewでスクロールするときにdyを入力すればいいです.
addOnScrollListenerで傍受し、スクロールすると表示されているすべてのItemを取得し、画像が表示されているItemを見つけます.次いでsetDyが呼び出され、dyの値は
setDyが入力した値を合理的に利用して、移動差をしたり、表示領域を上から下にしたりすることができます.
これで完成~~
一言で実現:スクロール時にdyを絶えず変更し、translateで描画すればよい.
四、もう一度考えてみる
ここまではもう実現しましたが、あなたは満足していますか?考えてないの?
コードを振り返ると、このコードは、
自分がDrawableで描くことができるのに、なぜbitmapに変えるのでしょうか.
なるほど、ImageView自体がDrawableを描いているようですが、私たちが制御しなければならないのは、このDrawableの描画範囲が十分に大きく、コントロール自体の幅に影響されず、画像が潰されることです.
そんな方法があるようです.
それは簡単です.drawable 2 bitmapのコードを除去し、元の描画を直接利用すればいいです.私たちが唯一しなければならないのはboundsを設定し、translate dyを作ることです.
完全なコード:
短いコードで実現したので、目が楽になりました~~
効果図を貼り付けます.
効果図は主に字を読んで、あなたは知っています!
さて、本編のまとめ:は、効果を見ると、まずそれを分割し、キーを見つけ、各キーに対して実行可能性を考慮することができます. 各点が実行可能であると判断すると、基本的なスキームが出てくる. には基本的な案がありますから、焦らずに書いて、改善の余地があるかどうかを考えてみましょう.
例は簡単だ
github.com/hongyangAnd…
一、概説
この間、非常に特色のある広告の表現方法を見たようです.つまり、リストページには、あるItemが背後の広告図を表示し、リストがスクロールするにつれて、すべての画像が徐々に表示されます.
ちょうど见た时に実现したいと思って、ずっと怠け者で、公众号の楽屋もどのように実现するかを闻く人がいて、今日みんなに说明して、もちろん、今いくつかのカスタマイズのViewはすでに难题ではありませんて、だから本文の说明はいくつか実现の考え方の导きをして、そんなに退屈な文章ではないと信じて、みんなに対して一定の助けがあることを望みます.
うん、今はもうこの効果が見つからないことを知っていて、いくつかの歴史バージョンを試しても見つからなかったので、実現した効果図を貼るしかありません.
効果図は以下の通りです.
2選1、どの効果図が好きですか~~
二、考え方
では、他のものを捨てて、本稿の目標を確定します.
リストに画像を表示することを実装します.
上へスクロール:画像が現れたばかりの時に上部部分を表示し、スクロール部分がすべて下へスクロールするにつれて:画像が現れたばかりの時に下部部分を表示し、スクロール部分がすべてを表示するにつれて
すなわち、リストをスクロールするときに、画像の表示部分を変更する必要があります.
2つのポイント:
結合すると、リストのスクロールdyをリスニングし、私たちの画像コントロールに伝え、translateを設定し、描画します.
ここまで来ると、考えがはっきりしていて、これはきっとできるに違いない.
初歩案:Viewをカスタマイズし、自分でbitmapを描き、setDy(dy)を外部に露出し、dyに基づいてcanvasオフセットを再描画すればよい.
初歩的な案があって、ほとんど慌てないで、それでは更に考えますか?
ImageViewなど、既存のコントロールを利用できますか?
間違いなく、画像を受け入れる属性を宣言するのを省いて、サブクラスを作成して、依然としてsrcを設定することで使用します.
それはImageViewを継承して実現してからにしよう.
コードを開始する前に、私の公衆番号を押してください.
Android関連技術に専念~
三、実現
まず、偽のリストを書きます.RVがますます増えているので、RecyclerViewを使いましょう.
レイアウト
プライマリ・レイアウト・ファイル:RecyclerView 1
"1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/id_recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
itemレイアウトファイル:
xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/item_bg"
android:gravity="center">
<com.imooc.rvimageads.AdImageViewVersion1
android:id="@+id/id_iv_ad"
android:layout_width="match_parent"
android:layout_height="180dp"
android:scaleType="matrix"
android:src="@mipmap/grsm"
android:visibility="gone" />
<TextView
android:layout_margin="12dp"
android:id="@+id/id_tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" title"
android:textSize="16dp"
android:textStyle="bold" />
<TextView
android:id="@+id/id_tv_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/id_tv_title"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp"
android:layout_marginBottom="12dp"
android:text=" " />
RelativeLayout>
簡単ですが、
AdImageViewVersion1
クラスにかかわらず、これは私たちの具体的な実装クラスになります.レイアウトファイルを使用すると、itemレイアウトファイルが1つしか使用されず、visible、gone制御によって異なる形態が表示されることがわかります.Activity
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private LinearLayoutManager mLinearLayoutManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = findViewById(R.id.id_recyclerview);
List mockDatas = new ArrayList<>();
for (int i = 0; i < 100; i++) {
mockDatas.add(i + "");
}
mRecyclerView.setLayoutManager(mLinearLayoutManager = new LinearLayoutManager(this));
mRecyclerView.setAdapter(new CommonAdapter(MainActivity.this,
R.layout.item,
mockDatas) {
@Override
protected void convert(ViewHolder holder, String o, int position) {
if (position > 0 && position % 6 == 0) {
holder.setVisible(R.id.id_tv_title, false);
holder.setVisible(R.id.id_tv_desc, false);
holder.setVisible(R.id.id_iv_ad, true);
} else {
holder.setVisible(R.id.id_tv_title, true);
holder.setVisible(R.id.id_tv_desc, true);
holder.setVisible(R.id.id_iv_ad, false);
}
}
});
}
データを設定しただけで、Adapterはここで使いました.
compile 'com.zhy:base-rvadapter:3.0.3'
自分の好きなAdapterパッケージクラスを勝手に使ってもいいです.
ここまで、1つのリストページが表示され、6つおきに画像として表示されます.
スクリーンショットしないで、脳は...
今から本格的に実現します.
カスタムAdImageView
public class AdImageViewVersion1 extends AppCompatImageView {
public AdImageViewVersion1(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
private RectF mBitmapRectF;
private Bitmap mBitmap;
private int mMinDy;
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mMinDy = h;
Drawable drawable = getDrawable();
if (drawable == null) {
return;
}
mBitmap = drawableToBitamp(drawable);
mBitmapRectF = new RectF(0, 0,
w,
mBitmap.getHeight() * w / mBitmap.getWidth());
}
private Bitmap drawableToBitamp(Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bd = (BitmapDrawable) drawable;
return bd.getBitmap();
}
int w = drawable.getIntrinsicWidth();
int h = drawable.getIntrinsicHeight();
Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, w, h);
drawable.draw(canvas);
return bitmap;
}
// ...
}
描画するのでdrawableをbitmapに変換し、デフォルトでは最下部を表示するので、コントロールの高さという最小のオフセットが必要です.
これらのことは、私たちはonSizeChangedでした.
また,現在のコントロール幅に基づいてbitmapをスケーリングし,スケーリング後の寸法をmBitmapRectFに存在させて描画した.
次に描画します.描画中、translateを利用して描画領域を制御していたことを覚えています.そのため、setDyメソッドを外部に暴露しなければなりません.so、私たちのコードは大体次のようになっています.
private int mDy;
public void setDy(int dy) {
if (getDrawable() == null) {
return;
}
mDy = dy - mMinDy;
if (mDy <= 0) {
mDy = 0;
}
if (mDy > mBitmapRectF.height() - mMinDy) {
mDy = (int) (mBitmapRectF.height() - mMinDy);
}
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
if (mBitmap == null) {
return;
}
canvas.save();
canvas.translate(0, -mDy);
canvas.drawBitmap(mBitmap, null, mBitmapRectF, null);
canvas.restore();
}
setDyの時、私たちは境界判断をして、最小の情況、私たちは-mMinDyをオフセットして、画像の底を表示します.最大の場合、画像の高さ-mMinDyをオフセットし、上部を表示します.
そこで,伝達された値について最小値と最大値の判断を行った.
では、描くときは簡単です.まずtranslate dy距離を引いてから描きます.
ここまでカスタマイズしたView部分が終わり、コードが少ない~
RecyclerViewと組み合わせる
次は、RecyclerViewでスクロールするときにdyを入力すればいいです.
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int fPos = mLinearLayoutManager.findFirstVisibleItemPosition();
int lPos = mLinearLayoutManager.findLastCompletelyVisibleItemPosition();
for (int i = fPos; i <= lPos; i++) {
View view = mLinearLayoutManager.findViewByPosition(i);
AdImageViewVersion1 adImageView = view.findViewById(R.id.id_iv_ad);
if (adImageView.getVisibility() == View.VISIBLE) {
adImageView.setDy(mLinearLayoutManager.getHeight() - view.getTop());
}
}
}
});
addOnScrollListenerで傍受し、スクロールすると表示されているすべてのItemを取得し、画像が表示されているItemを見つけます.次いでsetDyが呼び出され、dyの値は
mLinearLayoutManager.getHeight() - view.getTop()
であり、Viewが最底部から現れたときは0であり、Viewが最頂部に達したときは現在のrvの高さである.setDyが入力した値を合理的に利用して、移動差をしたり、表示領域を上から下にしたりすることができます.
これで完成~~
一言で実現:スクロール時にdyを絶えず変更し、translateで描画すればよい.
四、もう一度考えてみる
ここまではもう実現しましたが、あなたは満足していますか?考えてないの?
コードを振り返ると、このコードは、
drawableToBitamp
が非常に不快に見え、メモリを消費している部分でもあるようです.考えてみましょう自分がDrawableで描くことができるのに、なぜbitmapに変えるのでしょうか.
なるほど、ImageView自体がDrawableを描いているようですが、私たちが制御しなければならないのは、このDrawableの描画範囲が十分に大きく、コントロール自体の幅に影響されず、画像が潰されることです.
そんな方法があるようです.
drawable.setBounds();
それは簡単です.drawable 2 bitmapのコードを除去し、元の描画を直接利用すればいいです.私たちが唯一しなければならないのはboundsを設定し、translate dyを作ることです.
完全なコード:
public class AdImageView extends AppCompatImageView {
//
private int mDx;
private int mMinDx;
public void setDx(int dx) {
if (getDrawable() == null) {
return;
}
mDx = dx - mMinDx;
if (mDx <= 0) {
mDx = 0;
}
if (mDx > getDrawable().getBounds().height() - mMinDx) {
mDx = getDrawable().getBounds().height() - mMinDx;
}
invalidate();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mMinDx = h;
}
public int getDx() {
return mDx;
}
@Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
int w = getWidth();
int h = (int) (getWidth() * 1.0f / drawable.getIntrinsicWidth() * drawable.getIntrinsicHeight());
drawable.setBounds(0, 0, w, h);
canvas.save();
canvas.translate(0, -getDx());
super.onDraw(canvas);
canvas.restore();
}
}
短いコードで実現したので、目が楽になりました~~
効果図を貼り付けます.
効果図は主に字を読んで、あなたは知っています!
さて、本編のまとめ:
例は簡単だ
github.com/hongyangAnd…