RecyclerView详细介绍&使用。

<主菜>RecyclerView

简介

RecyclerViewAndroid 5.0提供的新控件,已经用了很长时间了,但是一直没有时间去仔细的梳理一下。现在有时间了,决定来整理下。

官方文档中是这样介绍的:

A flexible view for providing a limited window into a large data set.

RecyclerView比listview更先进更灵活,对于很多的视图它就是一个容器,可以有效的重用和滚动。当数据动态变化的时候请使用它。

专业术语:
  • Adapter: A subclass of RecyclerView.Adapter responsible for providing views that represent items in a data set.
  • Position: The position of a data item within an Adapter.
  • Index: The index of an attached child view as used in a call to getChildAt(int). Contrast with Position.
  • Binding: The process of preparing a child view to display data corresponding to a position within the adapter.
  • Recycle (view): A view previously used to display data for a specific adapter position may be placed in a cache for later reuse to display the same type of data again later. This can drastically improve performance by skipping initial layout inflation or construction.
  • Scrap (view): A child view that has entered into a temporarily detached state during layout. Scrap views may be reused without becoming fully detached from the parent RecyclerView, either unmodified if no rebinding is required or modified by the adapter if the view was considered dirty.
  • Dirty (view): A child view that must be rebound by the adapter before being displayed.
RecyclerView中的位置:

RecyclerViewRecyclerView.AdapterRecyclerView.LayoutManager中引进了一个抽象的额外中间层来保证在布局计算的过程中能批量的监听到数据变化。这样介绍了LayoutManager追踪adapter数据变化来计算动画的时间。因为所有的View绑定都是在同一时间执行,所以这样也提高了性能和避免了一些非必要的绑定。

因为这个原因,在RecylcerView中有两种position类型相关的方法:

- layout position: 在最近一次layout计算是item的位置。这是LayoutManager角度中的位置。

- adapter position: itemadapter中的位置。这是从Adapter的角度中的位置。

这两种position除了在分发adapter.notify*事件与之后计算布局更新的这段时间之内外都是相同的。

可以通过getLayoutPosition(),findViewHolderForLayoutPosition(int)方法来获取最近一次布局计算的LayoutPosition。这些positions包括从最近一次布局计算的所有改变。你可以根据这些位置来方便的得到用户当前从屏幕上所看到的。例如,如果在屏幕上有一个列表,用户请求的是第五个条目,你可以通过该方法来匹配当前用户正在看的内容。

另一种AdapterPosition相关的方法是getAdapterPosition(),findViewHolderForAdapterPosition(int),当及时一些数据可能没有来得及被展现到布局上时便需要获取最新的adapter位置可以使用这些相关的方法。例如,如果你想获取一个条目的ViewHOlderclick事件时,你应该使用getAdapterPosition()。需要知道这些方法在notifyDataSetChange()方法被调用和新布局还没有被计算之前是不能使用的。鉴于这个原因,你应该小心的去处理这些方法有可能返回NO_POSITION或者null的情况。

结构

  • RecyclerView.Adapter: 创建View并将数据集合绑定到View上
  • ViewHolder: 持有所有的用于绑定数据或者需要操作的View
  • LayoutManager: 布局管理器,负责摆放视图等相关操作
  • ItemDecoration: 负责绘制Item附近的分割线,通过RecyclerView.addItemDecoration()使用
  • ItemAnimator: 为Item的操作添加动画效果,如,增删条目等,通过RecyclerView.setItemAnimator(new DefaultItemAnimator());使用

下图能更直观的了解:

RecyclerView提供这些内置布局管理器:
  • LinearLayoutManager: 以垂直或水平滚动列表方式显示项目。
  • GridLayoutManager: 在网格中显示项目。
  • StaggeredGridLayoutManager: 在分散对齐网格中显示项目。
RecyclerView.ItemDecoration是一个抽象类,可以通过重写以下三个方法,来实现Item之间的偏移量或者装饰效果:
  • public void onDraw(Canvas c, RecyclerView parent) 装饰的绘制在Item条目绘制之前调用,所以这有可能被Item的内容所遮挡
  • public void onDrawOver(Canvas c, RecyclerView parent) 装饰的绘制在Item条目绘制之后调用,因此装饰将浮于Item之上
  • public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) 与padding或margin类似,LayoutManager在测量阶段会调用该方法,计算出每一个Item的正确尺寸并设置偏移量。
ItemAnimator触发于以下三种事件:
  • 某条数据被插入到数据集合中
  • 从数据集合中移除某条数据
  • 更改数据集合中的某条数据

在之前的版本中,当时据集合发生改变时通过调用notifyDataSetChanged(),来刷新列表,因为这样做会触发列表的重绘,所以并不会出现任何动画效果,因此需要调用一些以notifyItem*()作为前缀的特殊方法,比如:

  • public final void notifyItemInserted(int position) 向指定位置插入Item
  • public final void notifyItemRemoved(int position) 移除指定位置Item
  • public final void notifyItemChanged(int position) 更新指定位置Item

使用介绍:

  • 添加依赖库

    dependencies {

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

    }

  • 示例代码
    public class MainActivity extends AppCompatActivity {
        private RecyclerView mRecyclerView;
        private LinearLayoutManager mLayoutManager;
        private RecyclerView.Adapter mAdapter;
    
        private String [] mDatas = {"Android","ios","jack","tony","window","mac","1234","hehe","495948", "89757", "66666"};
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            findView();
            initView();
        }
    
        private void findView() {
            mRecyclerView = (RecyclerView) findViewById(R.id.rv);
        }
    
        private void initView() {
            // use this setting to improve performance if you know that changes
            // in content do not change the layout size of the RecyclerView
            mRecyclerView.setHasFixedSize(true);
    
            // use a linear layout manager
            mLayoutManager = new LinearLayoutManager(this);
            mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
            mRecyclerView.setLayoutManager(mLayoutManager);
            mAdapter = new MyAdapter(mDatas);
            mRecyclerView.setAdapter(mAdapter);
        }
    
        private class MyAdapter extends RecyclerView.Adapter<MyHolder> {
            private String[] mData;
    
            public MyAdapter(String[] data) {
                mData = data;
            }
    
            @Override
            public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                // create a new view
                View v = LayoutInflater.from(parent.getContext()).inflate(
                        R.layout.item, parent, false);
                MyHolder holder = new MyHolder(v);
                return holder;
            }
    
            @Override
            public void onBindViewHolder(MyHolder holder, int position) {
                holder.mTitleTv.setText(mData[position]);
            }
    
            @Override
            public int getItemCount() {
                return mData == null ? 0 : mData.length;
            }
        }
    
        static class MyHolder extends RecyclerView.ViewHolder {
            public TextView mTitleTv;
    
            public MyHolder(View itemView) {
                super(itemView);
                mTitleTv = (TextView) itemView;
            }
        }
    }

    activity_main的内容如下:

    <android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/rv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    item的内容如下:

    <?xml version="1.0" encoding="utf-8"?>
    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="20dp"
        android:gravity="center_horizontal"
        android:textSize="30dp">
    
    </TextView>

点击事件

之前在使用ListView的时候,设置点击事件是非常方便的。

mListView.setOnItemClickListener();
mListView.setOnItemLongClickListener();

但是RecylcerView确没有提供类似的方法。那我们只能是自己去处理。处理的方式也有两种:

  • 通过itemView.onClickListener()以及onLongClickListener()

    public class MainActivity extends AppCompatActivity {
        private RecyclerView mRecyclerView;
        private LinearLayoutManager mLayoutManager;
        private MyAdapter mAdapter;
    
        private String[] mDatas = {"Android", "ios", "jack", "tony", "window", "mac", "1234", "hehe", "495948", "89757", "66666"};
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            findView();
            initView();
        }
    
        private void findView() {
            mRecyclerView = (RecyclerView) findViewById(R.id.rv);
        }
    
        private void initView() {
            // use this setting to improve performance if you know that changes
            // in content do not change the layout size of the RecyclerView
            mRecyclerView.setHasFixedSize(true);
    
            // use a linear layout manager
            mLayoutManager = new LinearLayoutManager(this);
            mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
            mRecyclerView.setLayoutManager(mLayoutManager);
            mAdapter = new MyAdapter(mDatas);
            mAdapter.setOnItemClickListener(new OnItemClickListener() {
                @Override
                public void onItemClick(View view, int position) {
                    Toast.makeText(MainActivity.this, "click " + mDatas[position], Toast.LENGTH_SHORT).show();
                }
            });
            mAdapter.setOnItemLongClickListener(new OnItemLongClickListener() {
                @Override
                public void onItemLongClick(View view, int position) {
                    Toast.makeText(MainActivity.this, "long click " + mDatas[position], Toast.LENGTH_SHORT).show();
                }
            });
            mRecyclerView.setAdapter(mAdapter);
        }
    
        class MyAdapter extends RecyclerView.Adapter<MyHolder> {
            private String[] mData;
    
            public MyAdapter(String[] data) {
                mData = data;
            }
    
            @Override
            public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                // create a new view
                View v = LayoutInflater.from(parent.getContext()).inflate(
                        R.layout.item, parent, false);
                MyHolder holder = new MyHolder(v);
                return holder;
            }
    
            @Override
            public void onBindViewHolder(final MyHolder holder, final int position) {
                holder.mTitleTv.setText(mData[position]);
                if (mOnItemClickListener != null) {
                    holder.itemView.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            mOnItemClickListener.onItemClick(holder.itemView, position);
                        }
                    });
                }
                if (mOnItemLongClickListener != null) {
                    holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
                        @Override
                        public boolean onLongClick(View v) {
                            mOnItemLongClickListener.onItemLongClick(holder.itemView, position);
                            return true;
                        }
                    });
                }
            }
    
            @Override
            public int getItemCount() {
                return mData == null ? 0 : mData.length;
            }
    
            private OnItemClickListener mOnItemClickListener;
            private OnItemLongClickListener mOnItemLongClickListener;
    
            public void setOnItemClickListener(OnItemClickListener mOnItemClickListener) {
                this.mOnItemClickListener = mOnItemClickListener;
            }
    
            public void setOnItemLongClickListener(OnItemLongClickListener mOnItemLongClickListener) {
                this.mOnItemLongClickListener = mOnItemLongClickListener;
            }
    
        }
    
        static class MyHolder extends RecyclerView.ViewHolder {
            public TextView mTitleTv;
    
            public MyHolder(View itemView) {
                super(itemView);
                mTitleTv = (TextView) itemView;
            }
        }
    
        public interface OnItemClickListener {
            void onItemClick(View view, int position);
        }
    
        public interface OnItemLongClickListener {
            void onItemLongClick(View view, int position);
        }
    
    }
  • 使用RecyclerView.OnItemTouchListener

    虽然没有提供现成的监听器,但是提供了一个内部接口OnItemTouchListener

    先来看看它的介绍:

    /**
     * An OnItemTouchListener allows the application to intercept touch events in progress at the
     * view hierarchy level of the RecyclerView before those touch events are considered for
     * RecyclerView‘s own scrolling behavior.
     *
     * <p>This can be useful for applications that wish to implement various forms of gestural
     * manipulation of item views within the RecyclerView. OnItemTouchListeners may intercept
     * a touch interaction already in progress even if the RecyclerView is already handling that
     * gesture stream itself for the purposes of scrolling.</p>
     *
     * @see SimpleOnItemTouchListener
     */
    public static interface OnItemTouchListener {
        ...
    }

    说的很明白了,而且还让你看SimpleOnItemTouchListener,猜也能猜出来是一个默认的实现类。

    好了直接上代码:

    public class MainActivity extends AppCompatActivity {
    private RecyclerView mRecyclerView;
    private LinearLayoutManager mLayoutManager;
    private MyAdapter mAdapter;
    
    private String[] mDatas = {"Android", "ios", "jack", "tony", "window", "mac", "1234", "hehe", "495948", "89757", "66666"};
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findView();
        initView();
    }
    
    private void findView() {
        mRecyclerView = (RecyclerView) findViewById(R.id.rv);
    }
    
    private void initView() {
        // use this setting to improve performance if you know that changes
        // in content do not change the layout size of the RecyclerView
        mRecyclerView.setHasFixedSize(true);
    
        // use a linear layout manager
        mLayoutManager = new LinearLayoutManager(this);
        mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        mRecyclerView.setLayoutManager(mLayoutManager);
        mAdapter = new MyAdapter(mDatas);
        mRecyclerView.setAdapter(mAdapter);
        mRecyclerView.addOnItemTouchListener(new RecyclerViewClickListener(this, mRecyclerView, new OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                Toast.makeText(MainActivity.this, mDatas[position], Toast.LENGTH_SHORT).show();
            }
    
            @Override
            public void onItemLongClick(View view, int position) {
                Toast.makeText(MainActivity.this, "Long Click " + mDatas[position], Toast.LENGTH_SHORT).show();
            }
        }));
    }
    
    class RecyclerViewClickListener extends RecyclerView.SimpleOnItemTouchListener {
        private GestureDetector mGestureDetector;
        private OnItemClickListener mListener;
    
        public RecyclerViewClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) {
            mListener = listener;
            mGestureDetector = new GestureDetector(context,
                    new GestureDetector.SimpleOnGestureListener() {
                        @Override
                        public boolean onSingleTapUp(MotionEvent e) {
                            View childView = recyclerView.findChildViewUnder(e.getX(), e.getY());
                            if (childView != null && mListener != null) {
                                mListener.onItemClick(childView, recyclerView.getChildLayoutPosition(childView));
                                return true;
                            }
                            return false;
                        }
    
                        @Override
                        public void onLongPress(MotionEvent e) {
                            View childView = recyclerView.findChildViewUnder(e.getX(), e.getY());
                            if (childView != null && mListener != null) {
                                mListener.onItemLongClick(childView, recyclerView.getChildLayoutPosition(childView));
                            }
                        }
                    });
        }
    
        @Override
        public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
            if (mGestureDetector.onTouchEvent(e)) {
                return true;
            } else
                return super.onInterceptTouchEvent(rv, e);
        }
    
        @Override
        public void onTouchEvent(RecyclerView rv, MotionEvent e) {
            super.onTouchEvent(rv, e);
        }
    
        @Override
        public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
            super.onRequestDisallowInterceptTouchEvent(disallowIntercept);
        }
    }
    
    interface OnItemClickListener {
        void onItemClick(View view, int position);
    
        void onItemLongClick(View view, int position);
    }

    上面的实现稍微有些缺陷,就是如果我手指按住某个条目一直不抬起,他也会执行Long click事件,这显然是不合理的,至于怎么解决,就是可以不用GestureDetector,自己在DOWNUP事件中去判断处理。

Headerview FooterView

之前在ListView中提供了addHeaderView()addFooterView()等方法,但是在RecyclerView中并没有提供类似的方法,那我们该如何添加呢? 也很简单,就是通过Adapter中去添加,利用不同的itemViewType,然后根据不同的类型去在onCreateViewHOlder中创建不同的视图,通过这种方式来达到headerviewFooterView的效果。

上一段简单的示例代码:

    public class HeaderAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private static final int TYPE_HEADER = 0;
    private static final int TYPE_ITEM = 1;
    String[] data;

    public HeaderAdapter(String[] data) {
        this.data = data;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == TYPE_ITEM) {
            //inflate your layout and pass it to view holder
            return new VHItem(null);
        } else if (viewType == TYPE_HEADER) {
            //inflate your layout and pass it to view holder
            return new VHHeader(null);
        }

        throw new RuntimeException("there is no type that matches the type " + viewType + " + make sure your using types correctly");
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof VHItem) {
            String dataItem = getItem(position);
            //cast holder to VHItem and set data
        } else if (holder instanceof VHHeader) {
            //cast holder to VHHeader and set data for header.
        }
    }

    @Override
    public int getItemCount() {
        return data.length + 1;
    }

    @Override
    public int getItemViewType(int position) {
        if (isPositionHeader(position))
            return TYPE_HEADER;

        return TYPE_ITEM;
    }

    private boolean isPositionHeader(int position) {
        return position == 0;
    }

    private String getItem(int position) {
        return data[position - 1];
    }

    class VHItem extends RecyclerView.ViewHolder {
        TextView title;

        public VHItem(View itemView) {
            super(itemView);
        }
    }

    class VHHeader extends RecyclerView.ViewHolder {
        Button button;

        public VHHeader(View itemView) {
            super(itemView);
        }
    }
}

上面的代码对LinearLayoutManger是没问题的,但是使用GridLayoutManager呢? 如果是两列,那添加的HeaderView并不是占据上第一行,而是HeaderView与第二个ItemView一起占据第一行。那该怎么处理呢?

那就是使用setSpanSizeLookup()方法。

比如:

recyclerView.setLayoutManager(new GridLayoutManager(this, 2));

在上面的基本设置中,我们的spanCount为2,每个itemspan size为1,因此一个header需要的span size则为2。在我尝试着添加header之前,我想先看看如何设置span size。其实很简单。

final GridLayoutManager manager = new GridLayoutManager(this, 2);
recyclerView.setLayoutManager(manager);
manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
  @Override
  public int getSpanSize(int position) {
    return adapter.isHeader(position) ? manager.getSpanCount() : 1;
  }
});

下拉刷新、自动加载

实现下拉刷新

实现下拉刷新也很简单了,可以使用SwipeRefrshLayout,SwipeRefrshLayoutGoogle官方提供的组件,可以实现下拉刷新的功能。已包含到support.v4包中。

主要方法有:

  • setOnRefreshListener(OnRefreshListener):添加下拉刷新监听器
  • setRefreshing(boolean):显示或者隐藏刷新进度条
  • isRefreshing():检查是否处于刷新状态
  • setColorSchemeResources():设置进度条的颜色主题,最多设置四种。
<android.support.v4.widget.SwipeRefreshLayout
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
    android:scrollbars="vertical"
    >
   <android.support.v7.widget.RecyclerView
       android:layout_width="fill_parent"
       android:layout_height="fill_parent"
       ></android.support.v7.widget.RecyclerView>
</android.support.v4.widget.SwipeRefreshLayout>

具体实现就不写了。

实现滑动自动加载更多功能

实现方式和ListView的实现方式类似,就是通过监听scroll时间,然后判断当前显示的item

//RecyclerView滑动监听
mRecylcerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
       super.onScrollStateChanged(recyclerView, newState);
        if (newState ==RecyclerView.SCROLL_STATE_IDLE && lastVisibleItem + 1 ==adapter.getItemCount()) {
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    List<String> newDatas = new ArrayList<String>();
                    for (int i = 0; i< 5; i++) {
                        int index = i +1;
                       newDatas.add("more item" + index);
                    }
                   adapter.addMoreItem(newDatas);
                }
            },1000);
        }
    }
    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView,dx, dy);
        lastVisibleItem =linearLayoutManager.findLastVisibleItemPosition();
    }
});

然后再通过结合FooterView以及增加几种状态就可以实现自动加载更多了。


时间: 07-14

RecyclerView详细介绍&使用。的相关文章

微铺子点单系统详细介绍 - 争做国内最专业的微信商店平台,微信外卖订餐系统!

什么是微铺子? 微铺子是国内专业的微信点单系统,集成了外卖.点餐.订座等众多功能.通过微铺子,店家可以在微信上建立店铺,消费者只需关注店家的帐号,即可浏览商品与店家的信息,消费者关注到商家后,根据提示,进行点击点单,简单三步,15秒内,即可完成订餐.店家可以通过电脑后台.电子邮件.短信或无线打印机多种方式即时查看订单,并提供相应的服务. 微铺子系统适用于:餐饮.酒店.水果店.蛋糕店.花店.零售.超市等. 微铺子从创立到与合作商家的长期测试,再到正式投入商用,期间不断根据客户的需求完善产品,不断开

自动化运维工具ansible详细介绍

在学习批量管理软件时,首先要明确的知道自己需要什么,网上大神很多,他们都研究到源码上了,写了很多介绍绚丽功能的文档,但其实那些功能基本上我们都用不到,经常被各种文档弄得头脑发晕,此文就是为了简单直白的告诉大家ansible的功能,满足大家的基本需求. 首先确认批量管理我们需要什么:无外乎主机分组管理.实时批量执行命令或脚本.实时批量分发文件或目录.定时同步文件等. 目录 1.      ansible与saltstack对比... 2.      ansible安装... 3.      ans

详细介绍spring框架(下篇)

上篇简单介绍了spring,下面详细介绍为什么需要spring框架? Spring带给我们什么 方便解耦,简化开发,通过Spring提供的IoC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合.有了Spring,用户不必再为单实例模式类.属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用. AOP编程的支持 通过Spring提供的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付. 声明式事务的支持 在

TTL,COMS,USB,232,422,485电平之详细介绍及使用

如有错误敬请指导! 今天来详细介绍一下TTL,COMS,USB,232,422,485电平,以及之间的转换问题. 有些地方的引脚图可能不是规范的,具体引脚以自己的模块资料为主,这篇文章着重介绍使用... 先介绍各个电平 TTL电平------我们使用的51单片机,5V供电的那种,+5V等价于逻辑“1”,0V等价于逻辑“0”,“TTL电平”最常用于有关电专业,如:电路.数字电路.微机原理与接口技术.单片机等课程中都有所涉及.在数字电路中只有两种电平(高和低)高电平+5V.低电平0V. COMS电平

RAID详细介绍

RAID详细介绍 RAID 0 又称为Stripe或Striping,它代表了所有RAID级别中最高的存储性能.RAID 0提高存储性能的原理是把连续的数据分散到多个磁盘上存取,这样,系统有数据请求就可以被多个磁盘并行的执行,每个磁盘执行属于它自己的那部分数据请求.这种数据上的并行操作可以充分利用总线的带宽,显著提高磁盘整体存取性能 RAID 1又称为Mirror或Mirroring,它的宗旨是最大限度的保证用户数据的可用性和可修复性.RAID 1的操作方式是把用户写入硬盘的数据百分之百地自动复

Inf2Cat应用的参数使用详细介绍

http://msdn.microsoft.com/zh-cn/subscriptions/ff547089 ? Inf2Cat Inf2Cat (Inf2Cat.exe) 是一个命令行工具,该工具确定驱动程序包的?INF 文件是否可以针对指定的 Windows 版本列表进行数字签名.如果可以,那么 Inf2Cat 会生成适用于指定 Windows 版本的未签名的目录文件. Inf2Cat /driver: PackagePath /os: WindowsVersionList [/nocat]

DICOM:DICOM Print 服务详细介绍

背景: 昨天专栏中发表了一篇关于DICOM Print的博文DICOM:DICOM Print服务中PresentationContext协商之 MetaSOPClass与SOPClass对比分析,文章从部署中遇到的实际情况出发,对DICOM Print中的连接协商(Association Negotiation)进行了剖析,本文可看做是上一篇博文的补充,重新浏览和整理了DICOM3.0标准中对DICOM Print 服务的介绍,加深对DICOM打印的理解. DICOM Print服务数据流:

Linux shell脚本基础学习详细介绍(完整版)一

Linux shell脚本基础学习这里我们先来第一讲,介绍shell的语法基础,开头.注释.变量和 环境变量,向大家做一个基础的介绍,虽然不涉及具体东西,但是打好基础是以后学习轻松地前提.1. Linux 脚本编写基础◆1.1 语法基本介绍 1.1.1 开头 程序必须以下面的行开始(必须方在文件的第一行): #!/bin/sh 符号#!用来告诉系统它后面的参数是用来执行该文件的程序.在这个例子中我们使用/bin/sh来执行程序. 当编辑好脚本时,如果要执行该脚本,还必须使其可执行. 要使脚本可执

Linux shell脚本基础学习详细介绍(完整版)二

详细介绍Linux shell脚本基础学习(五) Linux shell脚本基础前面我们在介绍Linux shell脚本的控制流程时,还有一部分内容没讲就是有关here document的内容这里继续. Linux shell脚本基础已经被分成好几个部分了,这里对控制流程的内容也就马上讲完了,这是最后一部分关于here document,这里举例稍微有点复杂,我们慢慢来分析这个复杂Linux shell脚本. 6. Here documents 当要将几行文字传递给一个命令时,here docu