編輯:關於Android編程
Android自定義彈性ScrollView
總結了下最近寫的彈性ScrollView,如下代碼主要是通過觸摸事件加動態更改布局實現的彈性ScrollView,具體分析都在注解中!
package ljh.android.view;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.TranslateAnimation;
import android.widget.ScrollView;
/**
* 彈性ScrollView 實現下拉彈回和上拉彈回
*
* @author Ljh
* 2015年8月26日
*/
public class ReboundScrollView extends ScrollView {
// 保存ScrollView中子控件
private View contentView = null;
// 用來保存唯一子控件的布局信息
private Rect contentViewRect = new Rect();
// 移動開始時候的Y坐標
private float startY;
// 線性阻尼 緩沖過量移動的移動速度
private static float MOVE_FACTOR = 0.5f;
//過度位移恢復的動畫持續時間
private static long DURATION_MILLIS = 280;
public ReboundScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public ReboundScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ReboundScrollView(Context context) {
super(context);
}
/**
* 在布局完成後得到ScrollView的唯一子View,並存在contentView中
*/
@Override
protected void onFinishInflate() {
if (getChildCount() > 0) {
contentView = getChildAt(0);
}
}
/**
* 在事件分發其中處理觸摸事件
* 根據android中事件分發的機制判斷,個人覺得把事件處理邏輯寫在分發器中比寫在onTouchEvent中好些,
* 因為在其子View沒有接收到該觸摸事件之前自己就處理了觸摸事件。
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (contentView != null)
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
startY = ev.getY();
break;
case MotionEvent.ACTION_UP:
if (isNeedAnimation()) {
playAnimation();
}
break;
case MotionEvent.ACTION_MOVE:
float nowY = ev.getY();
int detailY = (int) (nowY - startY);
if (isNeedMove(detailY)) {
// 超出屏幕後滾動的View移動的距離為滑動位移的MOVE_FACTOR倍
detailY = (int) (detailY * MOVE_FACTOR);
//重新布局子View,並且只修改頂部與底部的位置
contentView.layout(contentViewRect.left, contentViewRect.top + detailY, contentViewRect.right,
contentViewRect.bottom + detailY);
}
break;
default:
break;
}
return super.dispatchTouchEvent(ev);
}
/**
* 在布局都完成後contentView的布局也就確定了
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
//在未超出移動前contentView的布局沒有發生變化 即全局中contentView的布局不變
if(contentView != null){
contentViewRect.set(contentView.getLeft(), contentView.getTop(), contentView.getRight(),
contentView.getBottom());
}
}
/**
* 判斷是否需要超出屏幕移動
*
* 通過三個量來判斷是否需要移動及如何移動,這三個量分別為scrollY、
* contentViewHeight和scrollViewHeight外加輔助detailY手指移動的位移。分三種情況:
*
* 其中兩種均為contentViewHeight>scrollViewHeight:
* 1、當contentView的頂部處於ScrollView頂部且向下滑動手指時候需要超出屏幕移動條件為:
* scrollY == 0 && detailY > 0, 如圖:
* |-----scrollViewHeight-----|
* |----------contentViewHeight--------|
* -----detailY---->
*
* 2、當contentView的底部處於ScrollView底部且向上滑動手指時候需要超出屏幕移動條件為:
* scrollY + scrollViewHeight >= contentViewHeight && detailY < 0, 如圖:
* |--scrollY--|
* |-----scrollViewHeight-----|
* |-----------contentViewHeight----------|
* <-----detailY----
*
* 另外一種情況是contentViewHeight<=scrollViewHeight上下滑動都需要做超出屏幕移動
* 3、當contentView的本身處於ScrollView內部時候無論向上或向下滑動手指時候都需要超出屏幕移動條件為:
* contentViewHeight <= scrollViewHeight,如圖:
* |-----scrollViewHeight-----|
* |---contentViewHeight---|
* <-----detailY---->
*
* @param detailY
* 手指移動的位移(向下或向右滑動為正方向)
* @return 是否需要移動
*/
private boolean isNeedMove(int detailY) {
int scrollY = getScrollY();
int contentViewHeight = contentView.getHeight();
int scrollViewHeight = getHeight();
return (scrollY == 0 && detailY > 0)|| (scrollY + scrollViewHeight >= contentViewHeight && detailY < 0)
|| (contentViewHeight <= scrollViewHeight);
}
/**
* 播放contentView復位的動畫並將contentView復位
* 動畫可以自定義
* 動畫執行時間隨拉伸的距離增加而減少
*/
private void playAnimation() {
int contentViewTop = contentView.getTop();
int scrollViewHeight = this.getHeight();
float factor = 1-Math.abs(contentViewTop - contentViewRect.top)/(scrollViewHeight*1.0f);
TranslateAnimation ta = new TranslateAnimation(0,0,contentViewTop,contentViewRect.top);
ta.setDuration((long) (DURATION_MILLIS*factor));
contentView.startAnimation(ta);
contentView.layout(contentViewRect.left, contentViewRect.top
,contentViewRect.right,contentViewRect.bottom);
}
/**
* 判斷是否需要動畫效果
* @return
*/
private boolean isNeedAnimation() {
return contentView.getTop() != contentViewRect.top;
}
}
該實現方式中存在的問題或者是有待優化的問題,當ReboundScrollView處在最頂端或最低端拖動實現過量位移中不松開手指再反向減小偏移量時,滾動條會滾動!如果還有其他問題可以留言看到了一定回復!小伙伴有更好的彈性ScrollView的話可以分享給我!郵箱1075209054@qq.com 謝謝啦。
Android實現button居中的方法
本文實例講述了Android實現button居中的方法。分享給大家供大家參考。具體如下:通過在main.xml 或者其他xml 布局文件中布局Button的時候,選擇An
Android監聽輸入法彈窗和關閉的實現方法
用過ios的都知道ios上輸入法關閉的同時會自動關閉輸入框,那麼在android上如何實現監聽輸入法彈出和關閉呢?本篇文章就為你提供了一種可靠的實現方式。演示效果視頻地址
Android上下文服務管理查詢過程
在開發Android應用程序時,如果需要使用系統提供的服務,可以通過服務名稱調用山下文的getSystemService(String name)來獲取服務管理者,那麼該
Android AsyncTask使用以及源碼解析
綜述 在Android中,我們需要進行一些耗時的操作,會將這個操作放在子線程中進行。在子線程操作完成以後我們可以通過Handler進行發送消息,通知UI進行一些更新操作