當前位置:首頁 » 安卓系統 » android的下拉刷新控制項

android的下拉刷新控制項

發布時間: 2025-08-11 23:43:27

『壹』 【Android】下拉刷新&上拉載入更多組件記錄(81/100)

SmartRefreshLayout,一個旨在提供強大、穩定和成熟的下拉刷新體驗的組件。它智能地支持所有視圖和多層嵌套結構,通過繼承 ViewGroup 而非 FrameLayout 或 LinearLayout,以提高性能。SmartRefreshLayout 吸收並融合了市面上流行的下拉刷新組件的優點,包括谷歌的 SwipeRefreshLayout 和其他第三方組件如 Ultra-Pull-To-Refresh、TwinklingRefreshLayout。此外,它還提供了一系列炫酷的 Header 和 Footer,豐富了用戶體驗。

以下是 SmartRefreshLayout 的實際應用效果。布局設計和預覽效果已經展示,直觀地呈現了組件的使用方式和外觀。

在業務層面,SmartRefreshLayout 的集成與配置需要與特定應用的業務邏輯相協調,以實現高效的數據載入和刷新操作。

SmartRefreshLayout 的源代碼託管在碼雲 GitHub,方便開發者進行下載、使用和反饋。

對於 API 介面的開發,smartApi-v1.0.0 版本的正式發布,標志著歷時一年半的開發工作終於迎來了成果。這款工具對標國外的 Postman,旨在為 API 調試和開發提供強大的支持。盡管開發團隊僅有一人,但v1.0.0版本已經提供了核心功能,包括但不限於 API 請求的發送、響應的接收和詳細的日誌記錄。

為了便於用戶獲取和使用 smartApi,開發者提供了一個下載鏈接,指向網路網盤,確保工具能夠迅速到達有需求的開發者手中。

『貳』 android中怎麼實現上拉刷新

這篇文章主要介紹了android實現listview下拉刷新和上拉刷新效果,Android的ListView上拉下拉刷新,原理都一樣,在Touch事件中操作header/footer的paddingTop屬性,需要的朋友可以參考下

java">{

privatestaticfinalStringTAG=PullToLoadListView.class.getSimpleName();

privatestaticfinalintSTATE_NON=0;
privatestaticfinalintSTATE_PULL_TO_REFRESH=1;
privatestaticfinalintSTATE_RELEASE_TO_REFRESH=2;
privatestaticfinalintSTATE_REFRESHING=3;

privateintstate;

privateintfirstVisibleItem;
privateintlastVisisibleItem;

privatefloatprevY=0;

privateViewheaderView;
privateViewfooterView;

//headerwidgets
;
;
privateTextViewheaderText;
;
;
//footerwidgets
;
privateTextViewfooterText;

privatebooleanheaderIsHanding=false;
privatebooleanfooterIsHanding=false;

privateintheaderHeight;
privateintfooterHeight;

;

;

;

publicPullToLoadListView(Contextcontext){
super(context);
init(context);
}

publicPullToLoadListView(Contextcontext,AttributeSetattrs){
super(context,attrs);
init(context);
}

privatevoidinit(Contextcontext){
state=STATE_NON;
firstVisibleItem=0;
lastVisisibleItem=0;

LayoutInflaterinflater=LayoutInflater.from(context);
headerView=inflater.inflate(R.layout.view_pull_header,null);
footerView=inflater.inflate(R.layout.view_pull_footer,null);

headerProgressBar=(ProgressBar)headerView.findViewById(R.id.progressbar);
headerImageArrow=(ImageView)headerView.findViewById(R.id.arrow);
headerText=(TextView)headerView.findViewById(R.id.text);
headerArrowAnim=newRotateAnimation(0,-180,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
headerArrowAnim.setDuration(300);
headerArrowAnim.setFillAfter(true);
headerArrowReverseAnim=newRotateAnimation(-180,0,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
headerArrowReverseAnim.setDuration(300);
headerArrowReverseAnim.setFillAfter(true);

footerProgressBar=(ProgressBar)footerView.findViewById(R.id.progressbar);
footerText=(TextView)footerView.findViewById(R.id.text);

measureView(headerView);
measureView(footerView);
headerHeight=headerView.getMeasuredHeight();
footerHeight=footerView.getMeasuredHeight();
headerView.setPadding(0,-1*headerView.getMeasuredHeight(),0,0);
footerView.setPadding(0,-1*footerView.getMeasuredHeight(),0,0);
headerView.invalidate();
footerView.invalidate();
addHeaderView(headerView,null,false);
addFooterView(footerView,null,false);

super.setOnScrollListener(this);
}

privatevoidmeasureView(Viewview){
ViewGroup.LayoutParamslp=view.getLayoutParams();
if(lp==null){
lp=newViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);
}
intchildWidthSpec=ViewGroup.getChildMeasureSpec(0,0,lp.width);
intchildHeightSpec;
if(lp.height>0){
childHeightSpec=MeasureSpec.makeMeasureSpec(0,MeasureSpec.EXACTLY);
}else{
childHeightSpec=MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED);
}
view.measure(childWidthSpec,childHeightSpec);
}

privatevoidresetHeader(){
//headerView.setPadding(0,-1*headerHeight,0,0);
resetAnim=newResetAnimation(headerView,headerHeight,headerView.getPaddingTop());
resetAnim.start();
}

privatevoidresetFooter(){
resetAnim=newResetAnimation(footerView,footerHeight,footerView.getPaddingTop());
resetAnim.start();
}

(intstate){
if(this.state==state){
return;
}
intprevState=this.state;
this.state=state;

switch(state){
caseSTATE_NON:
headerProgressBar.setVisibility(View.INVISIBLE);
headerImageArrow.setVisibility(View.VISIBLE);
headerImageArrow.clearAnimation();
headerText.setText("PullDownToRefresh");
break;
caseSTATE_PULL_TO_REFRESH:
headerProgressBar.setVisibility(View.INVISIBLE);
headerImageArrow.setVisibility(View.VISIBLE);
headerText.setText("PullDownToRefresh");
if(prevState==STATE_RELEASE_TO_REFRESH){
headerImageArrow.startAnimation(headerArrowReverseAnim);
}else{
headerImageArrow.clearAnimation();
}
break;
caseSTATE_RELEASE_TO_REFRESH:
headerProgressBar.setVisibility(View.INVISIBLE);
headerImageArrow.setVisibility(View.VISIBLE);
headerImageArrow.startAnimation(headerArrowAnim);
headerText.setText("ReleaseToRefresh");
break;
caseSTATE_REFRESHING:
headerProgressBar.setVisibility(View.VISIBLE);
headerImageArrow.setVisibility(View.INVISIBLE);
headerImageArrow.clearAnimation();
headerText.setText("Refreshing");
break;
default:
break;
}
}

(intstate){
if(this.state==state){
return;
}
this.state=state;

switch(state){
caseSTATE_NON:
footerProgressBar.setVisibility(View.INVISIBLE);
footerText.setText("PullUpToRefresh");
break;
caseSTATE_PULL_TO_REFRESH:
footerProgressBar.setVisibility(View.INVISIBLE);
footerText.setText("PullUpToRefresh");
break;
caseSTATE_RELEASE_TO_REFRESH:
footerProgressBar.setVisibility(View.INVISIBLE);
footerText.setText("ReleaseToRefresh");
break;
caseSTATE_REFRESHING:
footerProgressBar.setVisibility(View.VISIBLE);
footerText.setText("Refreshing");
break;
default:
break;
}
}

@Override
publicvoidsetOnScrollListener(OnScrollListenerl){
this.onScrollListener=l;
}

(){
this.onLoadingListener=onLoadingListener;
}

publicvoidloadCompleted(){
if(headerIsHanding){
changeHeaderViewByState(STATE_NON);
resetHeader();
headerIsHanding=false;
}
if(footerIsHanding){
changeFooterViewByState(STATE_NON);
resetFooter();
footerIsHanding=false;
}
}

(MotionEventev){
headerIsHanding=true;
floattempY=ev.getRawY();
floatvector=tempY-prevY;
vector/=2;
prevY=tempY;
if(vector>0){
intnewPadding=(int)(headerView.getPaddingTop()+vector);
newPadding=Math.min(newPadding,headerHeight/2);
headerView.setPadding(0,newPadding,0,0);
if(state!=STATE_REFRESHING){
if(newPadding>0){
changeHeaderViewByState(STATE_RELEASE_TO_REFRESH);
}else{
changeHeaderViewByState(STATE_PULL_TO_REFRESH);
}
}
}else{
if(state==STATE_RELEASE_TO_REFRESH||state==STATE_PULL_TO_REFRESH){
intnewPadding=(int)(headerView.getPaddingTop()+vector);
newPadding=Math.max(newPadding,-1*headerHeight);
headerView.setPadding(0,newPadding,0,0);
if(newPadding<=-1*headerHeight){
changeHeaderViewByState(STATE_NON);
headerIsHanding=false;
}elseif(newPadding<=0){
changeHeaderViewByState(STATE_PULL_TO_REFRESH);
}else{

}
}
}
}

(MotionEventev){
footerIsHanding=true;
floattempY=ev.getRawY();
floatvector=tempY-prevY;
vector/=2;
prevY=tempY;
if(vector<0){
intnewPadding=(int)(footerView.getPaddingTop()-vector);
if(newPadding>0){
newPadding=0;
}
footerView.setPadding(0,newPadding,0,0);
if(state!=STATE_REFRESHING){
if(newPadding<0){
changeFooterViewByState(STATE_PULL_TO_REFRESH);
}else{
changeFooterViewByState(STATE_RELEASE_TO_REFRESH);
}
}
}else{
intnewPadding=(int)(footerView.getPaddingTop()-vector);
newPadding=Math.min(newPadding,footerHeight);
footerView.setPadding(0,newPadding,0,0);
if(newPadding<=-1*footerHeight){
changeFooterViewByState(STATE_NON);
footerIsHanding=false;
}elseif(newPadding<0){
changeFooterViewByState(STATE_PULL_TO_REFRESH);
}
}
}

『叄』 android中listview的下拉刷新上拉載入是怎麼實現的

這是兩個分開的部分。如果你是新手,先一個一個來。

我只能跟你說一下思路,具體的東西你在網上查查,不行再問我,新手的話慢慢來。

  1. 下拉刷新,獲取listview的下拉時間顯示header,然後調用更新數據的介面就可以了。

  2. 上啦載入,是分頁獲取數據,獲取listview的是否拉到最底,如果拉倒最底,獲取數據,讓後list的數據添加獲取的數據,更新adapter就可以了。


『肆』 Android 怎麼實現支持所有View的通用的下拉刷新控制項

下拉刷新對於一個app來說是必不可少的一個功能,在早期大多數使用的是chrisbanes的PullToRefresh,或是修改自該框架的其他庫。而到現在已經有了更多的選擇,github上還是有很多體驗不錯的下拉刷新。
而下拉刷新主要有兩種實現方式:
1. 在ListView中添加header和footer,監聽ListView的滑動事件,動態設置header/footer的高度,但是這種方式只適用於ListView,RecyclerView。
2. 第二種方式則是繼承ViewGroup或其子類,監聽事件,通過scroll或Layout的方式移動child。如圖(又分兩種情況)

Layout時將header放到屏幕外面,target則填充滿屏幕。這個也是SwipeRefreshLayout的實現原理(第二種,只下拉header)

這兩種(指的是繼承ListView或繼承ViewGroup)下拉刷新的實現方式主要有以下區別

繼承ListView/RecyclerView

繼承ViewGroup或其子類

適用范圍
ListView/Recycler
理論支持所有View和ViewGroup

載入更多
實現簡單,體驗好
可以實現,看需求了,做不出ListView那種載入效果的,體驗比較一般

多點觸控
可以完美支持
header下拉狀態中是完美支持的,但是回去之後,很難將多點觸控事件傳遞給child

案例
QQ好友列表
美團、京東等

而今天,我打算先講第二種方式實現方式,繼承ViewGroup,代碼可以直接參考SwipeRefreshLayout,或者pullToRefresh,或者ultra-pull-to-refresh

一、思考和需求

下拉刷新需要幾個狀態:Reset–> Pull – > Refreshing – >Completed –>Reset

為了應對各式各樣的下拉刷新設計,我們應該提供設置自定義的Header,開發者可以通過實現介面從而自定義自己的header。

而且header可以有兩種顯示方式,一種是只下拉header,另外一種則是header和target一起下拉。

二、著手實現代碼

2.1 定義Header的介面,創建自定義Layout

<code class="hljs java">/**
* Created by AItsuki on 2016/6/13.
*
*/
public enum State {
RESET, PULL, LOADING, COMPLETE
}</code>

<code class="hljs java">/**
* Created by AItsuki on 2016/6/13.
*
*/
public interface RefreshHeader {

/**
* 鬆手,頭部隱藏後會回調這個方法
*/
void reset();

/**
* 下拉出頭部的一瞬間調用
*/
void pull();

/**
* 正在刷新的時候調用
*/
void refreshing();

/**
* 頭部滾動的時候持續調用
* @param currentPos target當前偏移高度
* @param lastPos target上一次的偏移高度
* @param refreshPos 可以鬆手刷新的高度
* @param isTouch 手指是否按下狀態(通過scroll自動滾動時需要判斷)
* @param state 當前狀態
*/
void onPositionChange(float currentPos, float lastPos, float refreshPos, boolean isTouch, State state);

/**
* 刷新成功的時候調用
*/
void complete();
}</code>
package com.aitsuki.custompulltorefresh;

import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.ImageView;

/**
* Created by AItsuki on 2016/6/13.
* -
*/
public class RefreshLayout extends ViewGroup {

private View refreshHeader;
private View target;
private int currentTargetOffsetTop; // target偏移距離
private boolean hasMeasureHeader; // 是否已經計算頭部高度
private int touchSlop;
private int headerHeight; // header高度
private int totalDragDistance; // 需要下拉這個距離才進入鬆手刷新狀態,默認和header高度一致

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

public RefreshLayout(Context context, AttributeSet attrs) {
super(context, attrs);

touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();

// 添加默認的頭部,先簡單的用一個ImageView代替頭部
ImageView imageView = new ImageView(context);
imageView.setImageResource(R.drawable.one_piece);
imageView.setBackgroundColor(Color.BLACK);
setRefreshHeader(imageView);
}

/**
* 設置自定義header
*/
public void setRefreshHeader(View view) {
if (view != null && view != refreshHeader) {
removeView(refreshHeader);

// 為header添加默認的layoutParams
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
if (layoutParams == null) {
layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
view.setLayoutParams(layoutParams);
}
refreshHeader = view;
addView(refreshHeader);
}
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (target == null) {
ensureTarget();
}

if (target == null) {
return;
}

// ----- measure target -----
// target占滿整屏
target.measure(MeasureSpec.makeMeasureSpec(
getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY));

// ----- measure refreshView-----
measureChild(refreshHeader, widthMeasureSpec, heightMeasureSpec);
if (!hasMeasureHeader) { // 防止header重復測量
hasMeasureHeader = true;
headerHeight = refreshHeader.getMeasuredHeight(); // header高度
totalDragDistance = headerHeight; // 需要pull這個距離才進入鬆手刷新狀態
}
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int width = getMeasuredWidth();
final int height = getMeasuredHeight();
if (getChildCount() == 0) {
return;
}

if (target == null) {
ensureTarget();
}
if (target == null) {
return;
}

// onLayout執行的時候,要讓target和header加上偏移距離(初始0),因為有可能在滾動它們的時候,child請求重新布局,從而導致target和header瞬間回到原位。

// target鋪滿屏幕
final View child = target;
final int childLeft = getPaddingLeft();
final int childTop = getPaddingTop() + currentTargetOffsetTop;
final int childWidth = width - getPaddingLeft() - getPaddingRight();
final int childHeight = height - getPaddingTop() - getPaddingBottom();
child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);

// header放到target的上方,水平居中
int refreshViewWidth = refreshHeader.getMeasuredWidth();
refreshHeader.layout((width / 2 - refreshViewWidth / 2),
-headerHeight + currentTargetOffsetTop,
(width / 2 + refreshViewWidth / 2),
currentTargetOffsetTop);
}

/**
* 將第一個Child作為target
*/
private void ensureTarget() {
// Don't bother getting the parent height if the parent hasn't been laid
// out yet.
if (target == null) {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (!child.equals(refreshHeader)) {
target = child;
break;
}
}
}
}
}</code>

『伍』 android上拉刷新下拉載入 通用框架怎麼用

1. 關於下拉刷新

下拉刷新這種用戶交互最早由twitter創始人洛倫•布里切特(Loren Brichter)發明,有理論認為,下拉刷新是一種適用於按照從新到舊的時間順序排列feeds的應用,在這種應用場景中看完舊的內容時,用戶會很自然地下拉查找更新的內容,因此下拉刷新就顯得非常合理。大家可以參考這篇文章:有趣的下拉刷新,下面我貼出一個有趣的下拉刷新的案例。

2. 實現原理

上面這些例子,外觀做得再好看,他的本質上都一樣,那就是一個下拉刷新控制項通常由以下幾部分組成:

【1】Header

Header通常有下拉箭頭,文字,進度條等元素,根據下拉的距離來改變它的狀態,從而顯示不同的樣式

【2】Content

這部分是內容區域,網上有很多例子都是直接在ListView裡面添加Header,但這就有局限性,因為好多情況下並不一定是用ListView來顯示數據。我們把要顯示內容的View放置在我們的一個容器中,如果你想實現一個用ListView顯示數據的下拉刷新,你需要創建一個ListView旋轉到我的容器中。我們處理這個容器的事件(down, move, up),如果向下拉,則把整個布局向下滑動,從而把header顯示出來。

【3】Footer

Footer可以用來顯示向上拉的箭頭,自動載入更多的進度條等。

『陸』 如何實現下拉刷新上ListFragment-java,安卓android,android

實現ListFragment的下拉刷新功能,關鍵在於監聽ListView的滾動狀態。具體代碼如下:

首先,在ListView中添加滾動監聽器:lv.setOnScrollListener(new OnScrollListener() {

在onScrollStateChanged方法中,通過判斷ListView的最後一個可見項是否為集合中的最後一個元素,來決定是否需要載入更多數據。具體的代碼如下:

if (listview.getLastVisiblePosition() == list.size() - 1) {

這里表示,當ListView的最後一個可見項與集合中的最後一個元素相同,說明當前已經載入到了列表的底部,這時可以請求網路數據,並將獲取到的數據添加到集合中。

list.addAll(...);

接下來,調用適配器的notifyDataSetChanged方法來刷新列表的顯示。

adapter.notifyDataSetChanged();

在onScroll方法中,可以獲取到當前可見的第一項、可見項的數量以及總項數。這些信息可以用於優化滾動性能,但通常情況下不需要在這里進行處理。

最後,通過這樣的監聽機制,可以實現下拉載入更多功能,使應用更加流暢和用戶友好。

值得注意的是,為了確保數據載入的正確性,通常需要在請求網路數據之後進行適配器的更新。這樣可以保證列表數據的及時更新。

此外,還可以根據實際情況對代碼進行優化,比如使用非同步任務或線程池來處理網路請求,避免阻塞主線程。

通過這種方式,可以輕松實現ListFragment的下拉刷新功能,為用戶提供更好的體驗。

熱點內容
伺服器private什麼意思 發布:2025-08-12 02:28:20 瀏覽:825
大氣公司網站源碼 發布:2025-08-12 02:27:34 瀏覽:621
plsql運行存儲過程 發布:2025-08-12 02:26:47 瀏覽:528
oracle存儲過程日期參數 發布:2025-08-12 02:26:44 瀏覽:802
怎麼解外密碼 發布:2025-08-12 02:09:48 瀏覽:842
安卓在哪裡下載收獲日 發布:2025-08-12 02:08:26 瀏覽:860
plsql設置中文 發布:2025-08-12 02:08:21 瀏覽:567
樹結構用什麼存儲結構 發布:2025-08-12 01:58:06 瀏覽:923
midi腳本 發布:2025-08-12 01:45:57 瀏覽:33
python中的isinstance 發布:2025-08-12 00:54:21 瀏覽:658