说到RecyclerView,相信大家都不陌生,它是我们经典级ListView的升级版,升级后的RecyclerView展现了极大的灵活性。同时内部直接封装了ViewHolder,不用我们自己定义ViewHolder就能实现item的回收和复用功能。当然它肯定不止这些好处,比如我们可以自定义分割线,可以更加方便的实现列表的布局方式等等。虽说我们自己在第一次使用时,会比使用listView和gridView稍微的复杂一些,需要自定义的也多了一点,但是它却更好的体现了灵活性,可以随自己的喜好来随便的定义,当然最主要的是能更好的复用,只需一次的定义,却可随处的复用。

下面,我们来好好的学习下它的使用。

首先,我们要是用RecyclerView必须引入support-V7包,拿android studio来举例:

先打开File->选择Project Structure,之后在左边Modules选择你的项目,然后在点击右边的Dependencies,然后点击绿色的+号选择添加Library,然后找到recyclerview-v7双击加入到依赖库中。然后可以在build.gradle中查看:

dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.3.0'
compile 'com.android.support:recyclerview-v7:23.3.0'
}

可以找dependencies 中找到对recyclerview的支持,则说明添加成功,如果还没有的,可以clean下自己的工程。

接下来,我们就进入Recyclerview的学习。RecyclerView的学习目标就是以下四个方法,把以下四个方法完全的掌握了,也就真正的掌握了RecyclerView。

RecyclerView.setAdapter:用来设置adapter,显示数据

RecyclerView.setLayoutManager :用来设置显示布局的,目前系统给出三种布局,分别是垂直,水平和瀑布流式布局

RecyclerView.setItemAnimator :用来设置显示动画的

RecyclerView.addItemDecoration :用来设置列表分割线的

接下来我们就学习怎么使用以上四个方法来真正掌握Recyclerview的使用。要使用Recyclerview,我们必须先定义一个类(CustomRecyclerAdapter)并继承Recyclerview.Adapter,且实现它里面的方法,代码如下:

public class CustomRecyclerAdapter extends RecyclerView.Adapter<CustomRecyclerAdapter.ViewHolderHelper>{

    @Override
public ViewHolderHelper onCreateViewHolder(ViewGroup parent, int viewType) {
return null;
}
@Override
public void onBindViewHolder(ViewHolderHelper holder, int position) { }
@Override
public int getItemCount() {
return 0;
} public class ViewHolderHelper extends RecyclerView.ViewHolder{ public ViewHolderHelper(View itemView) {
super(itemView);
}
}
}

在我们还没正式开始使用之前,先大体上了解下上面三个方法是做什么的:

A. onCreateViewHolder()方法:该方法就是将布局文件转化为View并传递给RecyclerView封装好的ViewHolder。

B. onBindViewHolder()方法:该方法将会在固定的位置上把ViewHolder里的itemView数据映射在item中。

C. getItemCount()方法:该方法和listView中的getCount()一样,都是返回Item的个数。

了解了这三个方法,我们来先实现最简单的应用,把我们的数据显示在app中。

首先,我们创建一个布局文件recycler_view.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"> <android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView> </LinearLayout>

创建RecycerActivity用来加载布局文件:

public class RecycerActivity extends Activity {
private RecyclerView mRecyclerView;
private List<String> mData;
private CustomRecyclerAdapter mCustomRecyclerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recycer_view);
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
initData();
//线性布局管理器
recyclerViewLayoutManager = new LinearLayoutManager(this);
//设置布局管理器
mRecyclerView.setLayoutManager(recyclerViewLayoutManager);
//设置显示动画
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
//设置adapter
mCustomRecyclerAdapter = new CustomRecyclerAdapter(mData);
mRecyclerView.setAdapter(mCustomRecyclerAdapter); }
private void initData() {
mData = new ArrayList<String>();
for(int i = 0; i < 10; i++){
mData.add("第"+i+"item");
}
}
}

经过修改的CustomRecyclerAdapter 如下,

public class CustomRecyclerAdapter extends RecyclerView.Adapter<CustomRecyclerAdapter.ViewHolderHelper>{

    private List<String> mData;
public CustomRecyclerAdapter(List<String> data) {
mData = data;
} @Override
public ViewHolderHelper onCreateViewHolder(ViewGroup parent, int viewType) {
//onCreateViewHolder方法就是将布局文件转化为View并传递给RecyclerView封装好的ViewHolder
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_view, parent, false);
return new ViewHolderHelper(view);
} @Override
public void onBindViewHolder(ViewHolderHelper holder, int position) {
holder.textView.setText(mData.get(position));
} @Override
public int getItemCount() {
return mData.size();
}
}

item_view.xml布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_item"
android:layout_toRightOf="@+id/iv_item"
android:layout_width="match_parent"
android:layout_height="30dp"
android:text="I am item view"/> </RelativeLayout>

好,基础工作已做足,我们先来看看效果吧

已经显示出来了,不过,大家看着是不是很别扭呢,连个分割线也没有,还不如listView呢,别急,我们在上面也提到过,RecyclerView给了我们最大的发挥自由度,它本身并没有给定列表的分割线,这是需要我们自己定义的。由此我们来定义自己的分割线。自定义分割线是需要我们继承RecyclerView.ItemDecoration类,并实现它的onDraw()方法。请看代码:

public class DividerItemDecoration extends RecyclerView.ItemDecoration{

    public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
private int mOrientation;
private Context mContext;
private TextPaint mTextPaint;
private float listDividerSize = 2;
private int listDividerColor;
public DividerItemDecoration(Context context,int orientation){
mContext = context;
mTextPaint = new TextPaint();
mTextPaint.setColor(Color.RED);
setOrientation(orientation);
}
public void setOrientation(int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
}
@Override
public void onDraw(Canvas c, RecyclerView parent) {
super.onDraw(c, parent);
if(mOrientation == HORIZONTAL_LIST){
drawHorizontal(c, parent);
}else{
drawVertical(c, parent);
}
}
/**
* 绘制垂直分割线
* @param c
* @param parent
*/
private void drawVertical(Canvas c, RecyclerView parent) {
//分割线的左边界 = 子View的左padding值
int rectLeft = parent.getPaddingLeft();
//分割线的右边界 = 子View的宽度 - 子View的右padding值
int rectRight = parent.getWidth() - parent.getPaddingRight();
int childCount = parent.getChildCount();
for(int i = 0; i < childCount; i ++){
View child = parent.getChildAt(i);
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
// 分割线的top = 子View的底部 + 子View的margin值
int rectTop = child.getBottom() + layoutParams.bottomMargin;
// 分割线的bottom = 分割线的top + 分割线的高度
float rectBottom = rectTop + listDividerSize;
c.drawRect(rectLeft,rectTop,rectRight,rectBottom,mTextPaint);
}
} /**
* 绘制水平分割线
* @param c
* @param parent
*/
private void drawHorizontal(Canvas c, RecyclerView parent) {
//分割线的上边界 = 子View的上padding值
int rectTop = parent.getPaddingTop();
//分割线的下边界 = 子View的高度 - 子View的底部padding值
int rectBottom = parent.getHeight() - parent.getPaddingBottom();
int childCount = parent.getChildCount();
for(int i = 0; i < childCount; i ++){
View child = parent.getChildAt(i);
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
//分割线的Left = 子View的右边界 + 子View的左margin值
int rectLeft = child.getRight() + layoutParams.rightMargin;
//分割线的right = 分割线的Left + 分割线的宽度
float rectRight = rectLeft + listDividerSize;
c.drawRect(rectLeft,rectTop,rectRight,rectBottom,mTextPaint);
}
} @Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if(mOrientation == VERTICAL_LIST){
outRect.set(0,0,0,(int)listDividerSize);
} else{
outRect.set(0,0,(int)listDividerSize,0);
}
}
}

代码很好理解,这里考虑了两个情况,分别是垂直和水平的布局,然后再ondraw()里面计算出四角边值,最后直接绘制一个矩形即可。

在RecycerActivity 中的onCreate中添加上一句

mRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL_LIST));

现在再来看看效果。

现在已显示出来了,分割线也出来了,在这里只列出了垂直方向的布局,就不再列出其他样式的布局代码了,伙伴们可自行写写看。

或许有经验的小伙伴们已经知道我们的RecyclerView自己是没有实现点击事件的,这里需要我们来根据业务的需求自己来实现。这里我们利用事件回调机制来完成事件的触发。

首先我们需要在CustomRecyclerAdapter中定义一个接口,并在其中定义两个可用的事件方法,如下:

public interface OnItemClickListener{
void onItemClickListener();
void onLongItemClickListener();
}

这里提供了用于点击和长按的事件方法,接下来我们需要对外暴露该接口用于被调用

 public void setOnClickItemListener(OnItemClickListener onItemClickListener){
mOnItemClickListener = onItemClickListener;
}

然后我们可以在ViewHolderHelper 做如下的修改:

public class ViewHolderHelper extends RecyclerView.ViewHolder{

        private TextView textView;
public ViewHolderHelper(View itemView) {
super(itemView);
textView = (TextView)itemView.findViewById(R.id.tv_item);
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mOnItemClickListener.onItemClickListener();
}
});
textView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
mOnItemClickListener.onLongItemClickListener();
return false;
}
});
}
}

首先得到我们itemView中的textView对应的Id,然后为textView添加事件,但是只是添加却并不实现,它的用意是谁调用谁实现。

最后在我们的RecycerActivity中添加如下代码,请看:

mCustomRecyclerAdapter.setOnClickItemListener(new CustomRecyclerAdapter.OnItemClickListener() {
@Override
public void onItemClickListener() {
Toast.makeText(getContext(),"单击",Toast.LENGTH_SHORT).show();
} @Override
public void onLongItemClickListener() {
Toast.makeText(getContext(),"长单击",Toast.LENGTH_SHORT).show();
}
});

下面在来看看是否可以实现事件的触发了呢?

ok,学到这里大家至少对RecylerView有了一个初步的认识,但是我们一想,这样写的话肯定达不到我们标题所说的无限复用,甚至连复用也遥不可及,是的,这样写是不可能完成复用的,接下来我们一步一步的慢慢调整,让它可以支持一次编写N次复用,达到极大多数的重复使用,即使不符合需求,我们也只需要修改丁点即可满足需求,这是我们的目标,接下来一步一步的实现。

首先,我们先整理下,看看可以调整哪些目标能逐步的实现重复使用的目标:

1. 数据类型:我们在使用List集合时,是无法固定类型的,有可能是String,int等等类型,所以我们不应该固定为哪一种类型。

2. 在onCreateViewHolder方法中,它需要映射一个布局文件并转化为View或是一个自定义View传递给RecyclerView封装好的ViewHolder,为了可以达到复用,所以我们就不可以在此直接映射布局文件。

3. 在onBindViewHolder方法中也不应该直接为itemView设置属性,如上面的:holder.textView.setText(mData.get(position));

4. 我们不应该在ViewHolder的构造方法中直接获取我们的itemView,并给它添加触发事件

以上几个是我们能很直观的得到的能重构的问题所在,至于其他的不容易想到的我们再重构的时候慢慢讲解。现在我们逐一的解决上面的问题,使我们能更达到重复使用的目的。

1,针对数据类型的不一致,我们可以根据具体的使用场景利用泛型进行传递到Adapter中,比如:我们再定义CustomRecyclerAdapter时使用泛型,让调用者传递过来它所拥有的类型,这样我们就可以不用考虑类型的不一致了。请看下面片段代码

public class CustomRecyclerAdapter<T> extends RecyclerView.Adapter<CustomViewHolderHelper>{
private Context mContext;
private List<T> mData;
private CustomOnItemClickListener mOnItemClickListener;
public CustomRecyclerAdapter(Context context, List<T> data) {
mContext = context;
mData = data;
}
}
...

RecycerActivity中在调用时可以这样使用:

mCustomRecyclerAdapter = new CustomRecyclerAdapter(this,mData);

这样就可以把类型给确定下来了,同时也解决了问题1的复用。

2 , 在onCreateViewHolder方法中,和问题一的解决方案是一样的,我们把需要的itemView给传递过去而不是固定写死在方法中

public class CustomRecyclerAdapter<T> extends RecyclerView.Adapter<CustomViewHolderHelper>{
private Context mContext;
private List<T> mData;
protected int mLayoutResId;
private CustomOnItemClickListener mOnItemClickListener;
public CustomRecyclerAdapter(Context context, int layoutResId, List<T> data) {
mContext = context;
mLayoutResId = layoutResId;
mData = data;
} /**
* Called when RecyclerView needs a new ViewHolder of the given type to represent
* an item.
* 当 RecyclerView 依据给出的类型需要一个新的 ViewHolder 去展示一个 item 时,该方法将会被调用
*
* 这个给出的类型是在 getItemViewType返回的,默认返回 0 。
*
* @param parent
* @param viewType
* @return
*/
@Override
public CustomViewHolderHelper onCreateViewHolder(ViewGroup parent, int viewType) {
//onCreateViewHolder方法就是将布局文件转化为View并传递给RecyclerView封装好的ViewHolder
View view = LayoutInflater.from(parent.getContext()).inflate(mLayoutResId, parent, false);
return new CustomViewHolderHelper(view);
}
}

RecycerActivity中在调用时可以这样使用:

mCustomRecyclerAdapter = new CustomRecyclerAdapter(this,R.layout.item_view,mData);

3 , 在onBindViewHolder方法中也不应该直接为itemView设置属性,我们可以在这里记录itemView的position,并给它设置监听事件,更重要的我们这这里可以创建一个抽象方法,让调用者自己去实现业务逻辑。请看代码:

public abstract class CustomRecyclerAdapter<T> extends RecyclerView.Adapter<CustomViewHolderHelper>
implements View.OnClickListener,View.OnLongClickListener{
private Context mContext;
private List<T> mData;
protected int mLayoutResId;
private CustomOnItemClickListener mOnItemClickListener;
public CustomRecyclerAdapter(Context context, int layoutResId, List<T> data) {
mContext = context;
mLayoutResId = layoutResId;
mData = data;
} /**
* Called when RecyclerView needs a new ViewHolder of the given type to represent
* an item.
* 当 RecyclerView 依据给出的类型需要一个新的 ViewHolder 去展示一个 item 时,该方法将会被调用
*
* 这个给出的类型是在 getItemViewType返回的,默认返回 0 。
*
* @param parent
* @param viewType
* @return
*/
@Override
public CustomViewHolderHelper onCreateViewHolder(ViewGroup parent, int viewType) {
//onCreateViewHolder方法就是将布局文件转化为View并传递给RecyclerView封装好的ViewHolder
View view = LayoutInflater.from(parent.getContext()).inflate(mLayoutResId, parent, false);
return new CustomViewHolderHelper(view);
} /**
* Called by RecyclerView to display the data at the specified position. This method should
* update the contents of the ViewHolder#itemView to reflect the item at the given position.
*
* RecyclerView 将要在特殊的位置上显示数据时,该方法将被调用。该方法将会在固定的位置上
* 把ViewHolder里的itemView数据映射在item中。
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(CustomViewHolderHelper holder, int position) {
//把每一个itemView设置一个标签,方便以后根据标签获取到该itemView以便做其他事项,比如点击事件
holder.itemView.setTag(position);
holder.itemView.setOnClickListener(this);
holder.itemView.setOnLongClickListener(this);
T itemData = mData.get(position);
displayContents(holder,itemData);
} /**
*用来在holder中设置每个ItemView的显示数据
* 设定为抽象方法,是为:自己本身并不实现,谁使用谁设置
* @param holder
* @param itemData
*/
protected abstract void displayContents(CustomViewHolderHelper holder, T itemData);
}

上面注解也写的很清楚,相信大家一看就明白,至于为什么可以直接使用holder.itemView来获取每个itemView是因为在onCreateViewHolder()方法中,我们返回了一个新的对象引用,这个对象的构造方法中使用super(itemView);把我们的itemView传递到了ViewHolder中,请看它的源码构造方法:

 public ViewHolder(View itemView) {
if (itemView == null) {
throw new IllegalArgumentException("itemView may not be null");
}
this.itemView = itemView;
}

因此我们可以在onBindViewHolder()方法中,直接使用holder.itemView来获取itemView。那么接下来,在RecycerActivity中,我们这样使用:

 mCustomRecyclerAdapter = new CustomRecyclerAdapter<String>(this, R.layout.item_view, mData) {
@Override
protected void displayContents(CustomViewHolderHelper holder, String itemData) {
holder.setText(R.id.tv_item,itemData);
}
};

当然你必须也得在ViewHolder中定义相应的方法,如:

public class CustomViewHolderHelper extends RecyclerView.ViewHolder{

    private SparseArray<View> views;
public CustomViewHolderHelper(View itemView) {
super(itemView);
views = new SparseArray<View>();
}
private <T extends View> T converToViewFromId(int resId) {
View view = views.get(resId);
if(view == null){
view = itemView.findViewById(resId);
}
views.put(resId,view);
return (T)view;
} public CustomViewHolderHelper setText(int resId, String value){
TextView itemView = converToViewFromId(resId);
if (TextUtils.isEmpty(value)) {
itemView.setText("");
} else {
itemView.setText(value);
}
return this;
}
}

ok,这样我们连第四个问题也一并解决了,看下效果吧,完全的一样,这样我们就实现的重复使用,但是有人会有疑问,这里也就只能使用TextView啊,其实已经在ViewHolder中给出了答案,大家只需要在添加相对应的方法即可,比如

public CustomViewHolderHelper setImageResource(int viewId, int imageResId) {
ImageView view = converToViewFromId(viewId);
view.setImageResource(imageResId);
return this;
}
public CustomViewHolderHelper setOnClickListener(int viewId, View.OnClickListener listener) {
View view = converToViewFromId(viewId);
view.setOnClickListener(listener);
return this;
}

上面我又添加了两个方法,用于点击事件和加载图片的ImageView,下面我们再把itemView布局文件修改下:

item_view.xml布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"> <ImageView
android:id="@+id/iv_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tv_item"
android:layout_toRightOf="@+id/iv_item"
android:layout_width="match_parent"
android:layout_height="30dp"
android:text="I am item view"/>
<Button
android:id="@+id/btn_item"
android:layout_toRightOf="@+id/iv_item"
android:layout_below="@+id/tv_item"
android:layout_width="wrap_content"
android:text="点我"
android:layout_height="wrap_content" />
</RelativeLayout>

RecycerActivity中在调用时可以这样使用:

mCustomRecyclerAdapter = new CustomRecyclerAdapter<String>(this, R.layout.item_view, mData) {
@Override
protected void displayContents(CustomViewHolderHelper holder, String itemData) {
holder.setText(R.id.tv_item,itemData)
.setImageResource(R.id.iv_item,R.mipmap.ic_launcher)
.setOnClickListener(R.id.btn_item, new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(RecycerActivity.this,"您单击了按钮",Toast.LENGTH_SHORT).show();
}
});
}
};

ok,来看下效果吧

是不是可以了呢,这样我们就可以完全的一次定义N次复用了,每次使用只需要更换不同的布局文件即可而不需要再次编写代码,学会了吧。

其实我们这节课主要讲解的RecyclerView.setAdapter的内容,其他的三个我们并没有详细的介入,我们会再以后的博文中陆续的讲解。

好了,今天就讲到这里吧,祝大家学习愉快。

更多资讯请关注微信平台,有博客更新会及时通知。爱学习爱技术。

Android 5.X新特性之RecyclerView基本解析及无限复用的更多相关文章

  1. android 5.0新特性学习--RecyclerView

    在过去很多年,我们的PC或者手机设备都是采用拟物化的设计风格,IOS采用扁平化的特性,android在2014年IO大会上说采用Material Design的设计风格,显示效果不能过于生硬的转换,而 ...

  2. Android 5.X新特性之为RecyclerView添加下拉刷新和上拉加载及SwipeRefreshLayout实现原理

    RecyclerView已经写过两篇文章了,分别是Android 5.X新特性之RecyclerView基本解析及无限复用 和 Android 5.X新特性之为RecyclerView添加Header ...

  3. Android 5.X新特性之为RecyclerView添加HeaderView和FooterView

    上一节我们讲到了 Android 5.X新特性之RecyclerView基本解析及无限复用 相信大家也应该熟悉了RecyclerView的基本使用,这一节我们来学习下,为RecyclerView添加H ...

  4. 《Android群英传》读书笔记 (5) 第十一章 搭建云端服务器 + 第十二章 Android 5.X新特性详解 + 第十三章 Android实例提高

    第十一章 搭建云端服务器 该章主要介绍了移动后端服务的概念以及Bmob的使用,比较简单,所以略过不总结. 第十三章 Android实例提高 该章主要介绍了拼图游戏和2048的小项目实例,主要是代码,所 ...

  5. Android 6.0 新特性 整理 资料来自网络

    Android 6.0新特性 Runtime Permissions Doze and App Standby Apache HTTP Client Removal BoringSSL Access ...

  6. 腾讯云安全:开发者必看|Android 8.0 新特性及开发指南

    欢迎大家关注腾讯云技术社区-博客园官方主页,我们将持续在博客园为大家推荐技术精品文章哦~ 背景介绍 谷歌2017 I/O开发者大会今年将于5月17-19日在美国加州举办.大会将跟往年一样发布最新的 A ...

  7. Android 8.0 新特性

    Android 8.0 (Android Oreo(奥利奥))新特性介绍 通知渠道 - Notification Channels 通知渠道是由应用自行定义的通知内容类别,借助渠道,开发者可以让用户对 ...

  8. 开发者必看|Android 8.0 新特性及开发指南

    背景介绍 谷歌2017 I/O开发者大会今年将于5月17-19日在美国加州举办.大会将跟往年一样发布最新的 Android 系统,今年为 Android 8.0.谷歌在今年3 月21日发布 Andro ...

  9. android 7.0 新特性 和对开发者的影响

    android 7.0新特性 - jiabailong的专栏 - 博客频道 - CSDN.NEThttp://blog.csdn.net/jiabailong/article/details/5241 ...

随机推荐

  1. LeetCode All in One 题目讲解汇总(持续更新中...)

    终于将LeetCode的免费题刷完了,真是漫长的第一遍啊,估计很多题都忘的差不多了,这次开个题目汇总贴,并附上每道题目的解题连接,方便之后查阅吧~ 477 Total Hamming Distance ...

  2. linux用户权限相关内容查看

    linux用户权限相关内容查看 1   用户信息 创建用户一个名为 webuser 的账号,并填写相应的信息: root@iZ94fabhqhuZ:~# adduser webuser Adding ...

  3. JavaScript多线程之HTML5 Web Worker

    在博主的前些文章Promise的前世今生和妙用技巧和JavaScript单线程和浏览器事件循环简述中都曾提到了HTML5 Web Worker这一个概念.在JavaScript单线程和浏览器事件循环简 ...

  4. CSharpGL(20)用unProject和Project实现鼠标拖拽图元

    CSharpGL(20)用unProject和Project实现鼠标拖拽图元 效果图 例如,你可以把Big Dipper这个模型拽成下面这个样子. 配合旋转,还可以继续拖拽成这样. 当然,能拖拽的不只 ...

  5. java的继承练习

     看程序写结果:    A:一个类的静态代码块,构造代码块,构造方法的执行流程    静态代码块 > 构造代码块 > 构造方法   B:静态的内容是随着类的加载而加载    静态代码块的内 ...

  6. .NET 基础一步步一幕幕[out、ref、params]

    out.ref.params out: 如果你在一个方法中,返回多个相同类型的值的时候,可以考虑返回一个数组. 但是,如果返回多个不同类型的值的时候,返回数组就不行了,那么这个时候, 我们可以考虑使用 ...

  7. Win10 字体模糊解决(DPI缩放禁用),设置默认输入法英文

    电脑坏了 , 换了新电脑, 但是新电脑,死活不能装win7, 装都不能装!!!郁闷了 好多地方字体模糊了,百般设置都不好看, 后来远程桌面到win2008server, 发现,在远程桌面里面居然很清晰 ...

  8. node.js学习总结(一)

    1.1.1 安装 Node.js 有三种方式安装 Node.js:一是通过安装包安装,二是通过源码编译安装,三是在 Linux 下可以通过 yum|apt-get 安装,在 Mac 下可以通过 Hom ...

  9. 06.移动先行之谁主沉浮----我的代码我来写(Xaml的优势)

    如果移动方向有任何问题请参考===> 异常处理汇总-移动系列(点) 前面几节课,我们都是在前台创建对象,进行一些设置,那么我们为什么不用传统的方法来编程呢? 我们今天来试试你就明了了~~ 打开M ...

  10. ITTC数据挖掘平台介绍(七)强化的数据库, 虚拟化,脚本编辑器

    一. 前言 好久没有更新博客了,最近一直在忙着找工作,目前差不多尘埃落定.特别期待而且准备的都很少能成功,反而是没怎么在意的最终反而能拿到,真是神一样的人生. 言归正传,一直以来,数据挖掘系统的数据类 ...