Android 技术文章简化开发常用收藏

RecyclerView使用StaggeredGridLayou

2021-06-17  本文已影响0人  编程的猫
Screenshot_2021-06-17-20-38-52-023_com.ww.myapplication.jpg

header是一个宽度占满全屏的item,下边是一个瀑布流。

要点:

下边展示代码:
MainActivity的布局文件:activity_main.xml

<?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">
    <!--    <data>-->
    <!--        <variable-->
    <!--            name="user"-->
    <!--            type="com.ww.myapplication.model.User" />-->
    <!--    </data>-->
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_constraintBottom_toTopOf="@+id/btn"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            />

        <Button
            android:id="@+id/btn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="添加数据"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

普通itemView的布局文件:item_normal.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView 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"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardCornerRadius="4dp">

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

        <ImageView
            android:id="@+id/show_iv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:contentDescription="展示图片"
            android:scaleType="centerCrop"
            tools:ignore="HardcodedText" />

        <TextView
            android:id="@+id/desc_tv"
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:gravity="start|center_vertical"
            android:paddingStart="8dp"
            android:textSize="16sp"
            tools:ignore="RtlSymmetry"
            tools:text="测试文字" />
    </LinearLayout>
</androidx.cardview.widget.CardView>

Header的布局文件:item_header.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

</LinearLayout>

给Adapter的数据,封装成了一个Model,每个itemView的高度来源于这个Model

package com.ww.myapplication.model;

public class ImageModel {
    private int imageRes;
    private String desc;
    // 图片的高度
    private double imageHeight;

    public ImageModel(int imageRes, String desc, double imageHeight) {
        this.imageRes = imageRes;
        this.desc = desc;
        this.imageHeight = imageHeight;
    }

    public int getImageRes() {
        return imageRes;
    }

    public void setImageRes(int imageRes) {
        this.imageRes = imageRes;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public double getImageHeight() {
        return imageHeight;
    }

    public void setImageHeight(double imageHeight) {
        this.imageHeight = imageHeight;
    }
}

MainActivity中调用的代码:

package com.ww.myapplication;

import android.graphics.Color;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;

import com.ww.myapplication.adapter.MyAdapter;
import com.ww.myapplication.adapter.SpaceItemDecoration;
import com.ww.myapplication.databinding.ActivityMainBinding;
import com.ww.myapplication.model.ImageModel;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 练习constraintLayout
 */
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static String TAG = "== MainActivity ==>";
    private ActivityMainBinding binding;

    private List<ImageModel> imageModels = new ArrayList<>();
    private int[] imgRes = {
            R.drawable.img1,
            R.drawable.img2,
            R.drawable.img3,
            R.drawable.cat,
            R.drawable.cat2,
            R.drawable.lion2,
            R.drawable.lion1
    };
    private String[] descNames = {
            "春风又绿江南岸",
            "十步杀一人,千里不留行",
            "明月何时照我还",
            "君不见,黄河之水天上来",
            "蜀道难,难于上青天",
            "落霞与孤鹜齐飞",
            "关山难越,谁悲失路之人",
            "两岸猿声啼不住",
            "海上生明月,天涯共此时",
            "乘舟侧畔千帆过",
            "青青子衿,依依我心"
    };
    private MyAdapter myAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityMainBinding.inflate(LayoutInflater.from(this));
        setContentView(binding.getRoot());

        binding.btn.setOnClickListener(this);

        increaseData();

        StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
        staggeredGridLayoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
        binding.rv.setLayoutManager(staggeredGridLayoutManager);

       // 设置网格布局
       //  GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2);
       //   binding.rv.setLayoutManager(gridLayoutManager);

        SpaceItemDecoration dividerItemDecoration = new SpaceItemDecoration(16);
        binding.rv.addItemDecoration(dividerItemDecoration);

        myAdapter = new MyAdapter();

        TextView textView = new TextView(this);
        LinearLayout.LayoutParams textViewLp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 50);
        textViewLp.gravity = Gravity.CENTER;
        textView.setText("这是Header Item");
        textView.setTextColor(Color.parseColor("#000000"));
        textView.setGravity(Gravity.CENTER);
        textView.setLayoutParams(textViewLp);
        myAdapter.addHeader(textView);

        binding.rv.setAdapter(myAdapter);

        myAdapter.addData(imageModels);


    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.btn) {

            myAdapter.addData(increaseData());


        }
    }

    private List<ImageModel> increaseData() {
        imageModels.clear();

        Random random = new Random();
        // 初始数据
        for (int i = 0; i < 10; i++) {
            imageModels.add(new ImageModel(imgRes[random.nextInt(imgRes.length)],
                    descNames[random.nextInt(descNames.length)],
                    getRandomDouble()));
        }
        return imageModels;
    }

    public double getRandomDouble() {
        Random random = new Random();
        double nextDouble = random.nextDouble();
        if (nextDouble < 0.1) {
            nextDouble = nextDouble + 0.55;
        }
        return nextDouble;
    }

}

MyAdapter的代码:

package com.ww.myapplication.adapter;

import android.content.Context;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;

import com.ww.myapplication.R;
import com.ww.myapplication.model.ImageModel;

import java.util.ArrayList;
import java.util.List;

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyHolder> {

    public static int ITEM_HEADER = 0x012;
    public static int ITEM_NORMAL = 0x013;
    public static int ITEM_FOOTER = 0x014;

    private List<View> headerList = new ArrayList<>();
    private List<View> footerList = new ArrayList<>();
    private List<ImageModel> data;

    public MyAdapter() {
        data = new ArrayList<>();
    }

    public void addData(List<ImageModel> newData) {
        if (newData != null && newData.size() > 0) {
            data.addAll(newData);
            notifyItemInserted(data.size());
        }
    }

    public void addFooter(View view) {
        if (view != null) {
            footerList.add(view);
        }
    }

    public void addHeader(View view) {
        if (view != null) {
            headerList.add(view);
        }
    }

    @Override
    public int getItemViewType(int position) {

        if (position < headerList.size()) {
            // header item
            return ITEM_HEADER;
        } else if (position >= (headerList.size() + data.size())) {
            // footer item
            return ITEM_FOOTER;
        } else {
            // 正常的Item
            return ITEM_NORMAL;
        }
    }

    @NonNull
    @Override
    public MyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = null;
        if (viewType == ITEM_HEADER || viewType == ITEM_FOOTER) {
            // header item
            view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_header, parent, false);
        } else {
            // 正常普通的item
            view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_normal, parent, false);
        }
        return new MyHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MyHolder holder, int position) {
        if (holder.getItemViewType() == ITEM_HEADER) {
            LinearLayout headerViewParent = (LinearLayout) holder.itemView;
            if (headerViewParent.getChildCount() == 0) {
                Log.d("==TAG==>", "添加 header 子View");
                for (View view : headerList) {
                    // 将header view添加到itemView中
                    headerViewParent.addView(view);
                }
            }
        } else if (holder.getItemViewType() == ITEM_FOOTER) {
            LinearLayout footerViewParent = (LinearLayout) holder.itemView;
            if (footerViewParent.getChildCount() == 0) {
                Log.d("==TAG==>", "添加 footer 子View");
                for (View view : footerList) {
                    // 将footer view添加到itemView中
                    footerViewParent.addView(view);
                }
            }
        } else {
            ImageModel imageModel = data.get(position - headerList.size());

            RecyclerView.LayoutManager manager = mRecyclerView.getLayoutManager();
            if (manager instanceof StaggeredGridLayoutManager) {
                int screenWidth = getScreenWidth(holder.itemView.getContext());
                ViewGroup.LayoutParams lp = holder.showIv.getLayoutParams();
                lp.width = screenWidth / 2;
                // 固定设置每个ItemView的高度,防止滑动的复用ItemView的时候重新分配itemView的高度
                lp.height = (int) (screenWidth * imageModel.getImageHeight());
                holder.showIv.setLayoutParams(lp);
            } else if (manager instanceof GridLayoutManager) {
                int screenWidth = getScreenWidth(holder.itemView.getContext());
                ViewGroup.LayoutParams lp = holder.showIv.getLayoutParams();
                lp.width = screenWidth / 2;
                // 固定设置每个ItemView的高度,防止滑动的复用ItemView的时候重新分配itemView的高度
                lp.height = (int) (screenWidth * 2 / 3);
                holder.showIv.setLayoutParams(lp);
            } else {
                int screenWidth = getScreenWidth(holder.itemView.getContext());
                ViewGroup.LayoutParams lp = holder.showIv.getLayoutParams();
                lp.width = screenWidth / 2;
                // 固定设置每个ItemView的高度,防止滑动的复用ItemView的时候重新分配itemView的高度
                lp.height = (int) (screenWidth / 3);
                holder.showIv.setLayoutParams(lp);
            }
            holder.descTv.setText(imageModel.getDesc());
            holder.showIv.setImageResource(imageModel.getImageRes());
        }


    }

    private RecyclerView mRecyclerView;

    @Override
    public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        this.mRecyclerView = recyclerView;
        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
            gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    // 指定每个item占用几个网格坑位
                    if (position < headerList.size() || position >= (headerList.size()) + data.size()) {
                        // header 或者 footer
                        return gridLayoutManager.getSpanCount();
                    }
                    return 1;
                }
            });
        }
    }

    @Override
    public void onViewAttachedToWindow(@NonNull MyHolder holder) {
        super.onViewAttachedToWindow(holder);
        ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
        if (lp instanceof StaggeredGridLayoutManager.LayoutParams) {
            // 瀑布流的布局参数
            StaggeredGridLayoutManager.LayoutParams layoutParams = (StaggeredGridLayoutManager.LayoutParams) lp;
            if (holder.getItemViewType() == ITEM_HEADER || holder.getItemViewType() == ITEM_FOOTER) {
                layoutParams.setFullSpan(true);
                holder.itemView.setLayoutParams(layoutParams);
            } else {
                layoutParams.setFullSpan(false);
                holder.itemView.setLayoutParams(layoutParams);
            }
        }
    }

    @Override
    public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
        super.onDetachedFromRecyclerView(recyclerView);
    }

    @Override
    public void onViewDetachedFromWindow(@NonNull MyHolder holder) {
        super.onViewDetachedFromWindow(holder);
    }

    @Override
    public int getItemCount() {
        return data.size() + headerList.size() + footerList.size();
    }

    static class MyHolder extends RecyclerView.ViewHolder {

        private final ImageView showIv;
        private final TextView descTv;

        public MyHolder(@NonNull View itemView) {
            super(itemView);
            showIv = itemView.findViewById(R.id.show_iv);
            descTv = itemView.findViewById(R.id.desc_tv);

            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(itemView.getContext(), "position:" + getLayoutPosition(), Toast.LENGTH_SHORT).show();
                }
            });

        }
    }

    public int getScreenWidth(Context context) {
        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        windowManager.getDefaultDisplay().getMetrics(displayMetrics);
        return displayMetrics.widthPixels;
    }

    public int getScreenHeight(Context context) {
        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        windowManager.getDefaultDisplay().getRealMetrics(displayMetrics);
        return displayMetrics.heightPixels;
    }


}

每个itemView的分割线:

package com.ww.myapplication.adapter;

import android.graphics.Rect;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

public class SpaceItemDecoration extends RecyclerView.ItemDecoration {
    private int space;

    public SpaceItemDecoration(int space) {
        this.space = space;
    }

    @Override
    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        outRect.left = space;
        outRect.top = space;
        outRect.right = space;
        outRect.bottom = space;
    }
}

recyclerView

上一篇下一篇

猜你喜欢

热点阅读