Android自定义控件——PullZoomView
Posted 顾明伟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android自定义控件——PullZoomView相关的知识,希望对你有一定的参考价值。
本文介绍PullZoomView的简单实现,如图:
就是通过下拉ListView或者ScrollView或者更多的View如GridView,RecycleView等等,的时候对Header有一个放大缩小的效果
实现思路就是根据所需要封装的不同的下拉控件来做不同的实现,比如:
ListView:该控件本身有添加Header的功能,我们只需做简单的处理就可以用了,在满足一定条件时做事件拦截,让整个控件向下滚动的时候回传一个value用来改变Header的高度。
ScrollView:这就需要我们自己封装一个Header在ScrollView的孩子控件当中。滚动的时候和ListView做相同的操作即可。
IPullZoom 定义公共接口
PullZoomBase 抽象公共的方法
PullZoomListView ListView的实现
PullZoomScrollView ScrollView的实现
IPullZoom.java
public interface IPullZoom
void initHeader(TypedArray a);
PullZoomBase.java
public abstract class PullZoomBase<T extends View> extends LinearLayout implements IPullZoom
/**
* 根布局,用来装所有内容
*/
protected T mRootView;
/**
* 定义的显示伸缩效果的View
*/
protected View mZoomView;
/**
* 伸缩效果上展示的内容
*/
protected View mHeadView;
/**
* 是否允许下拉
*/
private boolean isPullEnable = true;
private boolean isZooming;
private boolean isHeadHide;
private boolean isDragging;
private float mLastX;
private float mLastY;
private float mInitX;
private float mInitY;
private int mTouchSlop;
public PullZoomBase(Context context)
this(context, null);
public PullZoomBase(Context context, AttributeSet attrs)
this(context, attrs, 0);
public PullZoomBase(Context context, AttributeSet attrs, int defStyleAttr)
super(context, attrs, defStyleAttr);
ViewConfiguration config = ViewConfiguration.get(context);
mTouchSlop = config.getScaledTouchSlop();
mRootView = initRootView(context, attrs);
LayoutInflater inflater = LayoutInflater.from(context);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PullZoomView);
int zoomResId = a.getResourceId(R.styleable.PullZoomView_zoomview, 0);
if (zoomResId > 0)
mZoomView = inflater.inflate(zoomResId, null, false);
int headResId = a.getResourceId(R.styleable.PullZoomView_headview, 0);
if (headResId > 0)
mHeadView = inflater.inflate(headResId, null, false);
initHeader(a);
a.recycle();
addView(mRootView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
@Override
public boolean onInterceptTouchEvent(MotionEvent ev)
if (!isPullEnable() || isHeadHide())
return false;
int action = ev.getAction();
if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP)
isDragging = false;
return false;
if (action != MotionEvent.ACTION_DOWN && isDragging)
return true;
switch (action)
case MotionEvent.ACTION_DOWN:
if (allowStart())
mLastX = mInitX = ev.getX();
mLastY = mInitY = ev.getY();
isDragging = false;
break;
case MotionEvent.ACTION_MOVE:
if (allowStart())
float x = ev.getX();
float y = ev.getY();
float diffX = x - mLastX;
float diffY = y - mLastY;
float diffYAds = Math.abs(diffY);
if (diffYAds > mTouchSlop && diffYAds > Math.abs(diffX))
if (diffY >= 1 && allowStart())
mLastX = x;
mLastY = y;
isDragging = true;
break;
return isDragging;
@Override
public boolean onTouchEvent(MotionEvent event)
if (!isPullEnable || isHeadHide())
return false;
if (event.getAction() == MotionEvent.ACTION_DOWN && event.getEdgeFlags() != 0)
return false;
switch (event.getAction())
case MotionEvent.ACTION_DOWN:
if (allowStart())
mLastX = mInitX = event.getX();
mLastY = mInitY = event.getY();
return true;
break;
case MotionEvent.ACTION_MOVE:
if (allowStart())
mLastX = event.getX();
mLastY = event.getY();
final int newScrollValue = Math.round(Math.min(mInitY - mLastY, 0) / 2.0f);
pull(newScrollValue);
return true;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (isDragging)
isDragging = false;
smoothRestore();
break;
return false;
public boolean isPullEnable()
return isPullEnable;
public void setIsPullEnable(boolean isPullEnable)
this.isPullEnable = isPullEnable;
public boolean isHeadHide()
return isHeadHide;
public void setIsHeadHide(boolean isHeadHide)
this.isHeadHide = isHeadHide;
/**
* 创建根布局,例如ListView,GridView,RecycleView,ScrollView等等
*
* @param context
* @param set
* @return
*/
public abstract T initRootView(Context context, AttributeSet set);
/**
* 判定是否允许开始滚动
*
* @return
*/
public abstract boolean allowStart();
/**
* 传入一个计算值,用来对Header做放大缩小操作
*
* @param value
*/
public abstract void pull(int value);
/**
*
*/
public abstract void smoothRestore();
PullZoomListView.java
public class PullZoomListView extends PullZoomBase<ListView>
private FrameLayout mHeaderContainer;
private int mHeaderHeight;
private SmoothRestore mSmoothRestore;
public static Interpolator mInterpolator = new Interpolator()
@Override
public float getInterpolation(float input)
float f = input - 1.0F;
return 1.0F + f * (f * (f * (f * f)));
;
public PullZoomListView(Context context)
this(context, null);
public PullZoomListView(Context context, AttributeSet attrs)
this(context, attrs, 0);
public PullZoomListView(Context context, AttributeSet attrs, int defStyleAttr)
super(context, attrs, defStyleAttr);
mSmoothRestore = new SmoothRestore();
@Override
public ListView initRootView(Context context, AttributeSet set)
ListView listview = new ListView(context, set);
return listview;
@Override
public void initHeader(TypedArray a)
mHeaderContainer = new FrameLayout(getContext());
if (mZoomView != null)
mHeaderContainer.addView(mZoomView);
if (mHeadView != null)
mHeaderContainer.addView(mHeadView);
mRootView.addHeaderView(mHeaderContainer);
public void setAdapter(BaseAdapter adapter)
mRootView.setAdapter(adapter);
public void setHeaderLayoutParams(AbsListView.LayoutParams params)
if (mHeaderContainer != null)
mHeaderContainer.setLayoutParams(params);
mHeaderHeight = params.height;
public void updateHeader()
if (mHeaderContainer != null)
mRootView.removeHeaderView(mHeaderContainer);
mHeaderContainer.removeAllViews();
if (mZoomView != null)
mHeaderContainer.addView(mZoomView);
if (mHeadView != null)
mHeaderContainer.addView(mHeadView);
mHeaderHeight = mHeaderContainer.getHeight();
mRootView.addHeaderView(mHeaderContainer);
@Override
public boolean allowStart()
return isFirstItemVisiable();
private boolean isFirstItemVisiable()
Adapter adapter = mRootView.getAdapter();
if (null == adapter || adapter.isEmpty())
return true;
else
if (mRootView.getFirstVisiblePosition() <= 1)
View view = mRootView.getChildAt(0);
if (view != null)
return view.getTop() >= mRootView.getTop();
return false;
@Override
public void pull(int value)
if (mSmoothRestore != null && !mSmoothRestore.isFinish())
mSmoothRestore.abort();
ViewGroup.LayoutParams params = mHeaderContainer.getLayoutParams();
params.height = Math.abs(value) + mHeaderHeight;
mHeaderContainer.setLayoutParams(params);
@Override
public void smoothRestore()
mSmoothRestore.start(200L);
class SmoothRestore implements Runnable
protected long duration;
protected boolean isFinished;
protected float scale;
protected long starttime;
SmoothRestore()
public void abort()
isFinished = true;
public boolean isFinish()
return isFinished;
public void start(long d)
if (mZoomView != null)
starttime = SystemClock.currentThreadTimeMillis();
duration = d;
scale = (float) mHeaderContainer.getBottom() / mHeaderHeight;
isFinished = false;
post(this);
@Override
public void run()
if (mZoomView != null)
float f2;
ViewGroup.LayoutParams params;
if (!isFinished && scale > 1.0D)
float f1 = ((float) SystemClock.currentThreadTimeMillis() - (float) starttime) / (float) duration;
f2 = scale - (scale - 1.0F) * PullZoomListView.mInterpolator.getInterpolation(f1);
params = mHeaderContainer.getLayoutParams();
if (f2 > 1.0F)
params.height = (int) (f2 * mHeaderHeight);
mHeaderContainer.setLayoutParams(params);
post(this);
return;
isFinished = true;
以上是关于Android自定义控件——PullZoomView的主要内容,如果未能解决你的问题,请参考以下文章