仿知乎广告

2019-05-25  本文已影响0人  陈沉成染

仿知乎的广告栏学习

Screenshot_2019-05-25-16-08-00.png Screenshot_2019-05-25-16-08-04.png Screenshot_2019-05-25-16-08-07.png Screenshot_2019-05-25-16-32-09.png

思路
自定义View 继承自imgView
然后通过canvas 对图片进行局部绘制
进行局部的绘制就需要获取itemview的位置
Activity的代码

  import android.databinding.DataBindingUtil;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;

import com.chen.testapplciation.R;
import com.chen.testapplciation.databinding.ActivityRvAdvertisementBinding;

public class Rv_advertisement extends AppCompatActivity {

    ActivityRvAdvertisementBinding binding;
    LinearLayoutManager mLinearLayoutManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mLinearLayoutManager = new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false);
        binding = DataBindingUtil.setContentView(this,R.layout.activity_rv_advertisement);
        binding.rvAdvertisement.setAdapter(new MyAdapter());
        binding.rvAdvertisement.setLayoutManager(mLinearLayoutManager);
        binding.rvAdvertisement.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                int fpos = mLinearLayoutManager.findFirstVisibleItemPosition();
                int lpos =mLinearLayoutManager.findLastVisibleItemPosition();
                for (int i = fpos; i < lpos; i++) {
                    View view = mLinearLayoutManager.findViewByPosition(i);
                    AdimageView adimageView = view.findViewById(R.id.img_av);
                    if (adimageView != null){
                        adimageView.setTextView(binding.textMdy);
                        int dy1 = mLinearLayoutManager.getHeight() - view.getTop();
                        binding.textDy.setText("itemview顶部到底部的高"+dy1+" \n" + "recyclerview=" +mLinearLayoutManager.getHeight() + " \n"+"图片item到顶部的距离"+view.getTop());
                        adimageView.setDy(dy1);
                    }
                }
            }
        });
    }
}

我直接用的 databinding 来获取Recycleview

layout 为了理清思路 我把一些参数显示出来

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".donghua.Rv_advertisement">
    <data>

    </data>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <TextView
        android:id="@+id/text_dy"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="10sp"
        android:text="0"
        android:gravity="center"/>

    <TextView
        android:id="@+id/text_mdy"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="10sp"
        android:text="0"
        android:gravity="center"/>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_advertisement"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </android.support.v7.widget.RecyclerView>
</LinearLayout>
</layout>

adapter


import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.chen.testapplciation.R;

import java.util.ArrayList;

public class MyAdapter extends RecyclerView.Adapter {

    ArrayList<String> data = new ArrayList<>();

    @Override
    public int getItemViewType(int position) {
        if (position%10 ==0){
            return 1;
        }
        return 0;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        if (i ==0){
            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.rv_item_textview,viewGroup,false);
            return new ViewHolder(view);
        }else {
            View view =LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.rv_item_advertisement,viewGroup,false);
            return new AdtViewHolder(view);
        }
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
       AdimageView adimageView =  viewHolder.itemView.findViewById(R.id.img_av);
       if (adimageView != null){
           adimageView.setnotvisible();
       }
    }

    @Override
    public int getItemCount() {
        return 100;
    }


    static class ViewHolder extends RecyclerView.ViewHolder {


        public ViewHolder(@NonNull View itemView) {
            super(itemView);
        }
    }

    static class AdtViewHolder extends RecyclerView.ViewHolder {

        public AdtViewHolder(@NonNull View itemView) {
            super(itemView);
        }
    }
}

adapter 就两个Viewholder
一种显示图片
一种显示文字
onBindViewHolder 因为recyclerview复用viewholder 。所以一定 要初始化一下viewholder

俩个viewholder的layout

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="200dp">

    <com.chen.testapplciation.donghua.AdimageView
        android:id="@+id/img_av"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/nav_bc_0"
        android:scaleType="centerCrop"
        />
</FrameLayout>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="100dp">

    <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>

其中adimgview 就是自定义的view

Adimgview代码

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;

public class AdimageView extends AppCompatImageView {
    private RectF mBitmapRectF;
    private Bitmap mBitmap;
    private TextView mTextView;

    private int mMinDy = 0;

    public void setTextView(TextView textView) {
        mTextView = textView;
    }

    public AdimageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    int showwidth;

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        showwidth = w;
        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;
    }

    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);
        }
        mTextView.setText("绘制偏移量"+mDy+"\n "+"imgageview显示的高度=" +mMinDy +"\n"+" 图片的缩小后的高度"+height );
        invalidate();
    }
    int bitmapheight ;
    int bitmapwidth ;
    int height =0;

    public void setnotvisible() {
        mDy =0;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mBitmap == null) {
            return;
        }
        bitmapheight = mBitmap.getHeight();
        bitmapwidth= mBitmap.getWidth();
        height = bitmapheight *showwidth/bitmapwidth;

        canvas.save();
        canvas.translate(0,-mDy);
        canvas.drawBitmap(mBitmap, null, mBitmapRectF, null);
        canvas.restore();
    }
}

再梳理一下过程

在Activity中给recyclerview的LinearLayoutManager 绑定一个监听(onScroollListener()),
监听滚动
找到可显示的item中的 有 AdimgView的item,然后recyclerview的高度减去itemview顶部的高度得到
itemview顶部到底部的高度,
将次高度传入adimgview中
这个高度减去adimgview自身的高度。就是canvas 作图的偏移量
然后通过这个偏移量canva 画出bitmap任意的一部分内容

上一篇下一篇

猜你喜欢

热点阅读