title: 带你实现开发者头条APP(五)--RecyclerView下拉刷新上拉加载

tags: -RecyclerView,下拉刷新,上拉加载更多

grammar_cjkRuby: true

一 、前言

最近实在太忙,一个多礼拜没有更新文章了,于是今晚加班加点把demo写出来,现在都12点了才开始写文章。

1.我们的目标

把RecyclerView下拉刷新上拉加载更多加入到我们的开发者头条APP中。

2.效果图

3.实现步骤

  • 找一个带上拉刷新下载加载更多的RecyclerView开源库,我们要站在巨人的肩膀上
  • 下载下来自己先运行下demo,然后看看是不是我们需要的功能,觉得不错就把module依赖进来,整合主项目。
  • 整合进来了之后,我们肯定需要进行修改,例如我这边就有滑动冲突,有多个headView等问题。

二 、具体实现

1.寻找RecyclerView上拉刷新下载加载开源库

我们找开源项目肯定首选github,去搜索一下一大堆,如果效果图是你想要的功能的话,然后找排名靠前,收藏比较多的项目吧,我找的项目是CommonPullToRefresh,支持ListView,RecyclerView,GridView,SwipeRefreshLayout等常用控件。我跑了一下Demo,没啥bug,挺好用的。

2.加入项目中

1).module导入进来,然后主项目依赖一下,这里有不会的看我另外一篇文章Android Studio 入门,里面有讲到Android Studio添加项目依赖。

2).代码实现,我们这边就是修改SelectedFragment

首先我们看布局文件的变化,在RecyclerView外面包裹了自定义的一个类PtrClassicFrameLayout,内部实现了下拉刷新,上拉加载更多。还可以设置自定义属性,都是啥意思我就不解释了,有兴趣的点击github上那个链接,讲解的很详细。

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical">
  6. <com.chanven.lib.cptr.PtrClassicFrameLayout xmlns:cube_ptr="http://schemas.android.com/apk/res-auto"
  7. android:id="@+id/test_recycler_view_frame"
  8. android:layout_width="match_parent"
  9. android:layout_height="match_parent"
  10. android:background="#f0f0f0"
  11. cube_ptr:ptr_duration_to_close="200"
  12. cube_ptr:ptr_duration_to_close_header="700"
  13. cube_ptr:ptr_keep_header_when_refresh="true"
  14. cube_ptr:ptr_pull_to_fresh="false"
  15. cube_ptr:ptr_ratio_of_header_height_to_refresh="1.2"
  16. cube_ptr:ptr_resistance="1.8">
  17. <android.support.v7.widget.RecyclerView
  18. android:id="@+id/test_recycler_view"
  19. android:layout_width="match_parent"
  20. android:layout_height="match_parent"
  21. android:background="@android:color/white"/>
  22. </com.chanven.lib.cptr.PtrClassicFrameLayout>
  23. </LinearLayout>

再来看onCreateView方法,这个代码就不解释了。

  1. @Override
  2. public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState){
  3. View rootView = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_selected, null);
  4. ptrClassicFrameLayout = (PtrClassicFrameLayout) rootView.findViewById(R.id.test_recycler_view_frame);
  5. mRecyclerView = (RecyclerView) rootView.findViewById(R.id.test_recycler_view);
  6. mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
  7. init();
  8. return rootView;
  9. }

在onCreateView里面调用了init()方法,我们来瞧瞧怎么实现的。这里解释一下为什么要对适配器进行包装,这样的目的在包装类里面处加入头部,底部View,处理点击事件。大家拿到源码了之后自己也可以看看。

  1. private void init() {
  2. //初始化适配器
  3. selectedAdapter = new SelectedRecyclerAdapter(getActivity());
  4. //对适配器进行封装
  5. mAdapter = new RecyclerAdapterWithHF(selectedAdapter);
  6. //把滚动Banner加入头部
  7. mAdapter.addCarouse(initCarouselHead());
  8. mRecyclerView.setAdapter(mAdapter);
  9. ptrClassicFrameLayout.setPtrHandler(ptrDefaultHandler);//设置下拉监听
  10. ptrClassicFrameLayout.setOnLoadMoreListener(onLoadMoreListener);//设置上拉监听
  11. ptrClassicFrameLayout.setLoadMoreEnable(true);//设置可以加载更多
  12. }

mAdapter.addCarouse(initCarouselHead()); 初始化一个滚动Banner,然后加入适配器头部。这个我前面的教程应该已经讲过了。。

  1. //初始化
  2. private View initCarouselHead(){
  3. View headView = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_selected_header,mRecyclerView,false);
  4. tvContent=(TextView) headView.findViewById(R.id.tv_content);
  5. tvContent.setText(carousePageStr[0]);
  6. viewPager = (ViewPager)headView.findViewById(R.id.viewpager);
  7. selectedPagerAdapter=new SelectedPagerAdapter(getActivity(),carousePagerSelectView);
  8. viewPager.setOffscreenPageLimit(2);
  9. viewPager.setCurrentItem(0);
  10. viewPager.addOnPageChangeListener(onPageChangeListener);
  11. viewPager.setAdapter(selectedPagerAdapter);
  12. ViewGroup group = (ViewGroup) headView.findViewById(R.id.viewGroup);// 初始化底部显示控件
  13. tips = new ImageView[3];
  14. for (int i = 0; i < tips.length; i++){
  15. ImageView imageView = new ImageView(getActivity());
  16. if (i == 0) {
  17. imageView.setBackgroundResource(R.mipmap.page_indicator_focused);
  18. } else {
  19. imageView.setBackgroundResource(R.mipmap.page_indicator_unfocused);
  20. }
  21. tips[i] = imageView;
  22. LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT));
  23. layoutParams.leftMargin = 10;// 设置点点点view的左边距
  24. layoutParams.rightMargin = 10;// 设置点点点view的右边距
  25. group.addView(imageView, layoutParams);
  26. }
  27. timer = new Timer(true);//初始化计时器
  28. timer.schedule(task, 0, CAROUSEL_TIME);//延时0ms后执行,3000ms执行一次
  29. return headView;
  30. }

SelectedRecyclerAdapter 必须继承RecyclerView.Adapter

这玩意跟ListView的适配器差不多,用过ListView适配器的应该一看就懂了。

首先会调用getItemCount,知道我要显示多少item。

知道了行数然后就是循环调用onCreateViewHolder跟onBindViewHolder了,onCreateViewHolder就是创建一个item的View,onBindViewHolder就会把上次创建的item的View传入进来,还有一个下标,这样我们就能给每一行赋值,这两个方法都是先后一起调用。item回收重用的机制应该跟ListView一样的。

  1. public class SelectedRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
  2. private List<SelectedArticle> selectedArticles;
  3. private LayoutInflater inflater;
  4. public SelectedRecyclerAdapter(Context context) {
  5. super();
  6. inflater = LayoutInflater.from(context);
  7. selectedArticles = new ArrayList<SelectedArticle>();
  8. initData();
  9. }
  10. private void initData() {
  11. for (int i = 0; i < 10; i++) {
  12. SelectedArticle selectedArticle = new SelectedArticle(i, "Android开发666", i, i, "");
  13. selectedArticles.add(selectedArticle);
  14. }
  15. }
  16. public void loadMore(int page) {
  17. for (int i = 0; i < 5; i++) {
  18. SelectedArticle selectedArticle = new SelectedArticle(i, "第" + page + "页数据", i, i, "");
  19. selectedArticles.add(selectedArticle);
  20. }
  21. }
  22. public void getFirst() {
  23. selectedArticles.clear();
  24. initData();
  25. }
  26. @Override
  27. public int getItemCount() {
  28. return selectedArticles.size();
  29. }
  30. @Override
  31. public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
  32. SelectedRecyclerHolder holder = (SelectedRecyclerHolder) viewHolder;
  33. SelectedArticle selectedArticle = selectedArticles.get(position);
  34. holder.title.setText(selectedArticle.getTitle());
  35. holder.like.setText("" + selectedArticle.getLikeNumber());
  36. holder.comment.setText("" + selectedArticle.getCommentNumber());
  37. }
  38. @Override
  39. public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewHolder, int position) {
  40. View view = inflater.inflate(R.layout.fragment_selected_item, null);
  41. return new SelectedRecyclerHolder(view);
  42. }
  43. public class SelectedRecyclerHolder extends RecyclerView.ViewHolder {
  44. private TextView title;//标题
  45. private TextView like;//喜欢数量
  46. private TextView comment;评论数量
  47. public SelectedRecyclerHolder(View view) {
  48. super(view);
  49. title = (TextView) view.findViewById(R.id.tv_title);
  50. like = (TextView) view.findViewById(R.id.tv_like);
  51. comment = (TextView) view.findViewById(R.id.tv_comment);
  52. }
  53. }
  54. }

3.解决整合进来的bug

  • 滑动冲突

    当我们上拉到顶部把标题栏挤出屏幕外的时候,进行下拉会触发RecyclerView的下拉事件,正确的情况应该是显示Toolbar.

    1).RecyclerView下拉刷新的时候先判断Toolbar有没有显示。如果Toolbar没有显示就不处理。

    2).AppBarLayout有一个addOnOffsetChangedListener方法,在AppBarLayout的布局偏移量发生改变时被调用。

在MainFragment里面进行监听

  1. appBarLayout= (AppBarLayout) rootView.findViewById(R.id.appBarLayout);
  2. appBarLayout.addOnOffsetChangedListener(onOffsetChangedListener);

然后在回调函数中,把值给SelectedFragment,

  1. private AppBarLayout.OnOffsetChangedListener onOffsetChangedListener=new AppBarLayout.OnOffsetChangedListener() {
  2. @Override
  3. public void onOffsetChanged(AppBarLayout appBarLayout, int i){
  4. //i>=0 Toolbar全部显示
  5. selectedFragment.setPullRefresh(i>=0);
  6. System.out.println("i值:"+i);
  7. }
  8. };

3).在SelectedFragment中,继续把值传给PtrFrameLayout

  1. public void setPullRefresh(boolean pullRefresh) {
  2. ptrClassicFrameLayout.setPullRefresh(pullRefresh);
  3. }

4.在PtrFrameLayout里面用一个实例变量接收这个值

  1. private boolean pullRefresh=true;
  2. public void setPullRefresh(boolean pullRefresh) {
  3. this.pullRefresh = pullRefresh;
  4. }

4).找到PtrFrameLayout类的dispatchTouchEvent事件,这个方法是处理屏幕的触摸事件的。

  1. @Override
  2. public boolean dispatchTouchEvent(MotionEvent e) {
  3. if (!isEnabled() || mContent == null || mHeaderView == null) {
  4. System.out.println("都是空的...");
  5. return dispatchTouchEventSupper(e);
  6. }
  7. int action = e.getAction();
  8. switch (action) {
  9. case MotionEvent.ACTION_UP:
  10. System.out.println("弹起...");
  11. case MotionEvent.ACTION_CANCEL:
  12. System.out.println("取消...");
  13. // if(pullRefresh){
  14. mPtrIndicator.onRelease();
  15. if (mPtrIndicator.hasLeftStartPosition()) {
  16. if (DEBUG) {
  17. PtrCLog.d(LOG_TAG, "call onRelease when user release");
  18. }
  19. System.out.println("call onRelease when user release");
  20. onRelease(false);
  21. if (mPtrIndicator.hasMovedAfterPressedDown()) {
  22. sendCancelEvent();
  23. return true;
  24. }
  25. }
  26. return dispatchTouchEventSupper(e);
  27. // }
  28. case MotionEvent.ACTION_DOWN:
  29. System.out.println("按下...");
  30. mHasSendCancelEvent = false;
  31. mPtrIndicator.onPressDown(e.getX(), e.getY());
  32. mScrollChecker.abortIfWorking();
  33. mPreventForHorizontal = false;
  34. // The cancel event will be sent once the position is moved.
  35. // So let the event pass to children.
  36. // fix #93, #102
  37. return dispatchTouchEventSupper(e);
  38. case MotionEvent.ACTION_MOVE:
  39. System.out.println("移动...");
  40. if(pullRefresh){//Toolbar显示
  41. mLastMoveEvent = e;
  42. mPtrIndicator.onMove(e.getX(), e.getY());
  43. float offsetX = mPtrIndicator.getOffsetX();
  44. float offsetY = mPtrIndicator.getOffsetY();
  45. if (mDisableWhenHorizontalMove && !mPreventForHorizontal && (Math.abs(offsetX) > mPagingTouchSlop && Math.abs(offsetX) > Math.abs(offsetY))) {
  46. if (mPtrIndicator.isInStartPosition()) {
  47. mPreventForHorizontal = true;
  48. }
  49. }
  50. if (mPreventForHorizontal) {
  51. return dispatchTouchEventSupper(e);
  52. }
  53. boolean moveDown = offsetY > 0;
  54. boolean moveUp = !moveDown;
  55. boolean canMoveUp = mPtrIndicator.hasLeftStartPosition();
  56. if (DEBUG) {
  57. boolean canMoveDown = mPtrHandler != null && mPtrHandler.checkCanDoRefresh(this, mContent, mHeaderView);
  58. PtrCLog.v(LOG_TAG, "ACTION_MOVE: offsetY:%s, currentPos: %s, moveUp: %s, canMoveUp: %s, moveDown: %s: canMoveDown: %s", offsetY, mPtrIndicator.getCurrentPosY(), moveUp, canMoveUp, moveDown, canMoveDown);
  59. }
  60. // disable move when header not reach top
  61. if (moveDown && mPtrHandler != null && !mPtrHandler.checkCanDoRefresh(this, mContent, mHeaderView)) {
  62. return dispatchTouchEventSupper(e);
  63. }
  64. if ((moveUp && canMoveUp) || moveDown) {
  65. // System.out.println("是否下拉刷新:"+pullRefresh+"偏移量是多少:"+offsetY);
  66. movePos(offsetY);
  67. return true;
  68. }
  69. }
  70. }
  71. return dispatchTouchEventSupper(e);
  72. }

我就改了一行代码,在action==MotionEvent.ACTION_MOVE的时候,先判断我们传入的pullRefresh是否为true。。。

  • 顶部加入轮播

    RecyclerView头部底部加入View,前面我们介绍过了,都是适配器的封装类RecyclerAdapterWithHF来控制。从效果图中,我们可以看出,轮播的View是加入头部的,找到RecyclerAdapterWithHF类,看看源码依葫芦画瓢就可以了。

1).得有一个保存View的集合,其实用一个变量也行,因为我们只有一个轮播View.

  1. private List<View> mCarouse = new ArrayList<View>();//保存轮播View
  2. //可以添加轮播View
  3. public void addCarouse(View view){
  4. mCarouse.add(view);
  5. }

2).定义一个常量,用于类型判断

  1. public static final int TYPE_CAROUSE = 7900;

3).在getItemViewType里面加入轮播的类型

  1. @Override
  2. public final int getItemViewType(int position) {
  3. // check what type our position is, based on the assumption that the
  4. // order is headers > items > footers
  5. if (isHeader(position)) {
  6. return TYPE_HEADER;
  7. } else if (mCarouse.size()>0&&mHeaders.size()==position){ //判断集合个数&&position==0 这个时候mHeaders里面是没有值的
  8. return TYPE_CAROUSE;
  9. }else if (isFooter(position)) {
  10. return TYPE_FOOTER;
  11. }
  12. int type = getItemViewTypeHF(getRealPosition(position));
  13. if (type == TYPE_HEADER || type == TYPE_FOOTER|| type == TYPE_CAROUSE) {
  14. throw new IllegalArgumentException("Item type cannot equal " + TYPE_HEADER + " or " + TYPE_FOOTER);
  15. }
  16. return type;
  17. }

4).onCreateViewHolder里面也要修改一下,就是在if里面多加了个&&.无论是头部,底部,轮播的View,都是添加到FrameLayout里面的。

  1. @Override
  2. public final RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int type) {
  3. // if our position is one of our items (this comes from
  4. // getItemViewType(int position) below)
  5. if (type != TYPE_HEADER && type != TYPE_FOOTER && type != TYPE_CAROUSE) {
  6. ViewHolder vh = onCreateViewHolderHF(viewGroup, type);
  7. return vh;
  8. // else we have a header/footer
  9. } else {
  10. // create a new framelayout, or inflate from a resource
  11. FrameLayout frameLayout = new FrameLayout(viewGroup.getContext());
  12. // make sure it fills the space
  13. frameLayout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
  14. return new HeaderFooterViewHolder(frameLayout);
  15. }
  16. }

5).onBindViewHolder这里为item绑定数据,其实就是第四步返回的ItemView绑定数据.

  1. @Override
  2. public final void onBindViewHolder(final RecyclerView.ViewHolder vh, int position){
  3. // check what type of view our position is
  4. if (isHeader(position)) {
  5. View v = mHeaders.get(position);
  6. // add our view to a header view and display it
  7. prepareHeaderFooter((HeaderFooterViewHolder) vh, v);
  8. }else if(mCarouse.size()>0&&position==mHeaders.size()){//这个时候mHeaders.size()值为0
  9. // System.out.println("有多少个头View:"+mHeaders.size()+"值等于多少:"+(mHeaders.size()-1));
  10. View v = mCarouse.get(mHeaders.size());//取出轮播的View
  11. prepareHeaderFooter((HeaderFooterViewHolder) vh, v);
  12. } else if (isFooter(position)) {
  13. View v = mFooters.get(position - getItemCountHF() - mHeaders.size());
  14. // add our view to a footer view and display it
  15. prepareHeaderFooter((HeaderFooterViewHolder) vh, v);
  16. } else {
  17. vh.itemView.setOnClickListener(new MyOnClickListener(vh));
  18. vh.itemView.setOnLongClickListener(new MyOnLongClickListener(vh));
  19. // it's one of our items, display as required
  20. onBindViewHolderHF(vh, getRealPosition(position));
  21. }
  22. }

6).我们从第五步看到头部底部轮播View最后都会调用prepareHeaderFooter方法。看到这方法的源码,其实就是把类型对应的View,添加到Item中.

  1. private void prepareHeaderFooter(HeaderFooterViewHolder vh, View view) {
  2. // if it's a staggered grid, span the whole layout
  3. if (mManagerType == TYPE_MANAGER_STAGGERED_GRID) {
  4. StaggeredGridLayoutManager.LayoutParams layoutParams = new StaggeredGridLayoutManager.LayoutParams
  5. (ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);
  6. layoutParams.setFullSpan(true);
  7. vh.itemView.setLayoutParams(layoutParams);
  8. }
  9. // if the view already belongs to another layout, remove it
  10. if (view.getParent() != null) {
  11. ((ViewGroup) view.getParent()).removeView(view);
  12. }
  13. // empty out our FrameLayout and replace with our header/footer
  14. vh.base.removeAllViews();
  15. vh.base.addView(view);
  16. }

三、源码下载

源码下载

四 、相关文章阅读

带你实现开发者头条(一) 启动页实现

带你实现开发者头条(二) 实现左滑菜单

带你实现开发者头条APP(三) 首页实现

带你实现开发者头条APP(四) 首页优化(加入design包)

各位看官如果觉得文章不错,帮忙点个赞吧,对于你来说是举手之劳,但对于我来说这就是坚持下去的动力。

如果你想第一时间看我们的后期文章,扫码关注公众号,每周不定期推送Android开发实战教程文章,你还等什么,赶快关注吧,学好技术,出任ceo,赢取白富美。。。。

  1. Android开发666 - 安卓开发技术分享
  2. 扫描二维码加关注

带你实现开发者头条APP(五)--RecyclerView下拉刷新上拉加载的更多相关文章

  1. Android 下拉刷新上啦加载SmartRefreshLayout + RecyclerView

    在弄android刷新的时候,可算是耗费了一番功夫,最后发觉有现成的控件,并且非常好用,这里记录一下. 原文是 https://blog.csdn.net/huangxin112/article/de ...

  2. 带你实现开发者头条APP(四)---首页优化(加入design包)

    title: 带你实现开发者头条APP(四)---首页优化(加入design包) tags: design,Toolbar,TabLayout,RecyclerView grammar_cjkRuby ...

  3. 带你实现开发者头条APP(三) 首页实现

    title: 带你实现开发者头条APP(三) 首页实现 tags: 轮播广告,ViewPager切换,圆形图片 grammar_cjkRuby: true --- 一.前言 今天实现开发者头条APP的 ...

  4. RecyclerView下拉刷新上拉加载(三)—对Adapter的封装

    RecyclerView下拉刷新上拉加载(一) http://blog.csdn.net/baiyuliang2013/article/details/51506036 RecyclerView下拉刷 ...

  5. RecyclerView下拉刷新上拉加载(二)

    listview下拉刷新上拉加载扩展(一) http://blog.csdn.net/baiyuliang2013/article/details/50252561 listview下拉刷新上拉加载扩 ...

  6. RecyclerView下拉刷新上拉加载(一)

    listview下拉刷新上拉加载扩展(一) http://blog.csdn.net/baiyuliang2013/article/details/50252561 listview下拉刷新上拉加载扩 ...

  7. RecyclerView 下拉刷新上拉加载

    步骤: 首先直接定义一个XRecyclerView继承RecyclerView,重写他的三个构造方法. init(Context mContext)方法用来初始化底部加载的view 回到XRecycl ...

  8. RecyclerView下拉刷新上拉加载更多

    现在Android里都建议用RecyclerView代替ListView和GridView,所以下拉刷新和上拉加载更多也需要实现.下拉刷新可以用SwipeRefreshLayout 包裹Recycle ...

  9. RecyclerView实例-实现可下拉刷新上拉加载更多并可切换线性流和瀑布流模式(1)

    摘要 最近项目有个列表页需要实现线性列表和瀑布流展示的切换,首先我想到的就是上 [RecyclerView],他本身已经很好的提供了三种布局方式,只是简单做个切换应该是很简单的事情,如果要用Recyc ...

随机推荐

  1. Angular2入门系列教程5-路由(一)-使用简单的路由并在在路由中传递参数

    上一篇:Angular2入门系列教程-服务 上一篇文章我们将Angular2的数据服务分离出来,学习了Angular2的依赖注入,这篇文章我们将要学习Angualr2的路由 为了编写样式方便,我们这篇 ...

  2. 《Django By Example》第四章 中文 翻译 (个人学习,渣翻)

    书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:祝大家新年快乐,这次带来<D ...

  3. javascript中的this与函数讲解

    前言 javascript中没有块级作用域(es6以前),javascript中作用域分为函数作用域和全局作用域.并且,大家可以认为全局作用域其实就是Window函数的函数作用域,我们编写的js代码, ...

  4. Redis/HBase/Tair比较

    KV系统对比表 对比维度 Redis Redis Cluster Medis Hbase Tair 访问模式    支持Value大小 理论上不超过1GB(建议不超过1MB) 理论上可配置(默认配置1 ...

  5. hash表长度优化证明

    hash表冲突的解决方法一般有两个方向: 一个是倾向于空间换时间,使用向量加链表可以最大程度的在节省空间的前提下解决冲突. 另外一个倾向于时间换空间,下面是关于这种思路的一种合适表长度的证明过程: 这 ...

  6. CodeSimth - .Net Framework Data Provider 可能没有安装。解决方法

    今天想使用CodeSimth生成一个sqlite数据库的模板.当添加添加数据库的时候发现: .Net Framework Data Provider 可能没有安装. 下面找到官方的文档说明: SQLi ...

  7. Windows 常用运行库下载 (DirectX、VC++、.Net Framework等)

    经常听到有朋友抱怨他的电脑运行软件或者游戏时提示缺少什么 d3dx9_xx.dll 或 msvcp71.dll.msvcr71.dll又或者是 .Net Framework 初始化之类的错误而无法正常 ...

  8. [C#] C# 知识回顾 - 表达式树 Expression Trees

    C# 知识回顾 - 表达式树 Expression Trees 目录 简介 Lambda 表达式创建表达式树 API 创建表达式树 解析表达式树 表达式树的永久性 编译表达式树 执行表达式树 修改表达 ...

  9. 介绍一款原创的四则运算算式生成器:CalculateIt2

    家里小朋友读一年级了,最近每天都有一些10以内的加减法口算练习,作为程序员爸爸,自然也是想办法能够偷懒,让电脑出题,给小朋友做些练习.于是,自己在业余时间开发了一个四则运算算式生成器,名为:Calcu ...

  10. 解决WINDOWS防火墙开启后Ping不通

    WINDOWS系统由于安全考虑,当开启防火墙时,默认不允许外主机对其进行ping功能,即别的电脑ping不通本机.别的主机ping不通本机是因为本机的防火墙关闭了ICMP回显功能,只要把这回显功能打开 ...