Listview现在用的很少了,基本都是使用Recycleview,但是不得不说Listview具有划时代的意义,拓展性很强,我们可以自己添加下拉刷新,上拉加载更多功能。他和recycleview不同,他生来具有addHeaderView和addFooterView的功能,这也导致同样都是列表控件,实现上拉下拉的方式缺截然不同。

效果图

1、创建刷新控件

public class MyListview extends ListView {


    public MyListview(Context context) {
        this(context,null);
    }

    public MyListview(Context context, AttributeSet attrs) {
        this(context,attrs,0);
    }

    public MyListview(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }
    public void init(Context context) {


    }

1.1、创建头部View

头部样式,我写的是最简单的,根据业务需求来定,下拉的时候无非就是几种

  • 产品logo作为箭头转动的icon
  • 添加刷新时间
  • 加入其他具有特色的动效

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:gravity="center"
    tools:ignore="MissingDefaultResource">
    <ProgressBar
        android:layout_width="20dp"
        android:layout_height="match_parent"
        style="?android:attr/progressBarStyle"
        android:layout_marginEnd="10dp"
        android:indeterminateTint="#E8AD56"
        />
    <TextView
        android:id="@ id/header_text"
        android:layout_width="wrap_content"
        android:layout_height="50dp"
        android:text="我是头部"
        android:gravity="center"
        android:textColor="#E8AD56"/>
</LinearLayout>

样式写好后,我们需要添加到我们控件中,addHeaderView就起到作用了

public void init(Context context) {
    //添加头部
    viewHeader = View.inflate(context, R.layout.view_header, null);
    viewHeader.measure(0, 0);
    //让系统自动检测头部高度
    heightHeader = viewHeader.getMeasuredHeight();
    header_text = viewHeader.findViewById(R.id.header_text);
    viewHeader.setPadding(0, -heightHeader, 0, 0);
    this.addHeaderView(viewHeader);
}

一些控件我定义成全局的是因为下面会用到。setPadding可以设置显示位置,左上右下,上为负数就是隐藏在顶部。我们需要手指下拉去控制他缓慢显示,就用到了OnTouchListener,我们实现OnTouch方法做一些事件的分发处理。

1.2、下拉事件

public class MyListview extends ListView implements View.OnTouchListener{
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return false;
    }
   public void init(Context context){
       setOnTouchListener(this);
   }
}

注意:别忘记了setOnTouchListener在init中添加

这时候我们需要对event的down,move,up事件进行逻辑处理,当手指按在屏幕时会触发事件,一个down事件,0~无数次move事件,一个up事件,这里面着重对move事件做处理,我们记录一下down事件的Y,因为是上下拉动,没必要计算X。然后diffY就是手指滑动的距离,我们需要处理一下这个值,因为值太大,而且值是整数,会让我们下拉的时候产生错乱,我们本意是让其从-100到0缓慢滑出(比如头部高度是100,从隐藏到显示就是-100到0),小伙伴都可以试试viewHeader.setPadding(0, diffY, 0, 0);和viewHeader.setPadding(0, paddY, 0, 0);效果是不一样的,diff/3是让其有种阻尼的感觉,不然的话会很块就被拉出来了。还有事件消费的话一定要return true。

@Override
public boolean onTouch(View v, MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            downY = (int) event.getY();
            break;
        case MotionEvent.ACTION_MOVE:
            moveY = (int) event.getY();
            diffY = moveY - downY;
            //滑动的距离
            paddY = - heightHeader   diffY / 3;
            viewHeader.setPadding(0, paddY, 0, 0);
            return true;
            //break;
        case MotionEvent.ACTION_UP:

            break;
    }
    return false;
}

我们下面要做下拉时给人的反馈,我们下拉时有3种状态分别是

  • 开始刷新  (下拉距离不超过100)
  • 释放刷新   (下拉距离超过100)
  • 刷新中    (手指释放,up事件处理)

//属性-开始刷新状态
private final int PULL_REFRESH_STATE = 0;
private final int PULL_REFRESH_RELEASE = 1;//释放刷新
private final int PULL_REFRESHING = 2;//正在刷新
private int pull_current_state = PULL_REFRESH_STATE;//当前状态
public void updateHeaderState() {
    switch (pull_current_state) {
        //开始
        case PULL_REFRESH_STATE:
            header_text.setText("开始刷新");
            viewHeader.setPadding(0, -heightHeader, 0, 0);
            break;
        //释放
        case PULL_REFRESH_RELEASE:
            header_text.setText("释放刷新");
            break;
        //正在
        case PULL_REFRESHING:
            header_text.setText("刷新中.......");
            viewHeader.setPadding(0, 0, 0, 0);
            break;

    }
}

我们只需要判断是否处于刷新中,如果不是,则计算是不是第一个item可见并且滑动距离大于0,证明手指滑动了。然后不同滑出高度显示不同的文字即可。

@Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downY = (int) event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                moveY = (int) event.getY();
                diffY = moveY - downY;
                //滑动的距离
                paddY = - heightHeader   diffY / 3;
                //如果是正在刷新中不做任何操作
                if (pull_current_state == PULL_REFRESHING) {
                    return false;
                }
//                下拉//第一条,并且滑动距离大于0
                if (getFirstVisiblePosition() == 0 && diffY > 0) {
                    if (paddY > 0 && pull_current_state != PULL_REFRESH_RELEASE) {
                        //释放刷新
                        pull_current_state = PULL_REFRESH_RELEASE;
                        updateHeaderState();
                    } else if (paddY < 0 && pull_current_state != PULL_REFRESH_STATE) {
                        pull_current_state = PULL_REFRESH_STATE;
                        header_text.setText("开始刷新");
                        updateHeaderState();
                    }
                    viewHeader.setPadding(0, paddY, 0, 0);
                    return true;
                }

                break;
            case MotionEvent.ACTION_UP:
                if (pull_current_state == PULL_REFRESH_STATE) {
                    updateHeaderState();
                } else if (pull_current_state == PULL_REFRESH_RELEASE) {
                    pull_current_state = PULL_REFRESHING;
                    updateHeaderState();
                }
                break;
        }
        return false;
    }

1.3、接口回调

我们需要状态根据业务来动态调整,在可以刷新的时候做一些逻辑处理,同时处理完了,调整状态。

public void setPullDownFinish() {
    pull_current_state = PULL_REFRESH_STATE;
    viewHeader.setPadding(0, -heightHeader, 0, 0);
}
public IPullDownRefreshService iPullDownRefreshService;
public interface IPullDownRefreshService {
    void onPullDownRefresh();//下拉刷新

    void onLoadMore();//上拉加载更多刷新
}

public void setOnRefreshListener(IPullDownRefreshService iPullDownRefreshService) {
    this.iPullDownRefreshService = iPullDownRefreshService;
}

准备工作做好后,我们在更新状态的地方调用

public void updateHeaderState() {
    switch (pull_current_state) {
        //开始
        case PULL_REFRESH_STATE:
            break;
        //释放
        case PULL_REFRESH_RELEASE:
            break;
        //正在
        case PULL_REFRESHING:
            header_text.setText("刷新中.......");
            viewHeader.setPadding(0, 0, 0, 0);
            if (iPullDownRefreshService != null) {
                iPullDownRefreshService.onPullDownRefresh();
            }
            break;

    }
}

Activity中使用,来一个3秒刷新完成

mBinding.listview.setOnRefreshListener(new MyListview.IPullDownRefreshService() {
            @Override
            public void onPullDownRefresh() {
                refreshSuccess();
                Toast.makeText(ActivityRefresh.this, "下拉-加载中.....", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onLoadMore() {
                Toast.makeText(ActivityRefresh.this, "more-加载中.....", Toast.LENGTH_SHORT).show();
            }
        });

    CountDownTimer countDownTimer;
    public void refreshSuccess() {
        if (countDownTimer == null) {
            countDownTimer = new CountDownTimer(3000, 1000) {

                @Override
                public void onTick(long millisUntilFinished) {

                }

                @Override
                public void onFinish() {
                    mBinding.listview.setPullDownFinish();
                    countDownTimer.cancel();
                    countDownTimer = null;
                }
            }.start();
        }
    }

到这下拉刷新就结束了。

上拉加载更多也是如此

2、上拉加载更多

2.1、底部样式

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:gravity="center"
    tools:ignore="MissingDefaultResource">
    <ProgressBar
        android:id="@ id/footer_prggress"
        android:layout_width="20dp"
        android:layout_height="match_parent"
        style="?android:attr/progressBarStyle"
        android:layout_marginEnd="10dp"
        android:indeterminateTint="#E8AD56"
        />
    <TextView
        android:id="@ id/footer_text"
        android:layout_width="wrap_content"
        android:layout_height="70dp"
        android:text="正在加载更多"
        android:gravity="center"
        android:textColor="#E8AD56"/>

</LinearLayout>

2.2、布局添加

public void init(Context context) {
    viewFooter = View.inflate(context, R.layout.view_footer, null);
    viewFooter.measure(0, 0);
    footer_text = viewFooter.findViewById(R.id.footer_text);
    footer_prggress = viewFooter.findViewById(R.id.footer_prggress);
    heightFooter = viewFooter.getMeasuredHeight();
    viewFooter.setPadding(0, -heightFooter, 0, 0);
    this.addFooterView(viewFooter);
}

到这里也布局算是添加完毕了,加载更多实现方式不同,我罗列两种

  • 结合OnTouchListener
  • 结合OnScrollListener

方式一

这里我先说方式一,因为我们下拉也是用的OnTouchListener,上拉加载也有几种状态,有加载中,还有暂无数据,普遍大家会写, 已经到底了~,一直显示在最底部,提示用户没数据了,从而我们控件的上拉事件不可触发状态。

private final int MORE_LOAD_STATE = 10;
private final int MORE_LOADING = 11;
private final int MORE_NO = 12;//已加载全部数据
private int more_current_state = MORE_LOAD_STATE;//当前状态

只有一点需要注意paddFooterY = paddFooterY > heightFooter ? 0 : paddFooterY;来判断不能滑出底部的高度。

@Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downY = (int) event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                moveY = (int) event.getY();
                diffY = moveY - downY;
                //滑动的距离
                paddFooterY = heightFooter - diffY/3 ;  
                //上拉加载更多
                if (getLastVisiblePosition() == getCount() - 1 && more_current_state != MORE_NO) {
                    if( more_current_state!=MORE_LOADING){
                        more_current_state = MORE_LOADING;
                        if (iPullDownRefreshService != null) {
                            iPullDownRefreshService.onLoadMore();
                        }
                    }
                    paddFooterY = paddFooterY > heightFooter ? 0 : paddFooterY;
                    viewFooter.setPadding(0,paddFooterY , 0, 0);
                     return true;
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return false;
    }

方式二

public class MyListview extends ListView implements View.OnTouchListener, AbsListView.OnScrollListener{
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        //没有滚动,或者已经用户触摸滚动动画结束
        if(scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_FLING){
            //最后一个可见
            if(getLastVisiblePosition() == getCount()-1){
                viewFooter.setPadding(0,0,0,0);
                if(iPullDownRefreshService!=null){
                    iPullDownRefreshService.onLoadMore();
                }
            }
        }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

    }

}

注意:在init方法中添加

public void init(Context context) {
    setOnTouchListener(this);
    ......
    this.setOnScrollListener(this);
}

到此这篇关于Android自定义ListView实现下拉刷新上拉加载更多的文章就介绍到这了,更多相关Android ListView下拉刷新上拉加载内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

Android自定义ListView实现下拉刷新上拉加载更多的更多相关文章

  1. html5 canvas合成海报所遇问题及解决方案总结

    这篇文章主要介绍了html5 canvas合成海报所遇问题及解决方案总结,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. Html5 video标签视频的最佳实践

    这篇文章主要介绍了Html5 video标签视频的最佳实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  3. HTML5在微信内置浏览器下右上角菜单的调整字体导致页面显示错乱的问题

    HTML5在微信内置浏览器下,在右上角菜单的调整字体导致页面显示错乱的问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

  4. ios – containerURLForSecurityApplicationGroupIdentifier:在iPhone和Watch模拟器上给出不同的结果

    我使用默认的XCode模板创建了一个WatchKit应用程序.我向iOSTarget,WatchkitAppTarget和WatchkitAppExtensionTarget添加了应用程序组权利.(这是应用程序组名称:group.com.lombax.fiveminutes)然后,我尝试使用iOSApp和WatchKitExtension访问共享文件夹URL:延期:iOS应用:但是,测试NSURL

  5. Ionic – Splash Screen适用于iOS,但不适用于Android

    我有一个离子应用程序,其中使用CLI命令离子资源生成的启动画面和图标iOS版本与正在渲染的启动画面完美配合,但在Android版本中,只有在加载应用程序时才会显示白屏.我检查了config.xml文件,所有路径看起来都是正确的,生成的图像出现在相应的文件夹中.(我使用了splash.psd模板来生成它们.我错过了什么?这是config.xml文件供参考,我觉得我在这里做错了–解决方法在config.xml中添加以下键:它对我有用!

  6. ios – 无法启动iPhone模拟器

    /Library/Developer/CoreSimulator/Devices/530A44CB-5978-4926-9E91-E9DBD5BFB105/data/Containers/Bundle/Application/07612A5C-659D-4C04-ACD3-D211D2830E17/ProductName.app/ProductName然后,如果您在Xcode构建设置中选择标准体系结构并再次构建和运行,则会产生以下结果:dyld:lazysymbolbindingFailed:Symbol

  7. Xamarin iOS图像在Grid内部重叠

    heyo,所以在Xamarin我有一个使用并在其中包含一对,所有这些都包含在内.这在Xamarin.Android中看起来完全没问题,但是在Xamarin.iOS中,图像与标签重叠.我不确定它的区别是什么–为什么它在Xamarin.Android中看起来不错但在iOS中它的全部都不稳定?

  8. ios – 在React Native中设置ListView的高度

    我需要设置ListView的宽度和高度.当设置宽度按预期工作时,设置高度无效,ListView总是伸展到屏幕的几乎底部.我用这种方式在render方法中创建ListView:这是它的风格:我还尝试通过此命令在方法中设置其高度:当我尝试使用此命令设置宽度时,它可以工作.但设定高度什么都不做.如何将ListView的高度设置为所需的值?

  9. 在iOS上向后播放HTML5视频

    我试图在iPad上反向播放HTML5视频.HTML5元素包括一个名为playbackRate的属性,它允许以更快或更慢的速率或相反的方式播放视频.根据Apple’sdocumentation,iOS不支持此属性.通过每秒多次设置currentTime属性,可以反复播放,而无需使用playbackRate.这种方法适用于桌面Safari,但似乎在iOS设备上的搜索限制为每秒1次更新–在我的情况下太慢了.有没有办法在iOS设备上向后播放HTML5视频?解决方法iOS6Safari现在支持playbackRat

  10. 使用 Swift 语言编写 Android 应用入门

    Swift标准库可以编译安卓armv7的内核,这使得可以在安卓移动设备上执行Swift语句代码。做梦,虽然Swift编译器可以胜任在安卓设备上编译Swift代码并运行。这需要的不仅仅是用Swift标准库编写一个APP,更多的是你需要一些框架来搭建你的应用用户界面,以上这些Swift标准库不能提供。简单来说,构建在安卓设备上使用的Swiftstdlib需要libiconv和libicu。通过命令行执行以下命令:gitclonegit@github.com:SwiftAndroid/libiconv-libi

随机推荐

  1. Flutter 网络请求框架封装详解

    这篇文章主要介绍了Flutter 网络请求框架封装详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. Android单选按钮RadioButton的使用详解

    今天小编就为大家分享一篇关于Android单选按钮RadioButton的使用详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

  3. 解决android studio 打包发现generate signed apk 消失不见问题

    这篇文章主要介绍了解决android studio 打包发现generate signed apk 消失不见问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

  4. Android 实现自定义圆形listview功能的实例代码

    这篇文章主要介绍了Android 实现自定义圆形listview功能的实例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  5. 详解Android studio 动态fragment的用法

    这篇文章主要介绍了Android studio 动态fragment的用法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  6. Android用RecyclerView实现图标拖拽排序以及增删管理

    这篇文章主要介绍了Android用RecyclerView实现图标拖拽排序以及增删管理的方法,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下

  7. Android notifyDataSetChanged() 动态更新ListView案例详解

    这篇文章主要介绍了Android notifyDataSetChanged() 动态更新ListView案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下

  8. Android自定义View实现弹幕效果

    这篇文章主要为大家详细介绍了Android自定义View实现弹幕效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  9. Android自定义View实现跟随手指移动

    这篇文章主要为大家详细介绍了Android自定义View实现跟随手指移动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. Android实现多点触摸操作

    这篇文章主要介绍了Android实现多点触摸操作,实现图片的放大、缩小和旋转等处理,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部