網站首頁 編程語言 正文
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);
}
原文鏈接:https://www.cnblogs.com/cmusketeer/p/16769560.html
相關推薦
- 2022-09-07 Jquery實現異步上傳文件_jquery
- 2022-10-19 Docker鏡像與容器的導入導出以及常用命令總結_docker
- 2022-12-29 一文詳細談談GoLang的panic和error_Golang
- 2022-09-04 C/C++?引用作為函數的返回值方式_C 語言
- 2022-07-04 C#使用System.Buffer以字節數組Byte[]操作基元類型數據_C#教程
- 2022-04-30 DataGridView自動設定列寬和行高_C#教程
- 2022-12-05 c++入門必學庫函數sort的基本用法_C 語言
- 2021-12-02 C++11標準庫bind函數應用教程_C 語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支