Android 源代码实例:实现上拉加载下拉刷新浮动效果

时间:2022-12-21 03:46:53 作者:聪明小狗 综合材料 收藏本文 下载本文

“聪明小狗”通过精心收集,向本站投稿了10篇Android 源代码实例:实现上拉加载下拉刷新浮动效果,以下是小编为大家准备的Android 源代码实例:实现上拉加载下拉刷新浮动效果,仅供参考,欢迎大家阅读。

篇1:Android 源代码实例:实现上拉加载下拉刷新浮动效果

下拉刷新这种用户交互最早由twitter创始人洛伦布里切特(Loren Brichter)发明,有理论认为,下拉刷新是一种适用于按照从新到旧的时间顺序排列feeds的应用,在这种应用场景中看完旧的内容时,用户会很自然地下拉查找更新的内容,因此下拉刷新就显得非常合理,大家可以参考这篇文章:有趣的下拉刷新,下面我贴出一个有趣的下拉刷新的案例。

图一、有趣的下拉刷新案例(一)

图一、有趣的下拉刷新案例(二)

篇2:Android 源代码实例:实现上拉加载下拉刷新浮动效果

上面这些例子,外观做得再好看,他的本质上都一样,那就是一个下拉刷新控件通常由以下几部分组成:

【1】Header

Header通常有下拉箭头,文字,进度条等元素,根据下拉的距离来改变它的状态,从而显示不同的样式

【2】Content

这部分是内容区域,网上有很多例子都是直接在ListView里面添加Header,但这就有局限性,因为好多情况下并不一定是用ListView来显示数据。我们把要显示内容的View放置在我们的一个容器中,如果你想实现一个用ListView显示数据的下拉刷新,你需要创建一个ListView旋转到我的容器中。我们处理这个容器的事件(down, move, up),如果向下拉,则把整个布局向下滑动,从而把header显示出来。

【3】Footer

Footer可以用来显示向上拉的箭头,自动加载更多的进度条等。

以上三部分总结的说来,就是如下图所示的这种布局结构:

图三,下拉刷新的布局结构

关于上图,需要说明几点:

1、这个布局扩展于LinearLayout,垂直排列

2、从上到下的顺序是:Header, Content, Footer

3、Content填充满父控件,通过设置top, bottom的padding来使Header和Footer不可见,也就是让它超出屏幕外

4、下拉时,调用scrollTo方法来将整个布局向下滑动,从而把Header显示出来,上拉正好与下拉相反。

5、派生类需要实现的是:将Content View填充到父容器中,比如,如果你要使用的话,那么你需要把ListView, ScrollView, WebView等添加到容器中。

6、上图中的红色区域就是屏的大小(严格来说,这里说屏幕大小并不准确,应该说成内容区域更加准确)

篇3:Android 源代码实例:实现上拉加载下拉刷新浮动效果

明白了实现原理与过程,我们尝试来具体实现,首先,为了以后更好地扩展,设计更加合理,我们把下拉刷新的功能抽象成一个接口:

1、IPullToRefresh

它具体的定义方法如下:

[java]view plaincopy

public interface IPullToRefresh {  

public void setPullRefreshEnabled(boolean pullRefreshEnabled);

public void setPullLoadEnabled(boolean pullLoadEnabled);

public void setScrollLoadEnabled(boolean scrollLoadEnabled);

public boolean isPullRefreshEnabled;

public boolean isPullLoadEnabled();

public boolean isScrollLoadEnabled();

public void setOnRefreshListener(OnRefreshListener refreshListener);  

public void onPullDownRefreshComplete();

public void onPullUpRefreshComplete();

public T getRefreshableView();

public LoadingLayout getHeaderLoadingLayout();

public LoadingLayout getFooterLoadingLayout();

public void setLastUpdatedLabel(CharSequence label);

}

这个接口是一个泛型的,它接受View的派生类,因为要放到我们的容器中的不就是一个View吗?

2、PullToRefreshBase

这个类实现了IPullToRefresh接口,它是从LinearLayout继承过来,作为下拉刷新的一个抽象基类,如果你想实现ListView的下拉刷新,只需要扩展这个类,实现一些必要的方法就可以了。这个类的职责主要有以下几点:

处理onInterceptTouchEvent()和onTouchEvent()中的事件:当内容的View(比如ListView)正如处于最顶部,此时再向下拉,我们必须截断事件,然后move事件就会把后续的事件传递到onTouchEvent()方法中,然后再在这个方法中,我们根据move的距离再进行scroll整个View。

负责创建Header、Footer和Content View:在构造方法中调用方法去创建这三个部分的View,派生类可以重写这些方法,以提供不同式样的Header和Footer,它会调用createHeaderLoadingLayout和createFooterLoadingLayout方法来创建Header和Footer创建Content View的方法是一个抽象方法,必须让派生类来实现,返回一个非null的View,然后容器再把这个View添加到自己里面。

设置各种状态:这里面有很多状态,如下拉、上拉、刷新、加载中、释放等,它会根据用户拉动的距离来更改状态,状态的改变,它也会把Header和Footer的状态改变,然后Header和Footer会根据状态去显示相应的界面式样。

3、PullToRefreshBase继承关系

这里我实现了三个下拉刷新的派生类,分别是ListView、ScrollView、WebView三个,它们的继承关系如下:

图四、PullToRefreshBase类的继承关系

关于PullToRefreshBase类及其派和类,有几点需要说明:

对于ListView,ScrollView,WebView这三种情况,他们是否滑动到最顶部或是最底部的实现是不一样的,所以,在PullToRefreshBase类中需要调用两个抽象方法来判断当前的位置是否在顶部或底部,而其派生类必须要实现这两个方法。比如对于ListView,它滑动到最顶部的条件就是第一个child完全可见并且first postion是0。这两个抽象方法是:

[java]view plaincopy

/**

* 判断刷新的View是否滑动到顶部

*

* @return true表示已经滑动到顶部,否则false

*/

protected abstract boolean isReadyForPullDown();

/**

* 判断刷新的View是否滑动到底

*

* @return true表示已经滑动到底部,否则false

*/

protected abstract boolean isReadyForPullUp();

创建可下拉刷新的View(也就是content view)的抽象方法是

[java]view plaincopy

/**

* 创建可以刷新的View

*

* @param context context

* @param attrs 属性

* @return View

*/

protected abstract T createRefreshableView(Context context, AttributeSet attrs);

4、LoadingLayout

LoadingLayout是刷新Layout的一个抽象,它是一个抽象基类。Header和Footer都扩展于这个类。这类抽象类,提供了两个抽象方法:

getContentSize

这个方法返回当前这个刷新Layout的大小,通常返回的是布局的高度,为了以后可以扩展为水平拉动,所以方法名字没有取成getLayoutHeight()之类的,这个返回值,将会作为松手后是否可以刷新的临界值,如果下拉的偏移值大于这个值,就认为可以刷新,否则不刷新,这个方法必须由派生类来实现。

setState

这个方法用来设置当前刷新Layout的状态,PullToRefreshBase类会调用这个方法,当进入下拉,松手等动作时,都会调用这个方法,派生类里面只需要根据这些状态实现不同的界面显示,如下拉状态时,就显示出箭头,刷新状态时,就显示loading的图标。

可能的状态值有:RESET, PULL_TO_REFRESH, RELEASE_TO_REFRESH, REFRESHING, NO_MORE_DATA

LoadingLayout及其派生类的继承关系如下图所示:

图五、LoadingLayout及其派生类的类图

我们可以随意地制定自己的Header和Footer,我们也可以实现如图一和图二中显示的各种下拉刷新案例中的Header和Footer,只要重写上述两个方法getContentSize()和setState()就行了。HeaderLoadingLayout,它默认是显示箭头式样的布局,而RotateLoadingLayout则是显示一个旋转图标的式样。

5、事件处理

我们必须重写PullToRefreshBase类的两个事件相关的方法onInterceptTouchEvent()和onTouchEvent()方法。由于ListView,ScrollView,WebView它们是放到PullToRefreshBase内部的,所在事件先是传递到PullToRefreshBase#onInterceptTouchEvent()方法中,所以我们应该在这个方法中去处理ACTION_MOVE事件,判断如果当前ListView,ScrollView,WebView是否在最顶部或最底部,如果是,则开始截断事件,一旦事件被截断,后续的事件就会传递到PullToRefreshBase#onInterceptTouchEvent()方法中,我们再在ACTION_MOVE事件中去移动整个布局,从而实现下拉或上拉动作。

6、滚动布局(scrollTo)

如图三的布局结构可知,默认情况下Header和Footer是放置在Content View的最上面和最下面,通过设置padding来让他跑到屏幕外面去了,如果我们将整个布局向下滚动(scrollTo)一定距离,那么Header就会被显示出来,基于这种情况,所以在我的实现中,最终我是调用scrollTo来实现下拉动作的。

总的说来,实现的重要的点就这些,具体的一些细节在实现在会碰到很多,可以参考代码。

篇4:Android 源代码实例:实现上拉加载下拉刷新浮动效果

使用下拉刷新的代码如下

[java]view plaincopy

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

mPullListView = new PullToRefreshListView(this);

setContentView(mPullListView);

// 上拉加载不可用

mPullListView.setPullLoadEnabled(false);

// 滚动到底自动加载可用

mPullListView.setScrollLoadEnabled(true);

mCurIndex = mLoadDataCount;

mListItems = new LinkedList();  

mListItems.addAll(Arrays.asList(mStrings).subList(0, mCurIndex));

mAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, mListItems);  

// 得到实际的ListView

mListView = mPullListView.getRefreshableView();

// 绑定数据

mListView.setAdapter(mAdapter);

// 设置下拉刷新的listener

mPullListView.setOnRefreshListener(new OnRefreshListener() {  

@Override

public void onPullDownToRefresh(PullToRefreshBase refreshView) {  

mIsStart = true;

new GetDataTask().execute();

}

@Override

public void onPullUpToRefresh(PullToRefreshBase refreshView) {  

mIsStart = false;

new GetDataTask().execute();

}

});

setLastUpdateTime();

// 自动刷新

mPullListView.doPullRefreshing(true, 500);

}

这是初始化一个下拉刷新的布局,并且调用setContentView来设置到Activity中。

在下拉刷新完成后,我们可以调用onPullDownRefreshComplete()和onPullUpRefreshComplete()方法来停止刷新和加载

篇5:Android 源代码实例:实现上拉加载下拉刷新浮动效果

实现这个下拉刷新的框架,并不是我的原创,我也是参考了很多开源的,把我认为比较好的东西借鉴过来,从而形成我的东西,我主要是参考了下面这个demo:

github.com/chrisbanes/Android-PullToRefresh 这个demo写得不错,不过他这个太复杂了,我们都知道,一旦复杂了,万一我们要添加一些需要,自然也要费劲一些,我其实就是把他的简化再简化,以满足我们自己的需要,

源码下载请猛点我

转载请说明出处

blog.csdn.net/leehong2005/article/details/12567757

谢谢!!!

篇6:Android 源代码实例:实现上拉加载下拉刷新浮动效果

已知bug修复情况如下,发现了代码bug的看官也可以给我反馈,谢谢~~~

1,对于ListView的下拉刷新,当启用滚动到底自动加载时,如果footer由隐藏变为显示时,出现显示异常的情况

这个问题已经修复了,修正的代码如下:

PullToRefreshListView#setScrollLoadEnabled方法,修正后的代码如下:

[java]view plaincopy

@Override

public void setScrollLoadEnabled(boolean scrollLoadEnabled) {

if (isScrollLoadEnabled == scrollLoadEnabled) {

return;

}

super.setScrollLoadEnabled(scrollLoadEnabled);

if (scrollLoadEnabled) {

// 设置Footer

if (null == mLoadMoreFooterLayout) {

mLoadMoreFooterLayout = new FooterLoadingLayout(getContext());

mListView.addFooterView(mLoadMoreFooterLayout, null, false);

}

mLoadMoreFooterLayout.show(true);

} else {

if (null != mLoadMoreFooterLayout) {

mLoadMoreFooterLayout.show(false);

}

}

}

LoadingLayout#show方法,修正后的代码如下:

[java]view plaincopy

/**

* 显示或隐藏这个布局

*

* @param show flag

*/

public void show(boolean show) {

// If is showing, do nothing.

if (show == (View.VISIBLE == getVisibility())) {

return;

}

ViewGroup.LayoutParams params = mContainer.getLayoutParams();

if (null != params) {

if (show) {

params.height = ViewGroup.LayoutParams.WRAP_CONTENT;

} else {

params.height = 0;

}

requestLayout();

setVisibility(show ? View.VISIBLE : View.INVISIBLE);

}

}

在更改LayoutParameter后,调用requestLayout()方法。

图片旋转兼容2.x系统

我之前想的是这个只需要兼容3.x以上的系统,但发现有很多网友在使用过程中遇到过兼容性问题,这次抽空将这个兼容性一并实现了。

onPull的修改如下:

[java]view plaincopy

@Override

public void onPull(float scale) {

if (null == mRotationHelper) {

mRotationHelper = new ImageViewRotationHelper(mArrowImageView);

}

float angle = scale * 180f; // SUPPRESS CHECKSTYLE

mRotationHelper.setRotation(angle);

}

ImageViewRotationHelper主要的作用就是实现了ImageView的旋转功能,内部作了版本的区分,实现代码如下:

[java]view plaincopy

/**

* The image view rotation helper

*

* @author lihong06

* @since 2014-5-2

*/

static class ImageViewRotationHelper {

/** The imageview */

private final ImageView mImageView;

/** The matrix */

private Matrix mMatrix;

/** Pivot X */

private float mRotationPivotX;

/** Pivot Y */

private float mRotationPivotY;

/**

* The constructor method.

*

* @param imageView the image view

*/

public ImageViewRotationHelper(ImageView imageView) {

mImageView = imageView;

}

/**

* Sets the degrees that the view is rotated around the pivot point. Increasing values

* result in clockwise rotation.

*

* @param rotation The degrees of rotation.

*

* @see #getRotation()

* @see #getPivotX()

* @see #getPivotY()

* @see #setRotationX(float)

* @see #setRotationY(float)

*

* @attr ref android.R.styleable#View_rotation

*/

public void setRotation(float rotation) {

if (APIUtils.hasHoneycomb()) {

mImageView.setRotation(rotation);

} else {

if (null == mMatrix) {

mMatrix = new Matrix();

// 计算旋转的中心点

Drawable imageDrawable = mImageView.getDrawable();

if (null != imageDrawable) {

mRotationPivotX = Math.round(imageDrawable.getIntrinsicWidth() / 2f);

mRotationPivotY = Math.round(imageDrawable.getIntrinsicHeight() / 2f);

}

}

mMatrix.setRotate(rotation, mRotationPivotX, mRotationPivotY);

mImageView.setImageMatrix(mMatrix);

}

}

}

最核心的就是,如果在2.x的版本上,旋转ImageView使用Matrix。

PullToRefreshBase构造方法兼容2.x

在三个参数的构造方法声明如下标注:

@SuppressLint(“NewApi”)

@TargetApi(Build.VERSION_CODES.HONEYCOMB)

篇7:Android 源代码实例:实现上拉加载下拉刷新浮动效果

这里列出了demo的运行效果图。

图六、ListView下拉刷新,注意Header和Footer的样式

图七、WebView和ScrollView的下拉刷新效果图

篇8:Android下拉刷新上拉加载控件,对所有View通用!

前面写过一篇关于下拉刷新控件的博客下拉刷新控件终结者:PullToRefreshLayout,后来看到好多人还有上拉加载更多的需求,于是就在前面下拉刷新控件的基础上进行了改进,加了上拉加载的功能,不仅如此,我已经把它改成了对所有View都通用!可以随心所欲使用这两个功能~~

我做了一个大集合的demo,实现了ListView、GridView、ExpandableListView、ScrollView、WebView、ImageView、TextView的下拉刷新和上拉加载。后面会提供demo的下载地址。

依照惯例,下面将会是一大波效果图:

demo首页也是可下拉的ListView,在底下可以加入table:

ListView:

GridView:

ExpandableListView:

ScrollView:

WebView:

ImageView:

TextView:

很不错吧?最后的ImageView和TextView是最简单的,直接在下面的接口方法里返回true。

增加上拉加载很简单,和管理下拉头一样,再多管理一个上拉头,也不费事;至于把它改成通用的就需要统一一下View的行为了,为此,我定义了这样一个接口:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

package com.jingchen.pulltorefresh.pullableview;

public interface Pullable

{

/**

* 判断是否可以下拉,如果不需要下拉功能可以直接return false

*

* @return true如果可以下拉否则返回false

*/

boolean canPullDown;

/**

* 判断是否可以上拉,如果不需要上拉功能可以直接return false

*

* @return true如果可以上拉否则返回false

*/

boolean canPullUp();

}

从接口名就可以看出它是一个提供判断是否可拉的方法的接口。这个接口的两个方法,canPullDown()是判断何时可以下拉的方法,canPullUp()则是判断何时可以上拉,我在demo中的判断是滑到顶部的时候可以下拉,滑到底部的时候可以上拉。所有需要上拉和下拉的View都需要实现这个接口。后面会给出一些View的实现。先来看看改进后的自定义的布局PullToRefreshLayout,增加了一个上拉头,下拉头和上拉头之间的View是实现了Pullable接口的pullableView。相比前面的版本,这里有改动的需要注意的地方如下:

1、增加了上拉头,相应的也增加了控制变量。

2、拉动时消除content_view事件防止误触发不再使用反射,直接设置 event.setAction(MotionEvent.ACTION_CANCEL)。

3、消除了拉动过程中的多点触碰导致的剧变。

4、不再设置content_view的onTouListener,让使用者可以更加自由的设置 。

这个PullToRefreshLayout只负责管理三个控件,如果一个View需要有上拉下拉功能则只需实现接口就行了。下面看PullToRefreshLayout的代码,注释写了好多:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

400

401

402

403

404

405

406

407

408

409

410

411

412

413

414

415

416

417

418

419

420

421

422

423

424

425

426

427

428

429

430

431

432

433

434

435

436

437

438

439

440

441

442

443

444

445

446

447

448

449

450

451

452

453

454

455

456

457

458

459

460

461

462

463

464

465

466

467

468

469

470

471

472

473

474

475

476

477

478

479

480

481

482

483

484

485

486

487

488

489

490

491

492

493

494

495

496

497

498

499

500

501

502

503

504

505

506

507

508

509

510

511

512

513

514

515

516

517

518

519

520

521

522

523

524

525

526

527

528

529

530

531

532

533

534

535

536

537

538

539

540

541

542

543

544

545

546

547

548

549

550

551

552

553

554

555

556

557

558

559

560

561

562

563

564

565

566

567

568

569

570

571

572

573

574

575

576

577

578

579

580

581

582

583

584

585

586

587

588

package com.jingchen.pulltorefresh;

import java.util.Timer;

import java.util.TimerTask;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.LinearGradient;

import android.graphics.Paint;

import android.graphics.Paint.Style;

import android.graphics.RectF;

import android.graphics.Shader.TileMode;

import android.os.Handler;

import android.os.Message;

import android.util.AttributeSet;

import android.util.Log;

import android.view.MotionEvent;

import android.view.View;

import android.view.ViewGroup;

import android.view.animation.AnimationUtils;

import android.view.animation.LinearInterpolator;

import android.view.animation.RotateAnimation;

import android.widget.RelativeLayout;

import android.widget.TextView;

import com.jingchen.pulltorefresh.pullableview.Pullable;

/**

* 自定义的布局,用来管理三个子控件,其中一个是下拉头,一个是包含内容的pullableView(可以是实现Pullable接口的的任何View),

* 还有一个上拉头

*

* @author 陈靖

*/

public class PullToRefreshLayout extends RelativeLayout

{

public static final String TAG = PullToRefreshLayout;

// 初始状态

public static final int INIT = 0;

// 释放刷新

public static final int RELEASE_TO_REFRESH = 1;

// 正在刷新

public static final int REFRESHING = 2;

// 释放加载

public static final int RELEASE_TO_LOAD = 3;

// 正在加载

public static final int LOADING = 4;

// 操作完毕

public static final int DONE = 5;

// 当前状态

private int state = INIT;

// 刷新回调接口

private OnRefreshListener mListener;

// 刷新成功

public static final int SUCCEED = 0;

// 刷新失败

public static final int FAIL = 1;

// 按下Y坐标,上一个事件点Y坐标

private float downY, lastY;

// 下拉的距离。注意:pullDownY和pullUpY不可能同时不为0

public float pullDownY = 0;

// 上拉的距离

private float pullUpY = 0;

// 释放刷新的距离

private float refreshDist = 200;

// 释放加载的距离

private float loadmoreDist = 200;

private MyTimer timer;

// 回滚速度

public float MOVE_SPEED = 8;

// 第一次执行布局

private boolean isLayout = false;

// 在刷新过程中滑动操作

private boolean isTouch = false;

// 手指滑动距离与下拉头的滑动距离比,中间会随正切函数变化

private float radio = 2;

// 下拉箭头的转180°动画

private RotateAnimation rotateAnimation;

// 均匀旋转动画

private RotateAnimation refreshingAnimation;

// 下拉头

private View refreshView;

// 下拉的箭头

private View pullView;

// 正在刷新的图标

private View refreshingView;

// 刷新结果图标

private View refreshStateImageView;

// 刷新结果:成功或失败

private TextView refreshStateTextView;

// 上拉头

private View loadmoreView;

// 上拉的箭头

private View pullUpView;

// 正在加载的图标

private View loadingView;

// 加载结果图标

private View loadStateImageView;

// 加载结果:成功或失败

private TextView loadStateTextView;

// 实现了Pullable接口的View

private View pullableView;

// 过滤多点触碰

private int mEvents;

// 这两个变量用来控制pull的方向,如果不加控制,当情况满足可上拉又可下拉时没法下拉

private boolean canPullDown = true;

private boolean canPullUp = true;

/**

* 执行自动回滚的handler

*/

Handler updateHandler = new Handler()

{

@Override

public void handleMessage(Message msg)

{

// 回弹速度随下拉距离moveDeltaY增大而增大

MOVE_SPEED = (float) (8 + 5 * Math.tan(Math.PI / 2

/ getMeasuredHeight() * (pullDownY + Math.abs(pullUpY))));

if (!isTouch)

{

// 正在刷新,且没有往上推的话则悬停,显示正在刷新...

if (state == REFRESHING && pullDownY <= refreshDist)

{

pullDownY = refreshDist;

timer.cancel();

} else if (state == LOADING && -pullUpY <= loadmoreDist)

{

pullUpY = -loadmoreDist;

timer.cancel();

}

}

if (pullDownY >0)

pullDownY -= MOVE_SPEED;

else if (pullUpY < 0)

pullUpY += MOVE_SPEED;

if (pullDownY < 0)

{

// 已完成回弹

pullDownY = 0;

pullView.clearAnimation();

// 隐藏下拉头时有可能还在刷新,只有当前状态不是正在刷新时才改变状态

if (state != REFRESHING && state != LOADING)

changeState(INIT);

timer.cancel();

}

if (pullUpY >0)

{

// 已完成回弹

pullUpY = 0;

pullUpView.clearAnimation();

// 隐藏下拉头时有可能还在刷新,只有当前状态不是正在刷新时才改变状态

if (state != REFRESHING && state != LOADING)

changeState(INIT);

timer.cancel();

}

// 刷新布局,会自动调用onLayout

requestLayout();

}

};

public void setOnRefreshListener(OnRefreshListener listener)

{

mListener = listener;

}

public PullToRefreshLayout(Context context)

{

super(context);

initView(context);

}

public PullToRefreshLayout(Context context, AttributeSet attrs)

{

super(context, attrs);

initView(context);

}

public PullToRefreshLayout(Context context, AttributeSet attrs, int defStyle)

{

super(context, attrs, defStyle);

initView(context);

}

private void initView(Context context)

{

timer = new MyTimer(updateHandler);

rotateAnimation = (RotateAnimation) AnimationUtils.loadAnimation(

context, R.anim.reverse_anim);

refreshingAnimation = (RotateAnimation) AnimationUtils.loadAnimation(

context, R.anim.rotating);

// 添加匀速转动动画

LinearInterpolator lir = new LinearInterpolator();

rotateAnimation.setInterpolator(lir);

refreshingAnimation.setInterpolator(lir);

}

private void hide()

{

timer.schedule(5);

}

/**

* 完成刷新操作,显示刷新结果,

注意:刷新完成后一定要调用这个方法

*/

/**

* @param refreshResult

*           PullToRefreshLayout.SUCCEED代表成功,PullToRefreshLayout.FAIL代表失败

*/

public void refreshFinish(int refreshResult)

{

refreshingView.clearAnimation();

refreshingView.setVisibility(View.GONE);

switch (refreshResult)

{

case SUCCEED:

// 刷新成功

refreshStateImageView.setVisibility(View.VISIBLE);

refreshStateTextView.setText(R.string.refresh_succeed);

refreshStateImageView

.setBackgroundResource(R.drawable.refresh_succeed);

break;

case FAIL:

default:

// 刷新失败

refreshStateImageView.setVisibility(View.VISIBLE);

refreshStateTextView.setText(R.string.refresh_fail);

refreshStateImageView

.setBackgroundResource(R.drawable.refresh_failed);

break;

}

// 刷新结果停留1秒

new Handler()

{

@Override

public void handleMessage(Message msg)

{

changeState(DONE);

hide();

}

}.sendEmptyMessageDelayed(0, 1000);

}

/**

* 加载完毕,显示加载结果。注意:加载完成后一定要调用这个方法

*

* @param refreshResult

*           PullToRefreshLayout.SUCCEED代表成功,PullToRefreshLayout.FAIL代表失败

*/

public void loadmoreFinish(int refreshResult)

{

loadingView.clearAnimation();

loadingView.setVisibility(View.GONE);

switch (refreshResult)

{

case SUCCEED:

// 加载成功

loadStateImageView.setVisibility(View.VISIBLE);

loadStateTextView.setText(R.string.load_succeed);

loadStateImageView.setBackgroundResource(R.drawable.load_succeed);

break;

case FAIL:

default:

// 加载失败

loadStateImageView.setVisibility(View.VISIBLE);

loadStateTextView.setText(R.string.load_fail);

loadStateImageView.setBackgroundResource(R.drawable.load_failed);

break;

}

// 刷新结果停留1秒

new Handler()

{

@Override

public void handleMessage(Message msg)

{

changeState(DONE);

hide();

}

}.sendEmptyMessageDelayed(0, 1000);

}

private void changeState(int to)

{

state = to;

switch (state)

{

case INIT:

// 下拉布局初始状态

refreshStateImageView.setVisibility(View.GONE);

refreshStateTextView.setText(R.string.pull_to_refresh);

pullView.clearAnimation();

pullView.setVisibility(View.VISIBLE);

// 上拉布局初始状态

loadStateImageView.setVisibility(View.GONE);

loadStateTextView.setText(R.string.pullup_to_load);

pullUpView.clearAnimation();

pullUpView.setVisibility(View.VISIBLE);

break;

case RELEASE_TO_REFRESH:

// 释放刷新状态

refreshStateTextView.setText(R.string.release_to_refresh);

pullView.startAnimation(rotateAnimation);

break;

case REFRESHING:

// 正在刷新状态

pullView.clearAnimation();

refreshingView.setVisibility(View.VISIBLE);

pullView.setVisibility(View.INVISIBLE);

refreshingView.startAnimation(refreshingAnimation);

refreshStateTextView.setText(R.string.refreshing);

break;

case RELEASE_TO_LOAD:

// 释放加载状态

loadStateTextView.setText(R.string.release_to_load);

pullUpView.startAnimation(rotateAnimation);

break;

case LOADING:

// 正在加载状态

pullUpView.clearAnimation();

loadingView.setVisibility(View.VISIBLE);

pullUpView.setVisibility(View.INVISIBLE);

loadingView.startAnimation(refreshingAnimation);

loadStateTextView.setText(R.string.loading);

break;

case DONE:

// 刷新或加载完毕,啥都不做

break;

}

}

/**

* 不限制上拉或下拉

*/

private void releasePull()

{

canPullDown = true;

canPullUp = true;

}

/*

* (非 Javadoc)由父控件决定是否分发事件,防止事件冲突

*

* @see android.view.ViewGroup#dispatchTouchEvent(android.view.MotionEvent)

*/

@Override

public boolean dispatchTouchEvent(MotionEvent ev)

{

switch (ev.getActionMasked())

{

case MotionEvent.ACTION_DOWN:

downY = ev.getY();

lastY = downY;

timer.cancel();

mEvents = 0;

releasePull();

break;

case MotionEvent.ACTION_POINTER_DOWN:

case MotionEvent.ACTION_POINTER_UP:

// 过滤多点触碰

mEvents = -1;

break;

case MotionEvent.ACTION_MOVE:

if (mEvents == 0)

{

if (((Pullable) pullableView).canPullDown() && canPullDown

&& state != LOADING)

{

// 可以下拉,正在加载时不能下拉

// 对实际滑动距离做缩小,造成用力拉的感觉

pullDownY = pullDownY + (ev.getY() - lastY) / radio;

if (pullDownY < 0)

{

pullDownY = 0;

canPullDown = false;

canPullUp = true;

}

if (pullDownY >getMeasuredHeight())

pullDownY = getMeasuredHeight();

if (state == REFRESHING)

{

// 正在刷新的时候触摸移动

isTouch = true;

}

} else if (((Pullable) pullableView).canPullUp() && canPullUp

&& state != REFRESHING)

{

// 可以上拉,正在刷新时不能上拉

pullUpY = pullUpY + (ev.getY() - lastY) / radio;

if (pullUpY >0)

{

pullUpY = 0;

canPullDown = true;

canPullUp = false;

}

if (pullUpY < -getMeasuredHeight())

pullUpY = -getMeasuredHeight();

if (state == LOADING)

{

// 正在加载的时候触摸移动

isTouch = true;

}

} else

releasePull();

} else

mEvents = 0;

lastY = ev.getY();

// 根据下拉距离改变比例

radio = (float) (2 + 2 * Math.tan(Math.PI / 2 / getMeasuredHeight()

* (pullDownY + Math.abs(pullUpY))));

requestLayout();

if (pullDownY <= refreshDist && state == RELEASE_TO_REFRESH)

{

// 如果下拉距离没达到刷新的距离且当前状态是释放刷新,改变状态为下拉刷新

changeState(INIT);

}

if (pullDownY >= refreshDist && state == INIT)

{

// 如果下拉距离达到刷新的距离且当前状态是初始状态刷新,改变状态为释放刷新

changeState(RELEASE_TO_REFRESH);

}

// 下面是判断上拉加载的,同上,注意pullUpY是负值

if (-pullUpY <= loadmoreDist && state == RELEASE_TO_LOAD)

{

changeState(INIT);

}

if (-pullUpY >= loadmoreDist && state == INIT)

{

changeState(RELEASE_TO_LOAD);

}

// 因为刷新和加载操作不能同时进行,所以pullDownY和pullUpY不会同时不为0,因此这里用(pullDownY +

// Math.abs(pullUpY))就可以不对当前状态作区分了

if ((pullDownY + Math.abs(pullUpY)) >8)

{

// 防止下拉过程中误触发长按事件和点击事件

ev.setAction(MotionEvent.ACTION_CANCEL);

}

break;

case MotionEvent.ACTION_UP:

if (pullDownY >refreshDist || -pullUpY >loadmoreDist)

// 正在刷新时往下拉(正在加载时往上拉),释放后下拉头(上拉头)不隐藏

isTouch = false;

if (state == RELEASE_TO_REFRESH)

{

changeState(REFRESHING);

// 刷新操作

if (mListener != null)

mListener.onRefresh(this);

} else if (state == RELEASE_TO_LOAD)

{

changeState(LOADING);

// 加载操作

if (mListener != null)

mListener.onLoadMore(this);

}

hide();

default:

break;

}

// 事件分发交给父类

super.dispatchTouchEvent(ev);

return true;

}

private void initView()

{

// 初始化下拉布局

pullView = refreshView.findViewById(R.id.pull_icon);

refreshStateTextView = (TextView) refreshView

.findViewById(R.id.state_tv);

refreshingView = refreshView.findViewById(R.id.refreshing_icon);

refreshStateImageView = refreshView.findViewById(R.id.state_iv);

// 初始化上拉布局

pullUpView = loadmoreView.findViewById(R.id.pullup_icon);

loadStateTextView = (TextView) loadmoreView

.findViewById(R.id.loadstate_tv);

loadingView = loadmoreView.findViewById(R.id.loading_icon);

loadStateImageView = loadmoreView.findViewById(R.id.loadstate_iv);

}

@Override

protected void onLayout(boolean changed, int l, int t, int r, int b)

{

if (!isLayout)

{

// 这里是第一次进来的时候做一些初始化

refreshView = getChildAt(0);

pullableView = getChildAt(1);

loadmoreView = getChildAt(2);

isLayout = true;

initView();

refreshDist = ((ViewGroup) refreshView).getChildAt(0)

.getMeasuredHeight();

loadmoreDist = ((ViewGroup) loadmoreView).getChildAt(0)

.getMeasuredHeight();

}

// 改变子控件的布局,这里直接用(pullDownY + pullUpY)作为偏移量,这样就可以不对当前状态作区分

refreshView.layout(0,

(int) (pullDownY + pullUpY) - refreshView.getMeasuredHeight(),

refreshView.getMeasuredWidth(), (int) (pullDownY + pullUpY));

pullableView.layout(0, (int) (pullDownY + pullUpY),

pullableView.getMeasuredWidth(), (int) (pullDownY + pullUpY)

+ pullableView.getMeasuredHeight());

loadmoreView.layout(0,

(int) (pullDownY + pullUpY) + pullableView.getMeasuredHeight(),

loadmoreView.getMeasuredWidth(),

(int) (pullDownY + pullUpY) + pullableView.getMeasuredHeight()

+ loadmoreView.getMeasuredHeight());

}

class MyTimer

{

private Handler handler;

private Timer timer;

private MyTask mTask;

public MyTimer(Handler handler)

{

this.handler = handler;

timer = new Timer();

}

public void schedule(long period)

{

if (mTask != null)

{

mTask.cancel();

mTask = null;

}

mTask = new MyTask(handler);

timer.schedule(mTask, 0, period);

}

public void cancel()

{

if (mTask != null)

{

mTask.cancel();

mTask = null;

}

}

class MyTask extends TimerTask

{

private Handler handler;

public MyTask(Handler handler)

{

this.handler = handler;

}

@Override

public void run()

{

handler.obtainMessage().sendToTarget();

}

}

}

/**

* 刷新加载回调接口

*

* @author chenjing

*

*/

public interface OnRefreshListener

{

/**

* 刷新操作

*/

void onRefresh(PullToRefreshLayout pullToRefreshLayout);

/**

* 加载操作

*/

void onLoadMore(PullToRefreshLayout pullToRefreshLayout);

}

}

篇9:iOS MJRefresh下拉刷新 上拉加载(可添加gif图版)

1.首先去github上下载最新版 MJ刷新库 下载MJ链接

2.tableVIew中加入相关代码

_tableView = [[UITableView alloc] initWithFrame.:CGRectMake(0, 0, MCAPPWidth, MCAPPHeight - 64)];

_tableView.backgroundColor = myClearColor;

_tableView.separatorStyle. = UITableViewCellSeparatorStyleNone;

_tableView.delegate = self;

_tableView.dataSource = self;

_tableView.showsVerticalScrollIndicator = NO;

_tableView.scrollsToTop = YES;

[self.view addSubview:_tableView];

[_tableView addGifHeaderWithRefreshingTarget:self refreshingAction:@selector(loadData)];

[_tableView addGifFooterWithRefreshingTarget:self refreshingAction:@selector(loadMoreData)];

[self gif];

//loadData 为你下拉刷新时请求网络数据的方法 loadMoreData为你上拉加载时请求网络数据的方法

3. [self gif]

- (void)gif

{

NSMutableArray *idleImages = [NSMutableArray array];

//这块为你刷新时出现的gif图 需要循环添加到数组中

for (NSUInteger i = 1; i <= 5; i++) {

UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@img_loading-%lu.png, (unsigned long)i]];

[idleImages addObject:image];

}

[_tableView.gifHeader setImages:idleImages forState:MJRefreshHeaderStateIdle];

_tableView.gifFooter.refreshingImages = idleImages;

_tableView.gifHeader.updatedTimeHidden = YES;

// 设置即将刷新状态的动画图片(一松开就会刷新的状态)

NSMutableArray *refreshingImages = [NSMutableArray array];

for (NSUInteger i = 1; i <= 5; i++) {

UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@img_loading-%lu.png, (unsigned long)i]];

[refreshingImages addObject:image];

}

[_tableView.gifHeader setImages:refreshingImages forState:MJRefreshHeaderStatePulling];

}

4. 自定义刷新时顶部底部出现的Label和gif图的frame. 这里举footer的例子

MJRefreshGifFooter.m

- (void)layoutSubviews

{

[super layoutSubviews];

// 指示器 gif图的frame

self.gifView.frame. = CGRectMake(self.bounds.origin.x + 20, self.bounds.origin.y + 15, self.bounds.size.width / 2, self.bounds.size.height / 2);

if (self.stateHidden) {

self.gifView.contentMode = UIViewContentModeCenter;

} else {

self.gifView.contentMode = UIViewContentModeScaleAspectFit;

self.gifView.mj_w = self.mj_w * 0.5 - 90;

}

}

MJRefreshFooter.m

- (void)layoutSubviews

{

[super layoutSubviews];

self.loadMoreButton.frame. = self.bounds;

self.loadMoreButton.hidden = YES;

//Label的frame

self.stateLabel.frame. = CGRectMake(self.bounds.origin.x, self.bounds.origin.y + 15, self.bounds.size.width, self.bounds.size.height / 2);

self.noMoreLabel.frame. = self.bounds;

}

同理header的gif图frame. 和Labelframe. 都在相应的类里的方法里 都可以根据需求去修改

更多的设置可以看下MJ在github上相关的文档,

iOS MJRefresh下拉刷新 上拉加载(可添加gif图版)

篇10:android 下拉刷新上拉加载更多,高仿ios左滑动删除item,解决了

一、前言

老规矩,别的不说,这demo是找了很相关知识集合而成的,可以说对我这种小白来说是绞尽脑汁!程序员讲的是无图无真相!现在大家一睹为快!

二、比较关键的还是scroller这个类的

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

package com.icq.slideview.view;

import android.content.Context;

import android.util.AttributeSet;

import android.util.Log;

import android.util.TypedValue;

import android.view.MotionEvent;

import android.view.View;

import android.widget.LinearLayout;

import android.widget.RelativeLayout;

import android.widget.Scroller;

import android.widget.TextView;

import com.icq.slideview.R;

public class SlideView extends LinearLayout {

private static final String TAG = SlideView;

private Context mContext;

private LinearLayout mViewContent;

private RelativeLayout mHolder;

private Scroller mScroller;

private OnSlideListener mOnSlideListener;

private int mHolderWidth = 120;

private int mLastX = 0;

private int mLastY = 0;

private static final int TAN = 2;

public interface OnSlideListener {

public static final int SLIDE_STATUS_OFF = 0;

public static final int SLIDE_STATUS_START_SCROLL = 1;

public static final int SLIDE_STATUS_ON = 2;

/**

* @param view current SlideView

* @param status SLIDE_STATUS_ON or SLIDE_STATUS_OFF

*/

public void onSlide(View view, int status);

}

public SlideView(Context context) {

super(context);

initView();

}

public SlideView(Context context, AttributeSet attrs) {

super(context, attrs);

initView();

}

private void initView() {

mContext = getContext();

mScroller = new Scroller(mContext);

setOrientation(LinearLayout.HORIZONTAL);

View.inflate(mContext, R.layout.slide_view_merge, this);

mViewContent = (LinearLayout) findViewById(R.id.view_content);

mHolderWidth = Math.round(TypedValue.applyDimension(

TypedValue.COMPLEX_UNIT_DIP, mHolderWidth, getResources()

.getDisplayMetrics()));

}

public void setButtonText(CharSequence text) {

((TextView)findViewById(R.id.delete)).setText(text);

}

public void setContentView(View view) {

mViewContent.addView(view);

}

public void setOnSlideListener(OnSlideListener onSlideListener) {

mOnSlideListener = onSlideListener;

}

public void shrink() {

if (getScrollX() != 0) {

this.smoothScrollTo(0, 0);

}

}

public void onRequireTouchEvent(MotionEvent event) {

int x = (int) event.getX();

int y = (int) event.getY();

int scrollX = getScrollX();

Log.d(TAG, x= + x +  y= + y);

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN: {

int deltaX = x - mLastX;

System.out.println(按下偏移+deltaX);

if (!mScroller.isFinished()) {

mScroller.abortAnimation();

}

if (mOnSlideListener != null) {

mOnSlideListener.onSlide(this,

OnSlideListener.SLIDE_STATUS_START_SCROLL);

}

break;

}

case MotionEvent.ACTION_MOVE: {

int deltaX = x - mLastX;

int deltaY = y - mLastY;

System.out.println(偏移+deltaX);

if (Math.abs(deltaX) < Math.abs(deltaY) * TAN) {

break;

}

int newScrollX = scrollX - deltaX;

if (deltaX != 0) {

if (newScrollX < 0) {

newScrollX = 0;

} else if (newScrollX >mHolderWidth) {

newScrollX = mHolderWidth;

}

this.scrollTo(newScrollX, 0);

}

break;

}

case MotionEvent.ACTION_UP: {

int newScrollX = 0;

if (scrollX - mHolderWidth * 0.75 >0) {

newScrollX = mHolderWidth;

}

this.smoothScrollTo(newScrollX, 0);

if (mOnSlideListener != null) {

mOnSlideListener.onSlide(this,

newScrollX == 0 ? OnSlideListener.SLIDE_STATUS_OFF

: OnSlideListener.SLIDE_STATUS_ON);

}

break;

}

default:

break;

}

mLastX = x;

mLastY = y;

}

private void smoothScrollTo(int destX, int destY) {

// 缓慢滚动到指定位置

int scrollX = getScrollX();

int delta = destX - scrollX;

System.out.println(偏移scrollX+scrollX);

System.out.println(偏移差delta+delta);

int a= Math.abs(delta) * 3;

System.out.println(什么意思+a);

mScroller.startScroll(scrollX, 0, delta, 0, Math.abs(delta) * 3);

invalidate();

}

@Override

public void computeScroll() {

if (mScroller.computeScrollOffset()) {

System.out.println(当前x位置:+mScroller.getCurrX());

System.out.println(当前Y位置:+mScroller.getCurrY());

scrollTo(mScroller.getCurrX(), mScroller.getCurrY());

postInvalidate();

}

}

}

Android登陆界面采用文件存储实现

实例解析TPlink路由器实现多人上网

Android开发之Drag&Drop框架实现拖放手势

Android ActionBar上不显示icon的问题

Android 源代码实例:实现上拉加载下拉刷新浮动效果(锦集10篇)

欢迎下载DOC格式的Android 源代码实例:实现上拉加载下拉刷新浮动效果,但愿能给您带来参考作用!
推荐度: 推荐 推荐 推荐 推荐 推荐
点击下载文档 文档为doc格式
推荐文章
最新范文
点击下载本文文档