1. RecyclerView介绍

      在Android应用程序中列表是一个非常重要的控件,适用场合非常多,如新闻列表、应用列表、消息列表等等,但是从Android 一出生到现在并没有非常好用的列表控件,早期的 ListView 用法非常复杂,尤其是自定义列表,简直就是地狱,因为其中还涉及到很多效率优化的问题,新手很难写出高效率的基于列表应用,而且 ListView 只能垂直方向呈现内容,使用很不灵活,为了解决这个缺陷,Android 官方推出了 RecyclerView 控件,用来替代 ListView。

(1)RecyclerView的控件相对于ListView,他好在哪里呢?

  1)它封装了viewholder的回收复用。

      2)RecyclerView使用布局管理器管理子view的位置,也就是说你再不用拘泥于ListView的竖直线性展示方式。通过设置LayoutManager来快速实现listview、gridview、瀑布流的效果;而且还可以设置横向和纵向显示

  3)带了ItemAnimation,可以设置加载和移除时的动画,方便做出各种动态浏览的效果。

  4)分开的view :

我们平时用listview的时候,adapter一般这么写的:

 if (convertView == null) {
holder = new ViewHolder();
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
convertView = inflater.inflate(
R.layout.list_device_binding, parent, false); holder.deviceImage = (ImageView) convertView
.findViewById(R.id.bluetoothDeviceImage);
holder.deviceName = (TextView) convertView
.findViewById(R.id.bluetoothDeviceName);
holder.deviceType = (TextView) convertView
.findViewById(R.id.bluetoothDeviceType);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}

但是,到了这里,RecyclerView分隔开了,如下:

 @Override
public A onCreateViewHolder(ViewGroup parent, int viewType) {
final View view = LayoutInflater.from(mContext).
inflate(R.layout.listitem_track_history, parent, false);
return new ViewHolder(view);
} @Override
public void onBindViewHolder(A holder, int position) {
Data da=getData(position);
holder.tvDate.setText(da.getDate());
}

  5)相对简单的层次结构:

我们看下Listview他背后的继承关系:

 public class ListView extends AbsListView
public abstract class AbsListView extends AdapterView<ListAdapter>
public abstract class AdapterView<T extends Adapter> extends ViewGroup

三重继承,内容还挺多的,不是直接继承ViewGroup,而相反的RecycleView却是直接继承自ViewGroup的。

(2)RecyclerView的控件相对于ListView,他有什么缺陷呢?(目前只知道1个缺点)

  1)不能简单的添加点击事件onListItemClickListener 

我们在使用listview设置子item的点击事件的时候,只需要像下面这么写

 listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { User user= parent.getItemAtPosition(position);
}
});

但是,如果你使用这个RecycleView,会发现没有这个接口了。RecyclerView不再负责Item视图的布局及显示,所以RecyclerView也没有为Item开放OnItemClick等点击事件。

这就需要我们自己实现,见我的博客:Android 高级UI设计笔记20:RecyclerView 的详解之RecyclerView添加Item点击事件

(3)RecyclerView 核心内容:
  • Android RecyclerView 的用法
  • Android RecyclerView 横向布局
  • Android RecyclerView 垂直布局
  • Android RecyclerView 表格布局

这里我们使用的Android Studio,首先新建Android工程之后,右击app,打开  "Open Module Setting" ,然后找到"Dependencies"选项,添加RecyclerView依赖库,如下:

在gradle中添加依赖

dependencies {

compile fileTree(dir: 'libs', include: ['*.jar'])

testCompile 'junit:junit:4.12'

compile 'com.android.support:appcompat-v7:23.4.0'

compile 'com.android.support:recyclerview-v7:23.4.0'

}

当然也有很多朋友使用Eclipse开发工具(建议大家尽快使用AS,AS比Eclipse高效太多了),如果要使用RecyclerView也很简单,只要添加一个jar包到工程的libs文件下,然后构建路径就可以使用了,当然静态布局设计的时候还是注意要引用RecyclerView的全路径。

这个jar包为android-support-v7-recyclerview.jar  和 android-support-v4.jar,这个两个jar包往往会因为版本不一致产生冲突,从而会报错:

java.lang.RuntimeException: Unable to start activity ComponentInfo

这里是安全使用的v4 和 v7 库的下载地址为:http://download.csdn.net/detail/hebao5201314/9567555

那么这里我先讲解使用RecyclerView主要方法,如下:

   1)setLayoutManager(layout):控制显示方式。

RecyclerView提供了三种LayoutManager:LinearLayoutManager、GridLayoutManager、StaggeredGridLayoutManager

   2)setItemAnimator():控制item的增删动画。

   3)addItemDecoration(): 控制item间的间隔,这里还可以自定义间隔的样式。

——Adapter:使用RecyclerView时,我们需要一个集成RecyclerView.Adapter的适配器,作用是将数据与每个item的界面进行绑定。

——LayoutManager:用来确定每个item的布局,何时展示和隐藏。回收或重用的时候LayoutManager会向适配器请求新的数据来替换旧的数据,这种机制和ListView的原理类似,都避免了创建过多的View和频繁的调用findViewById方法。

目前SDK中提供了三种自带的LayoutManager:

 1)LinearLayoutManager

 2)GridLayoutManager

 3)StaggeredGridLayoutManager

2. 接下来我们就可以使用RecyclerView。

(1)首先我们来到MainActivity里面,如下:

 package com.example.hebao.learnrv;

 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.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView; public class MainActivity extends AppCompatActivity { private RecyclerView rv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
rv = new RecyclerView(this);
//先加载RecyclerView
setContentView(rv);
//然后动态设置RecyclerView
rv.setLayoutManager(new LinearLayoutManager(this));
rv.setAdapter(new RecyclerView.Adapter(){
class ViewHolder extends RecyclerView.ViewHolder {
private TextView tv; public ViewHolder(TextView itemView) {
super(itemView);
tv = itemView;
} public TextView getTv() {
return tv;
}
} /**
* 创建ViewHolder
* @param viewGroup
* @param i
* @return
*/
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
return new ViewHolder(new TextView(viewGroup.getContext()));
} /**
* 对上面自己创建的ViewHolder携带数据进行处理
* @param viewHolder
* @param i
*/
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i) {
ViewHolder vh = (ViewHolder) viewHolder;
vh.getTv().setText("Item "+i);
} /**
*
* 获取RecyclerView的子对象数量
*/
@Override
public int getItemCount() {
return 100;
}
} );
} }

布署程序到模拟器上,如下:(可以上下滑动滚动)

(2)利用数组承载数据源:

 package com.example.hebao.learnrv;

 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.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView; public class MainActivity extends AppCompatActivity { private RecyclerView rv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
rv = new RecyclerView(this); setContentView(rv); rv.setLayoutManager(new LinearLayoutManager(this));
rv.setAdapter(new RecyclerView.Adapter(){
private String[] data = new String[] {"hello", "二胎时代","九阴真经"};
class ViewHolder extends RecyclerView.ViewHolder {
private TextView tv; public ViewHolder(TextView itemView) {
super(itemView);
tv = itemView;
} public TextView getTv() {
return tv;
}
} /**
* 创建ViewHolder
* @param viewGroup
* @param i
* @return
*/
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
return new ViewHolder(new TextView(viewGroup.getContext()));
} /**
* 对上面自己创建的ViewHolder携带数据进行处理
* @param viewHolder
* @param i
*/
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i) {
ViewHolder vh = (ViewHolder) viewHolder;
vh.getTv().setText(data[i]);
} /**
*
* 获取RecyclerView的子对象数量
*/
@Override
public int getItemCount() {
return data.length;
}
});
} }

布署程序到模拟器上,如下:

3. 使用资源文件自定义列表项:
(1)首先来到MainActivity,如下:
 package com.example.hebao.learnrv;

 import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; public class MainActivity extends AppCompatActivity { private RecyclerView rv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
rv = new RecyclerView(this); setContentView(rv); rv.setLayoutManager(new LinearLayoutManager(this));
rv.setAdapter(new MyAdapter());
} }

(2)此时MyAdapter,如下:

 package com.example.hebao.learnrv;

 import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView; /**
* Created by hebao on 11/16/15.
*/
class MyAdapter extends RecyclerView.Adapter {
private ItemData[] data = new ItemData[] {new ItemData("东邪", "黄药师"), new ItemData("西狂","杨过")}; class ViewHolder extends RecyclerView.ViewHolder {
private View root;
private TextView tvTitle, tvContent; public ViewHolder(View root) {
super(root);
tvTitle = (TextView) root.findViewById(R.id.tvTitle);
tvContent = (TextView) root.findViewById(R.id.tvContent);
} public TextView getTvContent() {
return tvContent;
} public TextView getTvTitle() {
return tvTitle;
}
} /**
* 创建ViewHolder
*
* @param viewGroup
* @param i
* @return
*/
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
return new ViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_cell,
null));
} /**
* 对上面自己创建的ViewHolder携带数据进行处理
*
* @param viewHolder
* @param i
*/
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i) {
ViewHolder vh = (ViewHolder) viewHolder;
ItemData id = data[i];
vh.getTvTitle().setText(id.title);
vh.getTvContent().setText(id.content); } /**
* 获取RecyclerView的子对象数量
*/
@Override
public int getItemCount() {
return data.length;
} }

此处我们用到了一个实体数据类ItemData,如下:

 package com.example.hebao.learnrv;

 /**
* Created by hebao on 11/16/15.
*/
public class ItemData {
public String title = "title";
public String content ="content"; public ItemData(String title, String content) {
this.title = title;
this.content = content;
}
}

自定义布局文件资源为list_cell.xml:

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"> <TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="@+id/tvTitle"
android:layout_gravity="center_horizontal" /> <TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="New Text"
android:id="@+id/tvContent"
android:layout_gravity="center_horizontal" />
</LinearLayout>

(3)程序布署到模拟器上,如下:

 
相信大家看到上面的显示效果Item之间没有分割线,该怎么办呢?

这里我们需要用到RecyclerView.ItemDecoration给每一项Item视图添加子View,可以进行画分隔线之类的东西

那么具体如何使用呢

    我们可以创建一个类继承RecyclerView.ItemDecoration类来绘制分隔线,通过ItemDecoration可 以让我们每一个Item从视觉上面相互分开来,实现一个ItemDecoration,系统提供的ItemDecoration是一个抽象类,因为当我们RecyclerView在进行绘制的时候会进行绘制。

下面是转载别人实现的RecycleViewDivider,如下:

 package com.himi.recyclerviewdemo;

 import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ItemDecoration;
import android.view.View; public class RecycleViewDivider extends ItemDecoration {
private Paint mPaint;
private Drawable mDivider;
private int mDividerHeight = 2;//分割线高度,默认为1px
private int mOrientation;//列表的方向:LinearLayoutManager.VERTICAL或LinearLayoutManager.HORIZONTAL
private static final int[] ATTRS = new int[]{android.R.attr.listDivider}; /**
* 默认分割线:高度为2px,颜色为灰色
*
* @param context
* @param orientation 列表方向
*/
public RecycleViewDivider(Context context, int orientation) {
if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) {
throw new IllegalArgumentException("请输入正确的参数!");
}
mOrientation = orientation; final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
} /**
* 自定义分割线
*
* @param context
* @param orientation 列表方向
* @param drawableId 分割线图片
*/
public RecycleViewDivider(Context context, int orientation, int drawableId) {
this(context, orientation);
mDivider = ContextCompat.getDrawable(context, drawableId);
mDividerHeight = mDivider.getIntrinsicHeight();
} /**
* 自定义分割线
*
* @param context
* @param orientation 列表方向
* @param dividerHeight 分割线高度
* @param dividerColor 分割线颜色
*/
public RecycleViewDivider(Context context, int orientation, int dividerHeight, int dividerColor) {
this(context, orientation);
mDividerHeight = dividerHeight;
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(dividerColor);
mPaint.setStyle(Paint.Style.FILL);
} //获取分割线尺寸
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.set(0, 0, 0, mDividerHeight);
} //绘制分割线
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
if (mOrientation == LinearLayoutManager.VERTICAL) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
} //绘制横向 item 分割线
private void drawHorizontal(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 + mDividerHeight;
if (mDivider != null) {
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(canvas);
}
if (mPaint != null) {
canvas.drawRect(left, top, right, bottom, mPaint);
}
}
} //绘制纵向 item 分割线
private void drawVertical(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 + mDividerHeight;
if (mDivider != null) {
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(canvas);
}
if (mPaint != null) {
canvas.drawRect(left, top, right, bottom, mPaint);
}
}
}
}

使用方法:

添加默认分割线:高度为2px,颜色为灰色

  mRecyclerView.addItemDecoration(new RecycleViewDivider(mContext, LinearLayoutManager.VERTICAL));

添加自定义分割线:可自定义分割线drawable

  mRecyclerView.addItemDecoration(new RecycleViewDivider(mContext, LinearLayoutManager.VERTICAL, R.drawable.divider_mileage));

添加自定义分割线:可自定义分割线高度和颜色

  mRecyclerView.addItemDecoration(new RecycleViewDivider(mContext, LinearLayoutManager.VERTICAL, 10, getResources().getColor(R.color.divide_gray_color)));

使用很简单,这里我就不添加代码实现了。

4. RecyclerView的布局样式
(1)RecyclerView的横向布局:
修改2上面代码,如下:
list_cell.xml
 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="@+id/tvTitle"
android:layout_gravity="center_horizontal" /> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Text"
android:id="@+id/tvContent"
android:layout_gravity="center_horizontal" />
</LinearLayout>

同时来到MainActivity,如下:

 package com.example.hebao.learnrv;

 import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; public class MainActivity extends AppCompatActivity { private RecyclerView rv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
rv = new RecyclerView(this); setContentView(rv);
//设置RecyclerView为横向布局
rv.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false));
rv.setAdapter(new MyAdapter());
} }

布署程序到模拟器上,如下:

 
 
(2)RecyclerView的垂直布局
rv.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));
 
(3)RecyclerView的表格布局:
rv.setLayoutManager(new GridLayoutManager(this,3));

Android 高级UI设计笔记07:RecyclerView 的详解的更多相关文章

  1. Android 高级UI设计笔记01:使用ExpandableListView组件(ListView的扩展)

    1.ExpandableListView是一个用来显示二级节点的ListView. 比如如下效果的界面: 2.使用ExpandableListView步骤 (1)要给ExpandableListVie ...

  2. Android 高级UI设计笔记20:RecyclerView 的详解之RecyclerView添加Item点击事件

    1. 引言: RecyclerView侧重的是布局的灵活性,虽说可以替代ListView但是连基本的点击事件都没有,这篇文章就来详细讲解如何为RecyclerView的item添加点击事件,顺便复习一 ...

  3. Android 高级UI设计笔记06:仿微信图片选择器(转载)

    仿微信图片选择器: 一.项目整体分析: 1. Android加载图片的3个目标: (1)尽可能的去避免内存溢出. a. 根据图片的显示大小去压缩图片 b. 使用缓存对我们图片进行管理(LruCache ...

  4. Android 高级UI设计笔记21:Android SegmentView(分段选择控件)

    1. 分段控制(SegmentView) 首先我们先看看什么是SegmentView的效果,如下: 分段控制这个View控件是ios7的分段控制,和QQ消息页面顶部的效果一样,android没有这个控 ...

  5. Android 高级UI设计笔记19:PopupWindow使用详解

    1. PopupWindow使用 PopupWindow这个类用来实现一个弹出框,可以使用任意布局的View作为其内容,这个弹出框是悬浮在当前activity之上的. 2. PopupWindow使用 ...

  6. Android 高级UI设计笔记17:Android在非UI线程中显示Toast

    1. 子线程的Toast怎么显示不出来? 因为Toast在创建的时候会依赖于一个Handler,并且一个Handler是需要有一个Looper才能够创建,而普通的线程是不会自动去创建一个Looper对 ...

  7. Android 高级UI设计笔记14:Gallery(画廊控件)之 3D图片浏览

    1. 利用Gallery组件实现 3D图片浏览器的功能,如下: 2. 下面是详细的实现过程如下: (1)这里我是测试性代码,我的图片是自己添加到res/drawable/目录下的,如下: 但是开发中不 ...

  8. Android 高级UI设计笔记09:Android如何实现无限滚动列表

    ListView和GridView已经成为原生的Android应用实现中两个最流行的设计模式.目前,这些模式被大量的开发者使用,主要是因为他们是简单而直接的实现,同时他们提供了一个良好,整洁的用户体验 ...

  9. Android 高级UI设计笔记08:Android开发者常用的7款Android UI组件(转载)

    Android开发是目前最热门的移动开发技术之一,随着开发者的不断努力和Android社区的进步,Android开发技术已经日趋成熟,当然,在Android开源社区中也涌现了很多不错的开源UI项目,它 ...

随机推荐

  1. 我的web前端修炼之路从此开始

    看过一篇文章,上面说过要想学习一门新技术,从什么时候开始都是不晚的.但对于一名大四的学生,只会一点简单的网页架构,只懂得HTML,CSS,JavaScript简单的一点皮毛,却怎么也说不过去.但也是这 ...

  2. JAVA与多线程开发(线程基础、继承Thread类来定义自己的线程、实现Runnable接口来解决单继承局限性、控制多线程程并发)

    实现线程并发有两种方式:1)继承Thread类:2)实现Runnable接口. 线程基础 1)程序.进程.线程:并行.并发. 2)线程生命周期:创建状态(new一个线程对象).就绪状态(调用该对象的s ...

  3. RT-thread内核之进程间通信

    这里面见到的同步和互斥的概念非常清晰,转载自: http://www.cnblogs.com/King-Gentleman/p/4311582.html 一.进程间通信机制 rt-thread操作系统 ...

  4. Mysql视图的作用及其性能分析

    定义:视图是从一个或几个基本表导出的表,它与基本表不同,是一个虚表. 作用: 1.简化操作,不用进行多表查询. 2.当不同种类的用用户共享同一个数据库时,非常灵活,(用户以不同的 方式看待同一数据. ...

  5. 第三百零一天 how can i 坚持

    其实真搞不大懂自己.不喜欢巴结人,也不喜欢阿谀奉承,但老是感觉自己却又在那么做,是对自己要求太高了,想太多?? 郭娜好像把我拉黑了,拉黑就拉黑吧.或许真不合适. 睡觉.

  6. PHP操作cookie函数:setcookie()与setrawcookie()

    PHP setcookie() 函数向客户端发送一个 HTTP cookie.cookie 是由服务器发送到浏览器的变量.cookie 通常是服务器嵌入到用户计算机中的小文本文件.每当计算机通过浏览器 ...

  7. Struts2通配符映射

    1.一个Web 应用可能有成百上千个 action 声明. 可以利用 struts 提供的通配符映射机制把多个彼此相似的映射关系简化为一个映射关系 2.通配符映射规则 –若找到多个匹配, 没有通配符的 ...

  8. CodeForces 176B Word Cut (计数DP)

    Word Cut Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit St ...

  9. POJ 3169 Layout (spfa+差分约束)

    题目链接:http://poj.org/problem?id=3169 差分约束的解释:http://www.cnblogs.com/void/archive/2011/08/26/2153928.h ...

  10. UVa 1252 Twenty Questions (状压DP+记忆化搜索)

    题意:有n件物品,每件物品有m个特征,可以对特征进行询问,询问的结果是得知某个物体是否含有该特征,要把所有的物品区分出来(n个物品的特征都互不相同), 最小需要多少次询问? 析:我们假设心中想的那个物 ...