Android打造(ListView、GridView等)通用的下拉刷新、上拉自动加载的组件

Android实现RecyclerView的下拉刷新和上拉加载更多 需求先上效果图, Material Design风格的下拉刷新和上拉加载更多。 源码地址(欢迎star) https://github.com/studychen/SeeNewsV2如果对于RecyclerView还不熟悉,参见这篇 Android Material Design学习之RecyclerView代替 ListView下拉刷新效果图上拉时候会有一个圆形动画,刷新加载数据。思路使用Goog 阅读详情

前言

      下拉刷新组件在开发中使用率是非常高的,基本上联网的APP都会采用这种方式。对于开发效率而言,使用获得大家认可的开源库必然是效率最高的,但是不重复发明轮子的前提是你得自己知道轮子是怎么发明出来的,并且自己能够实现这些功能。否则只是知道其原理,并没有去实践那也就是纸上谈兵了。做程序猿,动手做才会遇到真正的问题,否则就只是自以为是的认为自己懂了。今天这篇文章就是以自己重复发明轮子这个出发点而来的,通过实现经典、使用率较高的组件来提高自己的认识。下面我们就一起来学习吧。

整体布局结构

                                          

图1  图2

    该组件整体以竖直方向的LinearLayout为根视图,分别是Header、ContentView、Foooter, 从上到下依次排列下来,其中ContentView的宽高都为match_parent,footer和header的宽、高分别为match_parent、wrap_content,原始效果如图1;在Header、Foooter初始时都会通过设置padding隐藏掉,如图2中的Header设置paddingTop为负的Header的高度值,同理Footer也通过设置paddingBottom为Footer的负的Footer高度来达到隐藏的效果,所以只有 ContentView区域显示出来。当用户下拉到顶端,并且继续下拉时触发下拉刷新操作;当用户上拉到底部, 并且继续上拉时触发加载更多的操作。

    原理都虽然简单,但是实现起来却也是会有很多小麻烦。这里没有采用通过设置onTouchListener的方法,因此使用这个方式在下拉的时候依然会出现ListView的最顶部的"HOLD"视图,不太爽。这种实现方法也蛮简单的,具体看郭神的博客Android下拉刷新完全解析,教你如何一分钟实现下拉刷新功能。

下拉刷新基本原理

      基本原理就是在用户滑动屏幕上的组件时,在onInterceptTouchEvent方法中判断是否到了ContentView (这里我们以ListView为例来说明)的最顶端,如果到了最顶端且用户还继续向下滑,那么会拦截触摸事件避免它分发到ListView,即在onInterceptTouchEvent中返回true ( 不太清楚的可以参考资料如下 : Android Touch事件分发过程。 ),这样就将触摸事件分发到了onTouchEvent函数中,我们对于用户触摸事件的处理逻辑主要都在这个函数中。如果该函数返回false,那么触摸事件则会分发给其Child View,这里的这个Child View就是ListView了,当返回false时用户滑动屏幕时就会滚动ListView。
  1. /* 
  2.  * 在适当的时候拦截触摸事件,这里指的适当的时候是当mContentView滑动到顶部,并且是下拉时拦截触摸事件,否则不拦截,交给其child 
  3.  * view 来处理。 
  4.  * @see 
  5.  * android.view.ViewGroup#onInterceptTouchEvent(android.view.MotionEvent) 
  6.  */  
  7. @Override  
  8. public boolean onInterceptTouchEvent(MotionEvent ev) {  
  9.   
  10.     /* 
  11.      * This method JUST determines whether we want to intercept the motion. 
  12.      * If we return true, onTouchEvent will be called and we do the actual 
  13.      * scrolling there. 
  14.      */  
  15.     final int action = MotionEventCompat.getActionMasked(ev);  
  16.     // Always handle the case of the touch gesture being complete.  
  17.     if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {  
  18.         // Do not intercept touch event, let the child handle it  
  19.         return false;  
  20.     }  
  21.   
  22.     switch (action) {  
  23.   
  24.         case MotionEvent.ACTION_DOWN:  
  25.             mYDown = (int) ev.getRawY();  
  26.             break;  
  27.   
  28.         case MotionEvent.ACTION_MOVE:  
  29.             // int yDistance = (int) ev.getRawY() - mYDown;  
  30.             mYDistance = (int) ev.getRawY() - mYDown;  
  31.             showStatus(mCurrentStatus);  
  32.             Log.d(VIEW_LOG_TAG, "%%% isBottom : " + isBottom() + ", isTop : " + isTop()  
  33.                     + ", mYDistance : " + mYDistance);  
  34.             // 如果拉到了顶部, 并且是下拉,则拦截触摸事件,从而转到onTouchEvent来处理下拉刷新事件  
  35.             if ((isTop() && mYDistance > 0)  
  36.                     || (mYDistance > 0 && mCurrentStatus == STATUS_REFRESHING)) {  
  37.                 return true;  
  38.             }  
  39.             break;  
  40.   
  41.     }  
  42.   
  43.     // Do not intercept touch event, let the child handle it  
  44.     return false;  
  45. }  
    /*
     * 在适当的时候拦截触摸事件,这里指的适当的时候是当mContentView滑动到顶部,并且是下拉时拦截触摸事件,否则不拦截,交给其child
     * view 来处理。
     * @see
     * android.view.ViewGroup#onInterceptTouchEvent(android.view.MotionEvent)
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {

        /*
         * This method JUST determines whether we want to intercept the motion.
         * If we return true, onTouchEvent will be called and we do the actual
         * scrolling there.
         */
        final int action = MotionEventCompat.getActionMasked(ev);
        // Always handle the case of the touch gesture being complete.
        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
            // Do not intercept touch event, let the child handle it
            return false;
        }

        switch (action) {

            case MotionEvent.ACTION_DOWN:
                mYDown = (int) ev.getRawY();
                break;

            case MotionEvent.ACTION_MOVE:
                // int yDistance = (int) ev.getRawY() - mYDown;
                mYDistance = (int) ev.getRawY() - mYDown;
                showStatus(mCurrentStatus);
                Log.d(VIEW_LOG_TAG, "%%% isBottom : " + isBottom() + ", isTop : " + isTop()
                        + ", mYDistance : " + mYDistance);
                // 如果拉到了顶部, 并且是下拉,则拦截触摸事件,从而转到onTouchEvent来处理下拉刷新事件
                if ((isTop() && mYDistance > 0)
                        || (mYDistance > 0 && mCurrentStatus == STATUS_REFRESHING)) {
                    return true;
                }
                break;

        }

        // Do not intercept touch event, let the child handle it
        return false;
    }
      首先我们在ACTION_DOWN事件中记录用户按下的触摸点的Y轴坐标mYDown,然后在ACTION_MOVE中再次获取Y轴的坐标,计算出两者之间的差值。如果滑动的差值大于mTouchSlop则继续进行处理,mTouchSlop为判断一个触摸滑动事件是否有效的的最小阀值,如果小于这个阀值我们认为这个触摸滑动事件无效,例如手抖了一下,距离很短,因此我们忽略类似的事件。
      在有效的滑动距离之内,我们判断当前组件的状态,如果不是正在刷新的状态,那么我们根据当前ListView的paddingTop的高度来设置不同的值,paddingTop如果高度大于ListView高度的70%,那么我们将当前状态设置为“释放可刷新”状态,即STATUS_RELEASE_TO_REFRESH状态;反之,我们设置状态为“继续下拉”状态,即“STATUS_PULL_TO_REFRESH”。通过这个paddingTop高度我们来规定当用户下拉距离到一定的距离后才出发刷新操作,否则视为无效下拉。然而不管这个时候是什么状态,我们都会修改Header的padding Top属性,从而达到拉伸header的效果。
     当状态为“释放可刷新”时,我们抬起手指,会出发ACTION_UP事件,此时我们在该事件中进行下拉刷新操作。onTouchEvent代码如下 :
  1. /* 
  2.  * 在这里处理触摸事件以达到下拉刷新或者上拉自动加载的问题 
  3.  * @see android.view.View#onTouchEvent(android.view.MotionEvent) 
  4.  */  
  5. @Override  
  6. public boolean onTouchEvent(MotionEvent event) {  
  7.   
  8.     Log.d(VIEW_LOG_TAG, "@@@ onTouchEvent : action = " + event.getAction());  
  9.     switch (event.getAction()) {  
  10.         case MotionEvent.ACTION_DOWN:  
  11.             mYDown = (int) event.getRawY();  
  12.             Log.d(VIEW_LOG_TAG, "#### ACTION_DOWN");  
  13.             break;  
  14.   
  15.         case MotionEvent.ACTION_MOVE:  
  16.             Log.d(VIEW_LOG_TAG, "#### ACTION_MOVE");  
  17.             int currentY = (int) event.getRawY();  
  18.             mYDistance = currentY - mYDown;  
  19.             // 高度大于header view的高度才可以刷新  
  20.             if (mYDistance >= mTouchSlop) {  
  21.                 if (mCurrentStatus != STATUS_REFRESHING) {  
  22.                     //   
  23.                     if (mHeaderView.getPaddingTop() > mHeaderViewHeight * 0.7f) {  
  24.                         mCurrentStatus = STATUS_RELEASE_TO_REFRESH;  
  25.                         mTipsTextView.setText(R.string.pull_to_refresh_release_label);  
  26.                     } else {  
  27.                         mCurrentStatus = STATUS_PULL_TO_REFRESH;  
  28.                         mTipsTextView.setText(R.string.pull_to_refresh_pull_label);  
  29.                     }  
  30.                 }  
  31.   
  32.                 rotateHeaderArrow();  
  33.                 int scaleHeight = (int) (mYDistance * 0.8f);// 去了滑动距离的80%,减小灵敏度而已  
  34.                 // Y轴的滑动距离小于屏幕高度4分之一时才会拉伸header,反之保持不变  
  35.                 if (scaleHeight <= mScrHeight / 4) {  
  36.                     adjustHeaderPadding(scaleHeight);  
  37.                 }  
  38.             }  
  39.   
  40.             break;  
  41.   
  42.         case MotionEvent.ACTION_UP:  
  43.             // 下拉刷新的具体操作   
  44.             doRefresh();  
  45.             break;  
  46.         default:  
  47.             break;  
  48.   
  49.     }  
  50.     return true;  
  51. }  
    /*
     * 在这里处理触摸事件以达到下拉刷新或者上拉自动加载的问题
     * @see android.view.View#onTouchEvent(android.view.MotionEvent)
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {

        Log.d(VIEW_LOG_TAG, "@@@ onTouchEvent : action = " + event.getAction());
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mYDown = (int) event.getRawY();
                Log.d(VIEW_LOG_TAG, "#### ACTION_DOWN");
                break;

            case MotionEvent.ACTION_MOVE:
                Log.d(VIEW_LOG_TAG, "#### ACTION_MOVE");
                int currentY = (int) event.getRawY();
                mYDistance = currentY - mYDown;
                // 高度大于header view的高度才可以刷新
                if (mYDistance >= mTouchSlop) {
                    if (mCurrentStatus != STATUS_REFRESHING) {
                        //
                        if (mHeaderView.getPaddingTop() > mHeaderViewHeight * 0.7f) {
                            mCurrentStatus = STATUS_RELEASE_TO_REFRESH;
                            mTipsTextView.setText(R.string.pull_to_refresh_release_label);
                        } else {
                            mCurrentStatus = STATUS_PULL_TO_REFRESH;
                            mTipsTextView.setText(R.string.pull_to_refresh_pull_label);
                        }
                    }

                    rotateHeaderArrow();
                    int scaleHeight = (int) (mYDistance * 0.8f);// 去了滑动距离的80%,减小灵敏度而已
                    // Y轴的滑动距离小于屏幕高度4分之一时才会拉伸header,反之保持不变
                    if (scaleHeight <= mScrHeight / 4) {
                        adjustHeaderPadding(scaleHeight);
                    }
                }

                break;

            case MotionEvent.ACTION_UP:
                // 下拉刷新的具体操作
                doRefresh();
                break;
            default:
                break;

        }
        return true;
    }
抬起手指时出发的刷新操作,代码如下:
  1. /** 
  2.  * 执行刷新操作 
  3.  */  
  4. private final void doRefresh() {  
  5.     if (mCurrentStatus == STATUS_RELEASE_TO_REFRESH) {  
  6.         // 设置状态为正在刷新状态   
  7.         mCurrentStatus = STATUS_REFRESHING;  
  8.         mArrowImageView.clearAnimation();  
  9.         // 隐藏header中的箭头图标   
  10.         mArrowImageView.setVisibility(View.GONE);  
  11.         // 设置header中的进度条可见   
  12.         mHeaderProgressBar.setVisibility(View.VISIBLE);  
  13.         // 设置一些文本   
  14.         mTimeTextView.setText(R.string.pull_to_refresh_update_time_label);  
  15.         SimpleDateFormat sdf = new SimpleDateFormat();  
  16.         mTimeTextView.append(sdf.format(new Date()));  
  17.         //   
  18.         mTipsTextView.setText(R.string.pull_to_refresh_refreshing_label);  
  19.   
  20.         // 执行回调   
  21.         if (mPullRefreshListener != null) {  
  22.             mPullRefreshListener.onRefresh();  
  23.         }  
  24.         // 使headview 正常显示, 直到调用了refreshComplete后再隐藏  
  25.         new HeaderViewHideTask().execute(0);  
  26.   
  27.     } else {  
  28.         // 隐藏header view   
  29.         adjustHeaderPadding(-mHeaderViewHeight);  
  30.     }  
  31. }  
    /**
     * 执行刷新操作
     */
    private final void doRefresh() {
        if (mCurrentStatus == STATUS_RELEASE_TO_REFRESH) {
            // 设置状态为正在刷新状态
            mCurrentStatus = STATUS_REFRESHING;
            mArrowImageView.clearAnimation();
            // 隐藏header中的箭头图标
            mArrowImageView.setVisibility(View.GONE);
            // 设置header中的进度条可见
            mHeaderProgressBar.setVisibility(View.VISIBLE);
            // 设置一些文本
            mTimeTextView.setText(R.string.pull_to_refresh_update_time_label);
            SimpleDateFormat sdf = new SimpleDateFormat();
            mTimeTextView.append(sdf.format(new Date()));
            //
            mTipsTextView.setText(R.string.pull_to_refresh_refreshing_label);

            // 执行回调
            if (mPullRefreshListener != null) {
                mPullRefreshListener.onRefresh();
            }
            // 使headview 正常显示, 直到调用了refreshComplete后再隐藏
            new HeaderViewHideTask().execute(0);

        } else {
            // 隐藏header view
            adjustHeaderPadding(-mHeaderViewHeight);
        }
    }
在刷新状态时,header正常显示,即此时的padding top需要设置为0,我们使用一个异步任务来逐步修改padding top的值,使得header从拉伸效果逐步、平滑的恢复原始的大小。用户调用refreshComplete()函数后,即刷新完成后,再逐步调整listview的padding top将其隐藏。至此,整个下拉刷新过程结束。

滑动到底部自动加载

    滑动到底部自动加载相对来说要简单得多,我们也是以ContentView是ListView的情况来说明。原理就是监听ListView ( 即 ContentView )的的滚动事件,因此如果ContentView的类型不支持滚动事件,则不能实现该功能。listview符合要求,因此其能实现自动加载。我们在onScroll函数中判断listview是否到了最后一项,如果到了最后一项,那么显示出footer,并且开始加载。当用户调用loadMoreComplete函数时代表加载结束。此时隐藏footer,整个过程结束。
    
  1. /* 
  2.  * 滚动事件,实现滑动到底部时上拉加载更多 
  3.  * @see android.widget.AbsListView.OnScrollListener#onScroll(android.widget. 
  4.  * AbsListView, int, int, int) 
  5.  */  
  6. @Override  
  7. public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,  
  8.         int totalItemCount) {  
  9.   
  10.     Log.d(VIEW_LOG_TAG, "&&& mYDistance = " + mYDistance);  
  11.     if (mFooterView == null || mYDistance >= 0 || mCurrentStatus == STATUS_LOADING  
  12.             || mCurrentStatus == STATUS_REFRESHING) {  
  13.         return;  
  14.     }  
  15.   
  16.     loadmore();  
  17. }  
  18.   
  19. /** 
  20.  * 下拉到底部时加载更多 
  21.  */  
  22. private void loadmore() {  
  23.     if (isShowFooterView() && mLoadMoreListener != null) {  
  24.         mFooterTextView.setText(R.string.pull_to_refresh_refreshing_label);  
  25.         mFooterProgressBar.setVisibility(View.VISIBLE);  
  26.         adjustFooterPadding(0);  
  27.         mCurrentStatus = STATUS_LOADING;  
  28.         mLoadMoreListener.onLoadMore();  
  29.     }  
  30. }  
    /*
     * 滚动事件,实现滑动到底部时上拉加载更多
     * @see android.widget.AbsListView.OnScrollListener#onScroll(android.widget.
     * AbsListView, int, int, int)
     */
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
            int totalItemCount) {

        Log.d(VIEW_LOG_TAG, "&&& mYDistance = " + mYDistance);
        if (mFooterView == null || mYDistance >= 0 || mCurrentStatus == STATUS_LOADING
                || mCurrentStatus == STATUS_REFRESHING) {
            return;
        }

        loadmore();
    }

    /**
     * 下拉到底部时加载更多
     */
    private void loadmore() {
        if (isShowFooterView() && mLoadMoreListener != null) {
            mFooterTextView.setText(R.string.pull_to_refresh_refreshing_label);
            mFooterProgressBar.setVisibility(View.VISIBLE);
            adjustFooterPadding(0);
            mCurrentStatus = STATUS_LOADING;
            mLoadMoreListener.onLoadMore();
        }
    }
其中loadmore函数中调用的isShowFooterView函数就是用来判断是否到了最底部的,代码如下 : 
  1. /* 
  2.     * 下拉到listview 最后一项时则返回true, 将出发自动加载 
  3.     * @see com.uit.pullrefresh.base.PullRefreshBase#isShowFooterView() 
  4.     */  
  5.    @Override  
  6.    protected boolean isShowFooterView() {  
  7.        if (mContentView == null || mContentView.getAdapter() == null) {  
  8.            return false;  
  9.        }  
  10.   
  11.        return mContentView.getLastVisiblePosition() == mContentView.getAdapter().getCount() - 1;  
  12.    }  
 /*
     * 下拉到listview 最后一项时则返回true, 将出发自动加载
     * @see com.uit.pullrefresh.base.PullRefreshBase#isShowFooterView()
     */
    @Override
    protected boolean isShowFooterView() {
        if (mContentView == null || mContentView.getAdapter() == null) {
            return false;
        }

        return mContentView.getLastVisiblePosition() == mContentView.getAdapter().getCount() - 1;
    }
OK,至此整个核心的过程介绍完毕了。

效果图

ListView



TextView下拉刷新


github地址

猛击这里!

Android ScrollView、ListView与GridView下拉刷新上拉加载实战详解 GridView的问题比ListView更严重,因为它还要考虑列数适配。我们可以通过重写来强制它展开:@Override这里的关键是用了模式,并赋予一个极大值(约50万像素),相当于说:“你想多高就多高,但别超过这个上限。虽然听着有点野蛮,但在某些固定内容的页面(如标签墙、功能入口网格)中还挺实用的。但说实话,这些“打补丁”的方式就像是给漏水的船贴创可贴。真正靠谱的解决方案,还得靠现代化的嵌套滚动架构。默认的刷新样式太普通?想要更有个性的动画?完全可以! 阅读详情

相关推荐

哨兵2号遥感影像解析全流程:步骤、算法与AI应用详解

未来,多源数据融合与边缘计算技术的应用将进一步拓展遥感解析的边界。波段合成:选择10m分辨率波段(如B2、B3、B4、B8)进行Layer Stacking,生成多光谱影像。| 分类与识别 | Scikit-Learn、PyTorch | SVM、CNN、K-Means聚类 | 地块分类、目标检测 || 数据预处理 | SNAP、Sen2Cor | 大气校正、几何校正 | L2A产品生成、格式转换 || 波段融合 | ENVI、GDAL | Layer Stacking、重采样 | 多光谱影像合成 |

zhz5214的博客 2711

【Android】上拉加载更多,下拉刷新数据快速实现

页面数据刷新

每天不是在写bug就是在写bug的路上 1277

阿里云大模型ACP认证模拟考试(一)

摘要:在阿里云大模型高级工程师 ACP 认证暂无真题题库的现状下,模拟题具有重要意义。其依照真实考试设计,涵盖题型、题量与分值分布,助力考生熟悉考试框架,合理分配答题时间精力,提升效率。同时,模拟题紧扣官方课程,能帮助考生精准定位知识盲点,如大模型架构原理和通义千问应用实践等重点内容,以便针对性完善知识体系。此外,通过练习模拟题,考生可掌握不同题型的解题思维与技巧,快速洞察复杂题目本质,提高答题准确率。

davidkorhenn的博客 4743

Android中的RecyclerView下拉/上拉刷新数据

RecyclerView上拉/下拉刷新数据

m0_62278064的博客 5459

PSIM联合VS--C++实现正弦波发生

在利用VS联合PSIM仿真中,想要用VS构建一个正弦波发生模块。可以利用Sin函数进行编写,重点是需要编写一个计数器程序。首先打算用for循环语句来构建计数器,但在for循环运行时无法跳出,不能实时获得计数器的值。同理,while循环也无法实现。最后将count变量设置为static型,解决了这一问题。 体现出对于c++程序的运行不够了解,需要多进行程序的编写和调试。 //时钟计数器 static int count = 0; count++; if (count > Sinfre)

weixin_41850228的博客 1087

安卓 实现灯光闪过效果

有个小需求,给按钮加一个灯光划过的效果,这样的需求一般有UI,肯定就找UI了要个gif图不就完事了,可是这次没有,好久自己做一个嘛。Web端的大佬实现很快,到安卓这边呢,百度一搜发现诶?怎么没有,好吧自己来一个 一切动效相关的不给图看都是耍流氓 所以俺不能这么干啊,OK!直接上效果图,再来解释下怎么实现的 效果就是这样子,怎么实现呢? 从图分析下,就是一个光写着重左边移动要右边循环嘛,这有啥难的?? 来看一看我的第一版,第二版 这是个什么?????一点都不像啊? 赶紧再问了问Web端大佬,噢,加了一个

SummerCloudXT的博客 1378

Android实现下拉刷新和上拉加载数据(网络请求数据)

在安卓开发中,我们会经常遇到上拉加载和下拉刷新的功能,通过网络请求拿到数据然后添加到控件上,之前自己也在网上搜索过一些文章,但基本上用处不大,要么是效果不一样,要么是贴的代码不完整,从而导致功能无法正常使用(很蛋疼),所以在摸索了一阵之后,完成了一个大致OK的demo,供大家参考。有问题还望大家指正出来,感激不尽。。 ......

小口口的博客 1万+

【K8S系列】Kubernetes Pod节点CrashLoopBackOff 状态及解决方案详解【已解决】

在 Kubernetes 中,Pod 的状态为 **`CrashLoopBackOff`** 表示某个容器在启动后崩溃,Kubernetes > 尝试重启该容器,但由于持续崩溃,重启的间隔时间逐渐增加。下面将详细介绍 `CrashLoopBackOff > `状态的原因、解决方案及相关命令的输出解释。

颜淡慕潇 8381

Android打造 ListView GridView等 通用的下拉刷新 上拉自动加载的组件

Android打造 ListView GridView等 通用的下拉刷新 上拉自动加载的组件

qq_43661309的博客 511

国科大学习资料--人工智能原理与算法-2020年期末考试题解析(学长整理)

国科大学习资料–人工智能原理与算法-2020年期末考试题解析 张文生老师主讲 试卷共有6道题,题目不难,希望大家能取得好的成绩。 3.9 传教士和野人问题。三个传教士和三个野人在河的一岸,有一条能载一个人或者两个人的船。请设法使所有人都渡到河的另一岸,要求在任何地方野人数都不能多于传教士的人数。这个问题在AI领域中很有名,是因为它是第一个从分析的观点探讨问题形式化的论文的主题(Amarel,1968)。 a. 请对该问题进行详细形式化,只描述确保该问题求解所必需的特性。画出完整的状态空间图。 b. 应用合适

无名何许人的博客 4788

DeepSeek如何构建可扩展的 AI 驱动交易系统,基于 MetaTrader 5 与 Python 利用先进的数据处理、机器学习和容器化部署来优化算法交易。

MT5 Python API 架构设计分为三层:通信层:利用异步消息传递(例如 ZeroMQ 或标准套接字编程)支持每秒数万个数据请求。转换层: C++ 动态库有效地将 MT5 命令转换为 Python 对象(反之亦然),从而优化速度和内存使用率。接口层:提供Pythonic API,封装了所有终端功能,包括:1)实时价格订阅(滴答或秒级更新)2)历史数据检索(从M1到更高的时间范围)3)订单流监控(交易详情和市场深度)4)策略执行引擎(用于算法交易)

iCloudEnd的博客 1382

android下拉刷新完全解析,教你如何一分钟实现下拉刷新功能,Android打造(ListView、GridView等)通用的下拉刷新、上拉自动加载的组件...

前言下拉刷新组件在开发中使用率是非常高的,基本上联网的APP都会采用这种方式。对于开发效率而言,使用获得大家认可的开源库必然是效率最高的,但是不重复发明轮子的前提是你得自己知道轮子是怎么发明出来的,并且自己能够实现这些功能。否则只是知道其原理,并没有去实践那也就是纸上谈兵了。做程序猿,动手做才会遇到真正的问题,否则就只是自以为是的认为自己懂了。今天这篇文章就是以自己重复发明轮子这个出发点而来的,通...

weixin_36270006的博客 1031

海康visionmaster开发笔记10-集成HALCON第三方算子到VM工具箱的方法

海康visionmaster开发笔记10-HALCON第三方算子到VM工具箱的方法

视觉人机器视觉的博客 4347

打造通用的Android下拉刷新组件 适用于ListView GridView等各类View

打造通用的Android下拉刷新组件 适用于ListView GridView等各类View

qq_43661309的博客 149

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Android 快速开发系列 打造万能的ListView GridView 适配器

转载请标明出处:http://blog.youkuaiyun.com/lmj623565791/article/details/38902805 ,本文出自【张鸿洋的博客】1、概述相信做Android开发的写得最多的就是ListView,GridView的适配器吧,记得以前开发一同事开发项目,一个项目下来基本就一直在写ListView的Adapter都快吐了~~~对于Adapter一般都继承BaseAdapt

Hongyang 15万+

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

打造通用的Android下拉刷新组件(适用于ListView、GridView等各类View)

最近在做项目时,使用了一个开源的下拉刷新ListView组件,极其的不稳定,bug还多。稳定的组件又写得太复杂了,jar包较大。在我的一篇博客中也讲述过下拉刷新的实现,即Android打造(ListView、GridView等)通用的下拉刷新、上拉自动加载的组件。但是这种通过修改Margin的形式感觉不是特别的流畅,因此又花了点时间用另外的原理实现了一遍,特此分享出来。

Mr.Simple的专栏 1万+

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

上一篇: android 单元测试 .
下一篇: UI组件适配器AdapterView(创建ListView,Adapter接口).
mypanlong
博客等级 码龄19年 194粉丝 1原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值