高仿小紅書筆記詳情

效果圖:

redbook.gif

git鏈接:https://github.com/BelongsH/RedBook

大概介紹一下項目里面的一些知識點:

  • 動態(tài)更改ViewPager的高度
  • RecyclerView瀑布流的處理
  • RecyclerView多type的處理
如何動態(tài)的去修改ViewPager的高度?

要動態(tài)的修改ViewPager的高度,首先需要知道ViewPager中每一個Item的高度。那么怎么確定高度呢?在開發(fā)中,一般服務(wù)端會把圖片的寬度和高度通過api傳給我們, 如果沒有的話,我們也可以通過圖片加載框架獲取到圖片本身的寬和高。

Paste_Image.png

假設(shè)這個時候,服務(wù)端傳給我們這樣的數(shù)據(jù),我們就可以知道圖片的寬和高。因為寬度是充滿全屏不變的。然后我們拿圖片的原始寬度/屏幕的寬度=縮放比率。通過這個縮放比率,就可以知道圖片的高度。然后把它封裝到一個數(shù)據(jù)結(jié)構(gòu)中,方便使用。

    public class PictureSize {
        private int originalHeight;
        private int originalWidth;
        private float scale;
        private int scaleHeight;
        private int scaleWidth;


        public static PictureSize caculatePictureSize(int originalHeight, int originalWidth, int screenWidth) {
            PictureSize pictureSize = new PictureSize();
            pictureSize.originalHeight = originalHeight;
            pictureSize.originalWidth = originalWidth;
            pictureSize.scale = (screenWidth + 0f) / originalWidth;
            pictureSize.scaleHeight = (int) (originalHeight * pictureSize.scale);
            pictureSize.scaleWidth = screenWidth;
            return pictureSize;
        }  
    } 

這樣的話,我們可以計算出ViewPage中的每一個item的高度。那么現(xiàn)在需要處理的就是滑動的距離和圖片高度縮放的問題。首先我們需要獲取到ViewPage的滑動比率(是指滑動距離相對整個屏幕的百分比)。通過setPageTransformer的方法就可以獲取到一個position,這個position是相對View的一個的滑動比率。然后用這個滑動比率*item之間的高度差,就可以計算出滑動的高度值。

    holder1.vpHeadDelegate.setPageTransformer(true, new ViewPager.PageTransformer() {
                @Override
                public void transformPage(View page, float position) {
                    if (position > 0 && position <= 1) {
                        int badgePosition = (int) (page.getX() / screenWidth) - 1;
                        PictureSize offsetModel = mPictureSizes.get(String.valueOf(badgePosition + 1));
                        if (offsetModel == null) return;
                        PictureSize nowModel = mPictureSizes.get(String.valueOf(badgePosition));
                        float disHeight = (offsetModel.getScaleHeight() - nowModel.getScaleHeight()) * (1 - position);
                        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) holder1.vpHeadDelegate.getLayoutParams();
                        params.width = nowModel.getScaleWidth();
                        params.height = (int) (nowModel.getScaleHeight() + disHeight);
                        holder1.vpHeadDelegate.setLayoutParams(params);
                        holder1.vpHeadDelegate.requestLayout();
                    }
                }
            });

這樣的話,我們就完成了,動態(tài)更改ViewPager的高度。

RecyclerView瀑布流的處理

使用RecyclerView來處理瀑布流的話,是非常easy的事情.通過

     RecyclerView.LayoutManager layoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
            rvMain.setLayoutManager(layoutManager);

然后動態(tài)的去計算每一個item的高度

     ViewHolder viewHolder = (ViewHolder) holder;
            NoteModel itemModel = (NoteModel) items.get(position);
            PictureModel model = itemModel.pictures.get(0);
            LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) viewHolder.ivContentImage.getLayoutParams();
            float halfWidth = (ScreenUtils.getScreenWidth(holder.itemView.getContext()) - 60) / 2;
            layoutParams.width = (int) halfWidth;
            PictureSize pictureSize = PictureSize.caculatePictureSize(model.height, model.width, (int) halfWidth);
            layoutParams.height = pictureSize.getScaleHeight();
            viewHolder.ivContentImage.setLayoutParams(layoutParams);
            viewHolder.tvNoteDes.setText(itemModel.desc);
            viewHolder.tvNoteTitle.setText(itemModel.title);
            viewHolder.tvUserName.setText(itemModel.user.nickname);
            viewHolder.tvNoteTitle.setText(itemModel.title);
            StaggeredGridLayoutManager.LayoutParams params = (StaggeredGridLayoutManager.LayoutParams) viewHolder.itemView.getLayoutParams();
            params.setMargins(15, 15, 15, 15);
            holder.itemView.setLayoutParams(params);
            Glide.with(holder.itemView.getContext()).load(model.url).centerCrop().diskCacheStrategy(DiskCacheStrategy.ALL).into(viewHolder.ivContentImage);

需要注意的是,在StaggeredGridLayoutManager需要讓item全屏的話,可以這樣:

  HeadViewHolder headViewHolder = new HeadViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_note_head, parent, false));
        StaggeredGridLayoutManager.LayoutParams layoutParams = new StaggeredGridLayoutManager.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        layoutParams.setFullSpan(true);
        headViewHolder.itemView.setLayoutParams(layoutParams);
        screenWidth = (ScreenUtils.getScreenWidth(parent.getContext()) + 0f);
RecyclerView多type的處理

在RecyclerView.Adapter 中處理多type的話,會讓代碼變得臃腫,而且不易協(xié)作開發(fā)。比如

public class NoteAdapter extends RecyclerView.Adapter {

  final int VIEW_TYPE_ACCESS_0 = 0;
  final int VIEW_TYPE_ACCESS_1 = 1;
  final int VIEW_TYPE_ACCESS_2 = 2;
  final int VIEW_TYPE_ACCESS_3 = 3;

  List<Accessory> items;

  @Override public int getItemViewType(int position) {
     Accessory accessory = items.get(postion);
     if (position==0){
       return VIEW_TYPE_ACCESS_0;
     } else if(position==1) {
       return VIEW_TYPE_ACCESS_1;
     }else if(position==2) {
       return VIEW_TYPE_ACCESS_2;
     }else  {
       return VIEW_TYPE_ACCESS_3;
     }
  }

  @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    if (VIEW_TYPE_ACCESS_0 == viewType){
      return new ViewHolder1(inflater.inflate(R.layout.item_1, parent));
    } else if(VIEW_TYPE_ACCESS_1==viewType) {
      return new ViewHolder2 (inflater.inflate(R.layout.ietm_2,parent)):
    }else if(VIEW_TYPE_ACCESS_2==viewType) {
      return new ViewHolder2 (inflater.inflate(R.layout.ietm_3,parent)):
    }else if(VIEW_TYPE_ACCESS_3==viewType) {
      return new ViewHolder2 (inflater.inflate(R.layout.ietm_4,parent)):
    }
  }
}

這樣的話,所有的代碼都在一個類中,代碼會變得越來越臃腫。不易維護。而且協(xié)作開發(fā)問題也是非常的大,(多人操作同一文件)我們可以通過給Adapter設(shè)置一個代理,由它來完成所需要的操作。下面是對這個代理的抽象

   public abstract class AdapterDelegate<T> {
      protected abstract boolean isForViewType(@NonNull T items, int position);
      @NonNull abstract protected RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent);
      protected abstract void onBindViewHolder(@NonNull T items, int position,
          @NonNull RecyclerView.ViewHolder holder, @NonNull List<Object> payloads);
      protected void onViewRecycled(@NonNull RecyclerView.ViewHolder viewHolder) {}
      protected boolean onFailedToRecycleView(@NonNull RecyclerView.ViewHolder holder) {
        return false;
      }
      protected void onViewAttachedToWindow(@NonNull RecyclerView.ViewHolder holder) {}
      protected void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) {}
    }

然后我們將自己的核心代理繼承并實現(xiàn)這個基類,在isForViewType中來判斷當(dāng)前的position是不是我們需要處理的Item,然后在onCreateViewHolder>onBindViewHolder。

    public class ContentDelegate extends AdapterDelegate<List<HomeModel>> {


        @Override
        protected boolean isForViewType(@NonNull List<HomeModel> items, int position) {
            return items.get(position) instanceof NoteModel;
        }

        @NonNull
        @Override
        protected RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_note_notes, parent, false);
            return new ViewHolder(view);
        }

        @Override
        protected void onBindViewHolder(@NonNull List<HomeModel> items, int position, @NonNull RecyclerView.ViewHolder holder, @NonNull List<Object> payloads) {
            ViewHolder viewHolder = (ViewHolder) holder;
            NoteModel itemModel = (NoteModel) items.get(position);
            PictureModel model = itemModel.pictures.get(0);
            LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) viewHolder.ivContentImage.getLayoutParams();
            float halfWidth = (ScreenUtils.getScreenWidth(holder.itemView.getContext()) - 60) / 2;
            layoutParams.width = (int) halfWidth;
            PictureSize pictureSize = PictureSize.caculatePictureSize(model.height, model.width, (int) halfWidth);
            layoutParams.height = pictureSize.getScaleHeight();
            viewHolder.ivContentImage.setLayoutParams(layoutParams);
            viewHolder.tvNoteDes.setText(itemModel.desc);
            viewHolder.tvNoteTitle.setText(itemModel.title);
            viewHolder.tvUserName.setText(itemModel.user.nickname);
            viewHolder.tvNoteTitle.setText(itemModel.title);
            StaggeredGridLayoutManager.LayoutParams params = (StaggeredGridLayoutManager.LayoutParams) viewHolder.itemView.getLayoutParams();
            params.setMargins(15, 15, 15, 15);
            holder.itemView.setLayoutParams(params);
            Glide.with(holder.itemView.getContext()).load(model.url).centerCrop().diskCacheStrategy(DiskCacheStrategy.ALL).into(viewHolder.ivContentImage);
            Glide.with(viewHolder.ivContentImage.getContext()).load(itemModel.user.images).override(pictureSize.getScaleWidth(), pictureSize.getScaleHeight()).diskCacheStrategy(DiskCacheStrategy.ALL).bitmapTransform(new CropCircleTransformation(viewHolder.ivUserHead.getContext())).placeholder(R.drawable.ic_default_head).into(viewHolder.ivUserHead);
        }
    }

而這些核心代理會在AdapterDelegatesManager中被添加到AdapterDelegatesManager中,進行判斷當(dāng)前的邏輯,所以你需要做的就是繼承AbsDelegationAdapter,然后,將自己的多type添加進去即可。

    public class HomeAdapter extends AbsDelegationAdapter<List<HomeModel>> {
        private List<HomeModel> mDatas;
        public HomeAdapter(List<HomeModel> datas) {
            super();
            setItems(datas);
            this.mDatas = datas;
            this.delegatesManager.addDelegate(new HeadDelegate());
            this.delegatesManager.addDelegate(new ContentDelegate());
            this.delegatesManager.addDelegate(new CommentDelegate());
        }

        @Override
        public int getItemCount() {
            return mDatas.size();
        }
    }

關(guān)于多type的更多介紹:
http://hannesdorfmann.com/android/adapter-delegates
https://github.com/BelongsH/RedBook

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容