RecyclerView使用大全
RecylerView介绍
RecylerView是support-v7包中的新组件,是一个强大的滑动组件,与经典的ListView相比,同样拥有item回收复用的功能,这一点从它的名字recylerview即回收view也可以看出。官方对于它的介绍则是:RecyclerView 是 ListView 的升级版本,更加先进和灵活。RecyclerView通过设置LayoutManager,ItemDecoration,ItemAnimator实现你想要的效果。
- 使用LayoutManager来确定每一个item的排列方式。
- 使用ItemDecoration自己绘制分割线,更灵活
- 使用ItemAnimator为增加或删除一行设置动画效果。
注意
新建完项目,需要在app/build.gradle增加RecylerView依赖,不然找不到RecyclerView类
compile 'com.android.support:recyclerview-v7:23.1.0'
RecylerView简单的Demo
我们来看activity代码,跟ListView写法差不多,只是这边多设置了布局管理器。
public class LinearLayoutActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private RecyclerViewAdapter adapter;
private List<String> datas;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recycler_main);
initData();
recyclerView= (RecyclerView) findViewById(R.id.recyclerview);
recyclerView.setLayoutManager(new LinearLayoutManager(this));//设置布局管理器
recyclerView.addItemDecoration(new DividerItemDecoration(this));
recyclerView.setAdapter(adapter=new RecyclerViewAdapter(this,datas));
}
private void initData(){
datas=new ArrayList<>();
for(int i=0;i<100;i++){
datas.add("item:"+i);
}
}
}
activity对应的布局文件:recycler_main.xml
<?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="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
adapter相对ListView来说变化比较大的。把ViewHolder逻辑封装起来了,代码相对简单一些。
- 需要继承RecyclerView.Adapter,重写三个方法
- MyViewHolder需要继承RecyclerView.ViewHolder
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder>{
private List<String> datas;
private LayoutInflater inflater;
public RecyclerViewAdapter(Context context,List<String> datas){
inflater=LayoutInflater.from(context);
this.datas=datas;
}
//创建每一行的View 用RecyclerView.ViewHolder包装
@Override
public RecyclerViewAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView=inflater.inflate(R.layout.recycler_item,null);
return new MyViewHolder(itemView);
}
//给每一行View填充数据
@Override
public void onBindViewHolder(RecyclerViewAdapter.MyViewHolder holder, int position) {
holder.textview.setText(datas.get(position));
}
//数据源的数量
@Override
public int getItemCount() {
return datas.size();
}
class MyViewHolder extends RecyclerView.ViewHolder{
private TextView textview;
public MyViewHolder(View itemView) {
super(itemView);
textview= (TextView) itemView.findViewById(R.id.textview);
}
}
}
我们来看看效果图:
RecyclerView增加分隔线
RecyclerView是没有android:divider跟android:dividerHeight属性的,如果我们需要分割线,就只能自己动手去实现了。
- 需要继承ItemDecoration类,实现onDraw跟getItemOffsets方法。
- 调用RecyclerView的addItemDecoration方法。
我们先写一个DividerItemDecoration类,继承RecyclerView.ItemDecoration,在getItemOffsets留出item之间的间隔,然后就会调用onDraw方法绘制(onDraw的绘制优先于每一行的绘制)
public class DividerItemDecoration extends RecyclerView.ItemDecoration{
/*
* RecyclerView的布局方向,默认先赋值 为纵向布局
* RecyclerView 布局可横向,也可纵向
* 横向和纵向对应的分割线画法不一样
* */
private int mOrientation = LinearLayoutManager.VERTICAL;
private int mItemSize = 1;//item之间分割线的size,默认为1
private Paint mPaint;//绘制item分割线的画笔,和设置其属性
public DividerItemDecoration(Context context) {
this(context,LinearLayoutManager.VERTICAL,R.color.colorAccent);
}
public DividerItemDecoration(Context context, int orientation) {
this(context,orientation, R.color.colorAccent);
}
public DividerItemDecoration(Context context, int orientation, int dividerColor){
this(context,orientation,dividerColor,1);
}
/**
* @param context
* @param orientation 绘制方向
* @param dividerColor 分割线颜色 颜色资源id
* @param mItemSize 分割线宽度 传入dp值就行
*/
public DividerItemDecoration(Context context, int orientation, int dividerColor, int mItemSize){
this.mOrientation = orientation;
if(orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL){
throw new IllegalArgumentException("请传入正确的参数") ;
}
//把dp值换算成px
this.mItemSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,mItemSize,context.getResources().getDisplayMetrics());
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(context.getResources().getColor(dividerColor));
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
if(mOrientation == LinearLayoutManager.VERTICAL){
drawVertical(c,parent) ;
}else {
drawHorizontal(c,parent) ;
}
}
/**
* 绘制纵向 item 分割线
* @param canvas
* @param parent
*/
private void drawVertical(Canvas canvas,RecyclerView parent){
final int left = parent.getPaddingLeft() ;
final int right = parent.getMeasuredWidth() - parent.getPaddingRight();
final int childSize = parent.getChildCount() ;
for(int i = 0 ; i < childSize ; i ++){
final View child = parent.getChildAt( i ) ;
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
final int top = child.getBottom() + layoutParams.bottomMargin ;
final int bottom = top + mItemSize ;
canvas.drawRect(left,top,right,bottom,mPaint);
}
}
/**
* 绘制横向 item 分割线
* @param canvas
* @param parent
*/
private void drawHorizontal(Canvas canvas,RecyclerView parent){
final int top = parent.getPaddingTop() ;
final int bottom = parent.getMeasuredHeight() - parent.getPaddingBottom() ;
final int childSize = parent.getChildCount() ;
for(int i = 0 ; i < childSize ; i ++){
final View child = parent.getChildAt( i ) ;
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
final int left = child.getRight() + layoutParams.rightMargin ;
final int right = left + mItemSize ;
canvas.drawRect(left,top,right,bottom,mPaint);
}
}
/**
* 设置item分割线的size
* @param outRect
* @param view
* @param parent
* @param state
*/
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if(mOrientation == LinearLayoutManager.VERTICAL){
outRect.set(0,0,0,mItemSize);//垂直排列 底部偏移
}else {
outRect.set(0,0,mItemSize,0);//水平排列 右边偏移
}
}
}
不要忘记调用addItemDecoration方法哦
recyclerView.addItemDecoration(new DividerItemDecoration(this));//添加分割线
重新运行,效果图:
大家读到这里肯定会有一个疑问,这货比ListView麻烦多了啊,但是google官方为什么要说是ListView的升级版呢?接下来开始放大招。。。
GridLayoutManager
在RecyclerView中实现不同的列表,只需要切换不同的LayoutManager即可。RecyclerView.LayoutManager跟RecyclerView.ItemDecoration一样,都是RecyclerView静态抽象内部类,但是LayoutManager有三个官方写好的实现类。
- LinearLayoutManager 线性布局管理器 跟ListView功能相似
- GridLayoutManager 网格布局管理器 跟GridView功能相似
- StaggeredGridLayoutManager 瀑布流布局管理器
刚刚我们用的是LinearLayoutManager,现在我们切换到GridLayoutManager,看到下面这句代码,有没有感觉分分钟切换不同列表显示。
recyclerView.setLayoutManager(new GridLayoutManager(this,2));
如果要显示多列或者要纵向显示就new不同的构造方法,以下代码纵向显示4列。当前如果你还需要反方向显示,把false改成true就可以。
recyclerView.setLayoutManager(new GridLayoutManager(this,4,GridLayoutManager.HORIZONTAL,false));
因为用的是网格布局,所以呢绘制分割线的代码需要重新修改一下。网格布局一行可以有多列,并且最后一列跟最后一行不需要绘制,所以我们得重新创建一个类。
DividerGridItemDecoration.java
public class DividerGridItemDecoration extends RecyclerView.ItemDecoration {
/*
* RecyclerView的布局方向,默认先赋值 为纵向布局
* RecyclerView 布局可横向,也可纵向
* 横向和纵向对应的分割线画法不一样
* */
private int mOrientation = LinearLayoutManager.VERTICAL;
private int mItemSize = 1;//item之间分割线的size,默认为1
private Paint mPaint;//绘制item分割线的画笔,和设置其属性
public DividerGridItemDecoration(Context context) {
this(context,LinearLayoutManager.VERTICAL,R.color.colorAccent);
}
public DividerGridItemDecoration(Context context, int orientation) {
this(context,orientation, R.color.colorAccent);
}
public DividerGridItemDecoration(Context context, int orientation, int dividerColor){
this(context,orientation,dividerColor,1);
}
/**
* @param context
* @param orientation 绘制方向
* @param dividerColor 分割线颜色 颜色资源id
* @param mItemSize 分割线宽度 传入dp值就行
*/
public DividerGridItemDecoration(Context context, int orientation, int dividerColor, int mItemSize){
this.mOrientation = orientation;
if(orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL){
throw new IllegalArgumentException("请传入正确的参数") ;
}
//把dp值换算成px
this.mItemSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,mItemSize,context.getResources().getDisplayMetrics());
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(context.getResources().getColor(dividerColor));
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
drawHorizontal(c, parent);
drawVertical(c, parent);
}
private int getSpanCount(RecyclerView parent) {
// 列数
int spanCount = -1;
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount();
}
return spanCount;
}
public void drawHorizontal(Canvas canvas, RecyclerView parent) {
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
final int left = child.getLeft() - params.leftMargin;
final int right = child.getRight() + params.rightMargin + mItemSize;
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mItemSize;
canvas.drawRect(left,top,right,bottom,mPaint);
}
}
public void drawVertical(Canvas canvas, RecyclerView parent) {
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
final int top = child.getTop() - params.topMargin;
final int bottom = child.getBottom() + params.bottomMargin;
final int left = child.getRight() + params.rightMargin;
final int right = left + mItemSize;
canvas.drawRect(left,top,right,bottom,mPaint);
}
}
@Override
public void getItemOffsets(Rect outRect, int itemPosition,RecyclerView parent) {
int spanCount = getSpanCount(parent);
int childCount = parent.getAdapter().getItemCount();
if (isLastRow(parent, itemPosition, spanCount, childCount)){//如果是最后一行,不需要绘制底部
outRect.set(0, 0, mItemSize, 0);
} else if (isLastColum(parent, itemPosition, spanCount, childCount)){// 如果是最后一列,不需要绘制右边
outRect.set(0, 0, 0, mItemSize);
} else {
outRect.set(0, 0, mItemSize,mItemSize);
}
}
private boolean isLastColum(RecyclerView parent, int pos, int spanCount, int childCount) {
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
if ((pos + 1) % spanCount == 0){// 如果是最后一列,则不需要绘制右边
return true;
}
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
int orientation = ((StaggeredGridLayoutManager) layoutManager).getOrientation();
if (orientation == StaggeredGridLayoutManager.VERTICAL) {
if ((pos + 1) % spanCount == 0){// 如果是最后一列,则不需要绘制右边
return true;
}
} else {
childCount = childCount - childCount % spanCount;
if (pos >= childCount)// 如果是最后一列,则不需要绘制右边
return true;
}
}
return false;
}
private boolean isLastRow(RecyclerView parent, int pos, int spanCount, int childCount) {
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
childCount = childCount - childCount % spanCount;
if (pos >= childCount)//最后一行
return true;
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
int orientation = ((StaggeredGridLayoutManager) layoutManager).getOrientation();
if (orientation == StaggeredGridLayoutManager.VERTICAL){//纵向
childCount = childCount - childCount % spanCount;
if (pos >= childCount)//最后一行
return true;
} else{ //横向
if ((pos + 1) % spanCount == 0) {//是最后一行
return true;
}
}
}
return false;
}
}
写了这两个画分割线的类,主流的布局:线性列表跟网格列表都能展示了。。。赶紧运行代码看看结果:
StaggeredGridLayoutManager
actviity中修改下布局管理器,大家应该感觉很熟悉了吧~~~
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL));
瀑布流列表一般列的高度是不一致的,为了模拟不同的宽高,数据源我把String类型改成了对象.然后初始化的时候随机了一个高度.
public class ItemData {
private String content;//item内容
private int height;//item高度
public ItemData() {
}
public ItemData(String content, int height) {
this.content = content;
this.height = height;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
瀑布流列表没有添加分割线,给item布局设置了android:padding属性。recycler_staggered_item.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:padding="5dp"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<TextView
android:id="@+id/textview"
android:background="@color/colorAccent"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="122"
android:textSize="20sp"/>
</FrameLayout>
最后我们在适配器的onBindViewHolder方法中给itemd中的TextView设置一个高度
@Override
public void onBindViewHolder(StaggeredGridAdapter.MyViewHolder holder, int position) {
ItemData itemData=datas.get(position);
holder.textview.setText(itemData.getContent());
//手动更改高度,不同位置的高度有所不同
holder.textview.setHeight(itemData.getHeight());
}
是不是感觉so easy,赶紧运行看看效果:
添加header跟footer
RecyclerView添加头部跟底部是没有对应的api的,但是我们很多的需求都会用到,于是只能自己想办法实现了。我们可以通过适配器的getItemViewType方法来实现这个功能。
修改后的适配器代码:RecyclerHeadFootViewAdapter.java
public class RecyclerHeadFootViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
private List<String> datas;
private LayoutInflater inflater;
public static final int TYPE_HEADER=1;//header类型
public static final int TYPE_FOOTER=2;//footer类型
private View header=null;//头View
private View footer=null;//脚View
public RecyclerHeadFootViewAdapter(Context context, List<String> datas){
inflater=LayoutInflater.from(context);
this.datas=datas;
}
//创建每一行的View 用RecyclerView.ViewHolder包装
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if(viewType==TYPE_HEADER){
return new RecyclerView.ViewHolder(header){};
}else if(viewType==TYPE_FOOTER){
return new RecyclerView.ViewHolder(footer){};
}
View itemView=inflater.inflate(R.layout.recycler_item,null);
return new MyViewHolder(itemView);
}
//给每一行View填充数据
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position){
if(getItemViewType(position)==TYPE_HEADER||getItemViewType(position)==TYPE_FOOTER){
return;
}
MyViewHolder myholder= (MyViewHolder) holder;
myholder.textview.setText(datas.get(getRealPosition(position)));
}
//如果有头部 position的位置是从1开始的 所以需要-1
public int getRealPosition(int position){
return header==null?position:position-1;
}
//数据源的数量
@Override
public int getItemCount() {
if(header == null && footer == null){//没有head跟foot
return datas.size();
}else if(header == null && footer != null){//head为空&&foot不为空
return datas.size() + 1;
}else if (header != null && footer == null){//head不为空&&foot为空
return datas.size() + 1;
}else {
return datas.size() + 2;//head不为空&&foot不为空
}
}
@Override
public int getItemViewType(int position){
//如果头布局不为空&&位置是第一个那就是head类型
if(header!=null&&position==0){
return TYPE_HEADER;
}else if(footer!=null&&position==getItemCount()-1){//如果footer不为空&&最后一个
return TYPE_FOOTER;
}
return super.getItemViewType(position);
}
public void setHeader(View header) {
this.header = header;
notifyItemInserted(0);//在位置0插入一条数据,然后刷新
}
public void setFooter(View footer) {
this.footer = footer;
notifyItemInserted(datas.size()-1);//在尾部插入一条数据,然后刷新
}
class MyViewHolder extends RecyclerView.ViewHolder{
private TextView textview;
public MyViewHolder(View itemView) {
super(itemView);
textview= (TextView) itemView.findViewById(R.id.textview);
}
}
}
getItemCount
有header跟footer的时候需要在源数据长度基础上进行增加。
getItemViewType
通过getItemViewType判断不同的类型
onCreateViewHolder
通过不同的类型创建item的View
onBindViewHolder
如果是header跟footer类型是不需要绑定数据的,header跟footer的View一般在actvity中创建,不需要这边做处理,所以这两种类型我们就不往下执行,如果有头布局,position==0的位置被header占用了,但是我们的数据源也就是集合的下标是从0开始的,所以这里需要-1。
setHeader
设置头布局,在第一行插入一条数据,然后刷新。注意这个方法调用后会有插入的动画,这个动画可以使用默认的,也可以自己定义
setFooter
设置尾部布局,在尾部插入一条数据,然后刷新。
添加header跟footer的方法终于封装好了,在activity中只需要两行代码就能添加header,跟ListView调用addHeader方法一样简单,又可以happy的玩耍了。这里需要注意的是我们初始化View的时候,inflate方法需要三个参数。
- resource 资源id
- root 父View
- attachToRoot true:返回父View false:返回资源id生成的View
//添加header
View header=LayoutInflater.from(this).inflate(R.layout.recycler_header,recyclerView,false);
adapter.setHeader(header);
//添加footer
View footer=LayoutInflater.from(this).inflate(R.layout.recycler_footer,recyclerView,false);
adapter.setFooter(footer);
recycler_header跟recycler_footer布局文件我就不贴出来了,就一个TextView,我们直接看效果图:
item点击事件&&增加或删除带动画效果
当我们调用RecyclerView的setOnItemClickListener方法的时候,发现居然没有,用了RecyclerView你要习惯什么东西都自己封装。。。
首先我们从adapter开刀,内部写一个接口,一个实例变量,提供一个公共方法,设置监听。
private RecyclerViewItemClick recyclerViewItemClick;
public void setRecyclerViewItemClick(RecyclerViewItemClick recyclerViewItemClick) {
this.recyclerViewItemClick = recyclerViewItemClick;
}
public interface RecyclerViewItemClick{
/**
* item点击
* @param realPosition 数据源position
* @param position view position
*/
void onItemClick(int realPosition,int position);
}
在onBindViewHolder方法中给item监听点击事件
if(recyclerViewItemClick!=null) {
myholder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
recyclerViewItemClick.onItemClick(getRealPosition(position),position);
}
});
}
在activity的onCreate方法中进行监听,顺便设置item增加删除动画。我用的是sdk自带的默认动画。
adapter.setRecyclerViewItemClick(recyclerViewItemClick);
recyclerView.setItemAnimator(new DefaultItemAnimator());
private RecyclerHeadFootViewAdapter.RecyclerViewItemClick recyclerViewItemClick=new RecyclerHeadFootViewAdapter.RecyclerViewItemClick() {
@Override
public void onItemClick(int realPosition, int position) {
Log.i("ansen","删除数据:"+realPosition+" view位置:"+position);
Log.i("ansen","当前位置:"+position+" 更新item数量:"+(adapter.getItemCount()-position-1));
datas.remove(realPosition);//删除数据源
adapter.notifyItemRemoved(position);//item移除动画
//更新position至adapter.getItemCount()-1的数据
adapter.notifyItemRangeChanged(position,adapter.getItemCount()-position-1);
}
};
源码下载
如果你想第一时间看我的后期文章,扫码关注公众号,每周不定期推送Android开发实战教程文章...
Android开发666 - 安卓开发技术分享
扫描二维码加关注
RecyclerView使用大全的更多相关文章
- Android控件大全(三)——RecyclerView
是时候用RecyclerView来替换ListView和GridView了 好处就不多说了,百度一搜一大把,来介绍下用法 先定义个适配器: public class BottomSheetAdapte ...
- GitHub上最著名的Android播放器开源项目大全
GitHub上最著名的Android播放器开源项目大全 ...
- 带你实现开发者头条APP(五)--RecyclerView下拉刷新上拉加载
title: 带你实现开发者头条APP(五)--RecyclerView下拉刷新上拉加载 tags: -RecyclerView,下拉刷新,上拉加载更多 grammar_cjkRuby: true - ...
- 安卓易学,爬坑不易——腾讯老司机的RecyclerView局部刷新爬坑之路
针对手游的性能优化,腾讯WeTest平台的Cube工具提供了基本所有相关指标的检测,为手游进行最高效和准确的测试服务,不断改善玩家的体验.目前功能还在免费开放中. 点击地址:http://wetest ...
- Oracle 数据库语句大全
Oracle数据库语句大全 ORACLE支持五种类型的完整性约束 NOT NULL (非空)--防止NULL值进入指定的列,在单列基础上定义,默认情况下,ORACLE允许在任何列中有NULL值. CH ...
- Android Studio开发RecyclerView遇到的各种问题以及解决(二)
开发RecyclerView时候需要导入别人的例子,我的是从github导入的,下载下github的压缩包之后解压看你要导入的文件是priject还是Module.(一般有app文件夹的大部分是pro ...
- Android Studio开发RecyclerView遇到的各种问题以及解决(一)
以前一直在用ListView,,,最近才看RecyclerView发现好强大.RecyclerView前提是Android版本在5.0以上,本人以前用的是eclipse只支持到4.4.索性就安装一个A ...
- Android的Kotlin秘方(II):RecyclerView 和 DiffUtil
作者:Antonio Leiva 时间:Sep 12, 2016 原文链接:http://antonioleiva.com/recyclerview-diffutil-kotlin/ 如你所知,在[支 ...
- 开源 iOS 项目分类索引大全 - 待整理
开源 iOS 项目分类索引大全 GitHub 上大概600个开源 iOS 项目的分类和介绍,对于你挑选和使用开源项目应该有帮助 系统基础库 Category/Util sstoolkit 一套Cate ...
随机推荐
- EasyMesh - A Two-Dimensional Quality Mesh Generator
EasyMesh - A Two-Dimensional Quality Mesh Generator eryar@163.com Abstract. EasyMesh is developed by ...
- 算法笔记_013:汉诺塔问题(Java递归法和非递归法)
目录 1 问题描述 2 解决方案 2.1 递归法 2.2 非递归法 1 问题描述 Simulate the movement of the Towers of Hanoi Puzzle; Bonus ...
- Android Ormlite 学习笔记2 -- 主外键关系
以上一篇为例子,进行主外键的查询 定义Users.java 和 Role.java Users -- Role 关系为:1对1 即父表关系 Role -- Users 关系为:1对多 即子表关系 下面 ...
- 深入研究Visual studio 2017 RC新特性
在[Xamarin+Prism开发详解三:Visual studio 2017 RC初体验]中分享了Visual studio 2017RC的大致情况,同时也发现大家对新的Visual Studio很 ...
- UWP开发之Mvvmlight实践六:MissingMetadataException解决办法(.Net Native下Default.rd.xml配置问题)
最近完成一款UWP应用,在手机端测试发布版(Release)的时候应用莫名奇妙的强行关闭,而同样的应用包在PC端一点问题都没有,而且Debug版在两个平台都没有问题,唯独手机的Release版有问题. ...
- 微服务与Docker介绍
什么是微服务 微服务应用的一个最大的优点是,它们往往比传统的应用程序更有效地利用计算资源.这是因为它们通过扩展组件来处理功能瓶颈问题.这样一来,开发人员只需要为额外的组件部署计算资源,而不需要部署一个 ...
- 【干货分享】流程DEMO-采购预算编制
流程名: 采购预算编制 业务描述: 在月初由计财部进行预算编辑,提交审批后预算生效 流程相关文件: 流程包.xml WebService业务服务.xml WebService.asmx WebSe ...
- NSStringCompareOptions
typedefNS_OPTIONS(NSUInteger, NSStringCompareOptions) { NSCaseInsensitiveSearch = 1, //不区分大小写比较 N ...
- HTML5 标签 details 展开 搜索
details有一个新增加的子标签--summary,当鼠标点击summary标签中的内容文字时,details标签中的其他所有元素将会展开或收缩. 默认状态为 收缩状态 设置为展开状态为 <d ...
- 【已解决】Https请求——基础连接已经关闭 发送时发生错误
本人在做商用项目的推送消息功能时,借助第三方推送服务.这里避免有打广告的嫌疑,就不报名字了.由于是通过调用API接口,所以Post方法是自己写的,但是在开发环境是可以正常推送的,但是一上线就出各种问题 ...