前言
前面我们有介绍RecyclerView的使用,详见《Android中RecyclerView嵌套RecyclerView》,这一篇我们来讲讲RecyclerView的不规则Grid显示。
先上图看看效果
从上图里面我们可以看到,我们在单元模块中有标题栏和功能项,其实这个都昌在一个RecyclerView中实现的,下面我们就来介绍一下实现的方法。
代码演示
首先我们先建一个类,用于加载这些功能和标题的
CMenu
package sum.prm.pkgsys.main.mod;
/**
* 作者:Vaccae
* 邮箱:3657447@qq.com
* 创建时间:2019-02-26 14:14
* 功能模块说明:功能菜单类
*/
public class CMenu {
public CMenu() {
menuname = "";
menubmp = 0;
menuclass = null;
istitle = true;
}
//菜单名称
public String menuname;
//菜单图标
public int menubmp;
//菜单模块
public Class<?> menuclass;
//是否标题
public boolean istitle;
}
然后再写一个方法,创建我们开始上图中所需要显示的标题及功能
menuopt
package sum.prm.pkgsys.main.bll;
import java.util.ArrayList;
import java.util.List;
import sum.prm.pkgsys.R;
import sum.prm.pkgsys.cfg.CfgActivity;
import sum.prm.pkgsys.main.mod.CMenu;
import sum.prm.pkgwh.whin.WhInActivity;
import sum.prm.pkgwh.whout.WhOutActivity;
/**
* 作者:Vaccae
* 邮箱:3657447@qq.com
* 创建时间:2019-02-26 14:51
* 功能模块说明:
*/
public class menuopt {
public static List<CMenu> GetMenuList() {
List<CMenu> menus = new ArrayList<>();
//出入库业务
CreateWh(menus);
//报表查询
CreateRpt(menus);
//系统菜单增加
CreateSys(menus);
return menus;
}
/**
* 出入库业务
* @param menus
*/
private static void CreateWh(List<CMenu> menus) {
//出入库业务标题
CMenu menuwh = new CMenu();
menuwh.menuname = "出入库业务";
menuwh.menubmp = 0;
menuwh.menuclass = null;
menuwh.istitle = true;
menus.add(menuwh);
//组托入库
menuwh = new CMenu();
menuwh.menuname = "组托入库";
menuwh.menubmp = R.drawable.menu_whin;
menuwh.menuclass=WhInActivity.class;
menuwh.istitle = false;
menus.add(menuwh);
//扫描出库
menuwh=new CMenu();
menuwh.menuname="扫描出库";
menuwh.menubmp = R.drawable.menu_whout;
menuwh.menuclass=WhOutActivity.class;
menuwh.istitle = false;
menus.add(menuwh);
//托盘管理
menuwh=new CMenu();
menuwh.menuname="托盘管理";
menuwh.menubmp=R.drawable.menu_pallet;
menuwh.menuclass=WhInActivity.class;
menuwh.istitle=false;
menus.add(menuwh);
}
private static void CreateRpt(List<CMenu> menus) {
//报表查询标题
CMenu menurpt=new CMenu();
menurpt.menuname="报表查询";
menurpt.menubmp=0;
menurpt.menuclass=null;
menurpt.istitle=true;
menus.add(menurpt);
//库存查询
menurpt=new CMenu();
menurpt.menuname="库存查询";
menurpt.menubmp=R.drawable.menu_qry;
menurpt.menuclass=null;
menurpt.istitle=false;
menus.add(menurpt);
}
/**
* 系统菜单增加
* @param menus
*/
private static void CreateSys(List<CMenu> menus) {
//系统参数
CMenu menusys = new CMenu();
menusys.menuname = "系统参数";
menusys.menubmp = 0;
menusys.menuclass = null;
menusys.istitle = true;
menus.add(menusys);
//参数设置
menusys = new CMenu();
menusys.menuname = "参数设置";
menusys.menubmp = R.drawable.menu_cfg;
menusys.menuclass=CfgActivity.class;
menusys.istitle = false;
menus.add(menusys);
}
}
接下来我们看一下activity_main的布局文件
activity_main.xml、
然后我们看一下RecyclerView的布局
rcl_menu.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:weightSum="10"
android:orientation="vertical">
<view.XCRoundImageView
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_margin="10dp"
android:background="@drawable/shape"
android:scaleType="centerInside"
android:layout_gravity="center_horizontal"
android:id="@+id/rcl_menu_img"
android:layout_weight="8" />
<TextView
android:text="TextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:id="@+id/rcl_menu_tv"
android:textSize="9pt"
android:layout_weight="2" />
</LinearLayout>
显示的效果就是一个图片下面加一个文本
上面的XCRoundImageView是我自己设计的一个圆角矩形的方法,如果不需要我们直接用ImageView即可。
XCRoundImageView
package view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
public class XCRoundImageView extends android.support.v7.widget.AppCompatImageView {
private Paint paint ;
public XCRoundImageView(Context context) {
this(context,null);
}
public XCRoundImageView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public XCRoundImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
paint = new Paint();
}
/**
* 绘制圆形图片
* @author caizhiming
*/
@Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
if (null != drawable) {
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
Bitmap b = getCircleBitmap(bitmap, 14);
final Rect rectSrc = new Rect(0, 0, b.getWidth(), b.getHeight());
final Rect rectDest = new Rect(0,0,getWidth(),getHeight());
paint.reset();
canvas.drawBitmap(b, rectSrc, rectDest, paint);
} else {
super.onDraw(canvas);
}
}
/**
* 获取圆形图片方法
* @param bitmap
* @param pixels
* @return Bitmap
* @author caizhiming
*/
private Bitmap getCircleBitmap(Bitmap bitmap, int pixels) {
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
int x = bitmap.getWidth();
canvas.drawCircle(x / 2, x / 2, x / 2, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
}
XML已经创建好了,下面我们就要写对应的Adapter了
menuAdapter
package sum.prm.pkgsys.main;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Typeface;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.text.TextPaint;
import android.text.style.TextAppearanceSpan;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
import comm.user.CUserInfo;
import sum.prm.pkgsys.R;
import sum.prm.pkgsys.main.mod.CMenu;
import utils.image.imgHelper;
import view.XCRoundImageView;
/**
* 作者:Vaccae
* 邮箱:3657447@qq.com
* 创建时间:2019-02-26 14:07
* 功能模块说明:
*/
public class menuAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<CMenu> mMenulist;
private CUserInfo userInfo;
private Context mContext;
public menuAdapter(Context context,List<CMenu> list,CUserInfo info) {
mMenulist = list;
mContext = context;
userInfo=info;
}
public static class menuHolder extends RecyclerView.ViewHolder {
private XCRoundImageView img;
private TextView tv;
public menuHolder(View itemView) {
super(itemView);
img = itemView.findViewById(R.id.rcl_menu_img);
tv = itemView.findViewById(R.id.rcl_menu_tv);
}
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(mContext).inflate(R.layout.rcl_menu, parent, false);
return new menuHolder(v);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
menuHolder mholder = (menuHolder) holder;
final CMenu item = mMenulist.get(position);
if (!item.istitle) {
//图片显示
Bitmap bmp = imgHelper.readBitMap(mContext, item.menubmp);
mholder.img.setImageBitmap(bmp);
mholder.img.setVisibility(View.VISIBLE);
//点击事件
mholder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(mContext, item.menuclass);
intent.putExtra("menuname", item.menuname);
intent.putExtra("userinfo", userInfo.ToJson());
mContext.startActivity(intent);
}
});
//设置文本的背景,字体及位置
mholder.tv.setBackgroundColor(mContext.getResources().getColor(R.color.colortransparent));
mholder.tv.setTextColor(mContext.getResources().getColor(R.color.seesimilarcolorThistle4));
mholder.tv.setTypeface(Typeface.defaultFromStyle(Typeface.NORMAL));
mholder.tv.setGravity(Gravity.CENTER);
} else {
mholder.img.setVisibility(View.GONE);
//设置文本的背景,字体及位置
mholder.tv.setBackgroundColor(mContext.getResources().getColor(R.color.seesimilarcolorThistle4));
mholder.tv.setTextColor(mContext.getResources().getColor(R.color.colorWhite));
mholder.tv.setTypeface(Typeface.defaultFromStyle(Typeface.NORMAL));
mholder.tv.setGravity(Gravity.LEFT);
}
//功能名称
mholder.tv.setText(item.menuname);
}
@Override
public int getItemCount() {
return mMenulist.size();
}
}
到这里准备工作基本都做完了,我们看一下怎么样实现显示的核心方法
ShowRecyclerView
private void ShowRecyclerView(final List<CMenu> list) {
rcl_menu = findViewById(R.id.main_rcl_menu);
final menuAdapter adapter = new menuAdapter(this, list, userInfo);
//设置布局管理器 , 将布局设置成纵向
final GridLayoutManager layoutManager = new GridLayoutManager(this, 3, GridLayoutManager.VERTICAL, false);
rcl_menu.setLayoutManager(layoutManager);
//根据是否标题判断显示几格
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
if (list.get(position).istitle) {
return layoutManager.getSpanCount();
} else {
return 1;
}
}
});
//设置分隔线
// rcl_menu.addItemDecoration(new DividerItemDecoration(this , DividerItemDecoration.VERTICAL));
//设置增加或删除条目动画
rcl_menu.setItemAnimator(new DefaultItemAnimator());
//填充数据
rcl_menu.setAdapter(adapter);
//取消局部更新时闪烁动画
((SimpleItemAnimator)rcl_menu.getItemAnimator()).setSupportsChangeAnimations(false);
}
重点就是上面标红框的地方,判断类里面是不是标题用于显示几列的情况。
MainActivity.java
package sum.prm.pkgsys.main;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SimpleItemAnimator;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.Toast;
import java.util.List;
import comm.user.CUserInfo;
import sum.prm.pkgsys.R;
import sum.prm.pkgsys.main.bll.menuopt;
import sum.prm.pkgsys.main.mod.CMenu;
import view.background;
public class MainActivity extends Activity {
private List<CMenu> mMenuList;
private CUserInfo userInfo;
private background bglayout;
private RecyclerView rcl_menu;
// 定义一个变量,计算退出时间,用于按两次退出
private long exitTime = 0;
//界面返回按钮事件,用于点击两次退出
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.i("keycode", "" + keyCode);
if (keyCode == KeyEvent.KEYCODE_BACK) {
exit();
return false;
}
return super.onKeyDown(keyCode, event);
}
//退出事件
private void exit() {
//大于两秒时重置
if (System.currentTimeMillis() - exitTime > 2000) {
Toast.makeText(getApplicationContext(), "再按一次退出",
Toast.LENGTH_SHORT).show();
exitTime = System.currentTimeMillis();
} else {
finish();
System.exit(0);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent=getIntent();
userInfo=CUserInfo.fromJson(intent.getStringExtra("userinfo"));
bglayout = findViewById(R.id.main_bglayout);
bglayout.SetFunName("功能菜单");
bglayout.SetUserInfo(userInfo.UserName, "设备号:" + userInfo.DevCode);
//获取功能列表
mMenuList = menuopt.GetMenuList();
//显示列表
ShowRecyclerView(mMenuList);
}
private void ShowRecyclerView(final List<CMenu> list) {
rcl_menu = findViewById(R.id.main_rcl_menu);
final menuAdapter adapter = new menuAdapter(this, list, userInfo);
//设置布局管理器 , 将布局设置成纵向
final GridLayoutManager layoutManager = new GridLayoutManager(this, 3, GridLayoutManager.VERTICAL, false);
rcl_menu.setLayoutManager(layoutManager);
//根据是否标题判断显示几格
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
if (list.get(position).istitle) {
return layoutManager.getSpanCount();
} else {
return 1;
}
}
});
//设置分隔线
// rcl_menu.addItemDecoration(new DividerItemDecoration(this , DividerItemDecoration.VERTICAL));
//设置增加或删除条目动画
rcl_menu.setItemAnimator(new DefaultItemAnimator());
//填充数据
rcl_menu.setAdapter(adapter);
//取消局部更新时闪烁动画
((SimpleItemAnimator)rcl_menu.getItemAnimator()).setSupportsChangeAnimations(false);
}
}
上面代码主要是我自己程序中用到的,直接复制出来使用会报错,我们可以自己修改一下MainActivity,把一些不需要的东西直接删除即可。
-END-