- Function introduction
Drop-down refresh is a feature that almost every Android application needs. android-Ultra-Pull-To-Refresh (hereinafter referred to as UltraPTR) is a powerful Andriod drop-down refresh framework.
Main features:
(1) Inherited from ViewGroup, Content can contain any View.
(2) Simple and perfect Header abstraction, easy to expand and build a head that meets the needs.
GitHub
2. Overall design
The overall design of UltraPTR is simple and clear.
Firstly, two interfaces, functional interface and UI interface are abstracted.
PtrHandler represents the drop-down refresh function interface, including the refresh function callback method and the method of judging whether the drop-down can be made. Users implement this interface to refresh data.
PtrUIHandler represents a drop-down refresh UI interface, including callback methods for preparing drop-down, drop-down, drop-down completion, reset and position change during drop-down. Usually, headers need to implement this interface to handle changes in the Header UI during drop-down refresh.
The whole project revolves around the core class PtrFrameLayout. PtrFrameLayout represents a drop-down refresh custom control.
PtrFrameLayout inherits from ViewGroup and has and can only have two sub-Views, header and content. Usually the Header implements the PtrUIHandler interface, and Content can be any View.
Like all custom controls, PtrFrameLayout determines the size and location of controls by rewriting onFinishInflate, onMeasure, and onLayout. The drop-down behavior of the control is determined by rewriting dispatchTouchEvent.
rely on
compile 'in.srain.cube:ultra-ptr:1.0.11'
Customized
You can add PtrUIHandler to PtrFrameLayout to achieve any UI effect you want.
public interface PtrUIHandler {
/ * *
*When the content view reaches the top and the refresh is complete, the view is reset.
*
* @param frame
* / public void onUIReset( PtrFrameLayout frame);
/ * *
*Ready to load
*
* @param frame
* / public void onUIRefreshPrepare( PtrFrameLayout frame);
/ * *
*Execution refresh UI
* / public void onUIRefreshBegin( PtrFrameLayout frame);
/ * *
*Execution after refresh UI
* / public void onUIRefreshComplete( PtrFrameLayout frame);
public void onUIPositionChange(PtrFrameLayout frame,boolean isUnderTouch,byte status,int oldPosition,int currentPosition,float oldPercent,float currentPercent);
}}
Chestnut explanation
PtrClassic DefaultHeader implements the PtrUIHandler interface.
The classical style of Header implementation can be used as a reference for our implementation of custom header. The following is the specific implementation.
@Override
public void onUIReset(PtrFrameLayout frame) {
resetView();
mShouldShowLastUpdate = true;
tryUpdateLastUpdateTime();
}
private void resetView() {
hideRotateView();
mProgressBar.setVisibility(INVISIBLE);
}
private void hideRotateView() {
mRotateView.clearAnimation();
mRotateView.setVisibility(INVISIBLE);
}
Reset View, hide busy progress bar, hide arrow View, update last refresh time.
@Override
public void onUIRefreshPrepare(PtrFrameLayout frame) {
mShouldShowLastUpdate = true;
tryUpdateLastUpdateTime();
mLastUpdateTimeUpdater.start();
mProgressBar.setVisibility(INVISIBLE);
mRotateView.setVisibility(VISIBLE);
mTitleTextView.setVisibility(VISIBLE);
if (frame.isPullToRefresh()) {
mTitleTextView.setText(getResources().getString(R.string.cube_ptr_pull_down_to_refresh));
} else {
mTitleTextView.setText(getResources().getString(R.string.cube_ptr_pull_down));
}
}
Prepare to refresh, hide busy progress bar, display arrow View, display text, if it is a drop-down refresh, show "drop-down refresh", if it is a release refresh, show "drop-down".
@Override
public void onUIRefreshBegin(PtrFrameLayout frame) {
mShouldShowLastUpdate = false;
hideRotateView();
mProgressBar.setVisibility(VISIBLE);
mTitleTextView.setVisibility(VISIBLE);
mTitleTextView.setText(R.string.cube_ptr_refreshing);
tryUpdateLastUpdateTime();
mLastUpdateTimeUpdater.stop();
}
Start refreshing, hide arrow View, display busy progress bar, display text, display "loaded..." Update the last refresh time.
@Override
public void onUIRefreshComplete(PtrFrameLayout frame) {
hideRotateView();
mProgressBar.setVisibility(INVISIBLE);
mTitleTextView.setVisibility(VISIBLE);
mTitleTextView.setText(getResources().getString(R.string.cube_ptr_refresh_complete));
// update last update time
SharedPreferences sharedPreferences = getContext().getSharedPreferences(KEY_SharedPreferences, 0);
if (!TextUtils.isEmpty(mLastUpdateTimeKey)) {
mLastUpdateTime = new Date().getTime();
sharedPreferences.edit().putLong(mLastUpdateTimeKey, mLastUpdateTime).commit();
}
}
At the end of the refresh, hide the arrow View, hide the busy progress bar, display the text, show "Update Completed" and write the last refresh time.
@Override
public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, int lastPos, int currentPos, float oldPercent, float currentPercent) {
final int mOffsetToRefresh = frame.getOffsetToRefresh();
if (currentPos < mOffsetToRefresh && lastPos >= mOffsetToRefresh) {
if (isUnderTouch && status == PtrFrameLayout.PTR_STATUS_PREPARE) {
crossRotateLineFromBottomUnderTouch(frame);
if (mRotateView != null) {
mRotateView.clearAnimation();
mRotateView.startAnimation(mReverseFlipAnimation);
}
}
} else if (currentPos > mOffsetToRefresh && lastPos <= mOffsetToRefresh) {
if (isUnderTouch && status == PtrFrameLayout.PTR_STATUS_PREPARE) {
crossRotateLineFromTopUnderTouch(frame);
if (mRotateView != null) {
mRotateView.clearAnimation();
mRotateView.startAnimation(mFlipAnimation);
}
}
}
}
Position change callback during pull-down.
In the case of dragging, when the drop-down distance is from less than the refresh height to more than the refresh height, the arrow View changes from downward to upward, while changing the text display.
When the drop-down distance is from greater than the refresh height to less than the refresh height, the arrow View changes from upward to downward, while changing the text display.
Callback
ptrFrame.setPtrHandler(new PtrHandler() {
@Override
public void onRefreshBegin(PtrFrameLayout frame) {
frame.postDelayed(new Runnable() {
@Override
public void run() {
ptrFrame.refreshComplete();
}
}, 1800);
}
@Override
public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {
return PtrDefaultHandler.checkContentCanBePulledDown(frame, content, header);
}
});
Case 2
First, we need to define the head layout we need.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp"
android:orientation="horizontal"
android:background="@color/grby">
<LinearLayout
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_weight="0.5">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="@+id/iv_windmill"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:background="@mipmap/header"/>
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="35dp"
android:orientation="vertical">
<TextView
android:id="@+id/tv_head_title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="30dp"
android:gravity="bottom"
android:text="Drop-down refresh"
android:textColor="#ffffff"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="25dp"
android:orientation="vertical">
<TextView
android:id="@+id/tv_head_time"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:text="The refresh time : 2015-10-23 12:00"
android:textColor="#ffffff"
android:textSize="10dp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
public class WindmillHeader extends FrameLayout implements PtrUIHandler {
private LayoutInflater inflater;
// Drop-down Refresh View (Header View)
private ViewGroup headView;
// Dropdown refresh text
private TextView tvHeadTitle;
// Drop-down Icon
private ImageView ivWindmill;
// Drop-down refresh time
private TextView tvHeadTime;
/** Save the last refresh time. */
private String lastRefreshTime = null;
//animation
private WindmillDrawable drawable;
public WindmillHeader(Context context) {
this(context, null);
}
public WindmillHeader(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public WindmillHeader(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
/**
* Initialization
*
* @param context
*/
private void init(Context context) {
inflater = LayoutInflater.from(context);
/**
* head
*/
headView = (ViewGroup) inflater.inflate(R.layout.windmill_header, this, true);
ivWindmill = (ImageView) headView.findViewById(R.id.iv_windmill);
tvHeadTitle = (TextView) headView.findViewById(R.id.tv_head_title);
tvHeadTime= (TextView) findViewById(R.id.tv_head_time);
drawable = new WindmillDrawable(context, ivWindmill);
ivWindmill.setImageDrawable(drawable);
}
@Override
public void onUIReset(PtrFrameLayout ptrFrameLayout) {
tvHeadTitle.setText("Drop-down refresh");
drawable.stop();
}
@Override
public void onUIRefreshPrepare(PtrFrameLayout ptrFrameLayout) {
tvHeadTitle.setText("Drop-down refresh");
if(lastRefreshTime==null){
lastRefreshTime = TimeUtils.getCurrentTimeInString();
tvHeadTime.setText("Current refresh time:" + lastRefreshTime);
}else{
tvHeadTime.setText("Last refresh time:" + lastRefreshTime);
}
}
@Override
public void onUIRefreshBegin(PtrFrameLayout ptrFrameLayout) {
tvHeadTitle.setText("Refreshing");
tvHeadTime.setText("This refresh time:" + lastRefreshTime);
drawable.start();
}
@Override
public void onUIRefreshComplete(PtrFrameLayout ptrFrameLayout) {
ivWindmill.clearAnimation();
tvHeadTitle.setText("Refresh finish");
tvHeadTime.setText("This refresh time:" + lastRefreshTime);
}
@Override
public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, int lastPos, int currentPos, float oldPercent, float currentPercent) {
if (isUnderTouch && status == PtrFrameLayout.PTR_STATUS_PREPARE) {
drawable.postRotation(currentPos - lastPos);
invalidate();
}
final int mOffsetToRefresh = frame.getOffsetToRefresh();
if (currentPos < mOffsetToRefresh && lastPos >= mOffsetToRefresh) {
if (isUnderTouch && status == PtrFrameLayout.PTR_STATUS_PREPARE) {
tvHeadTitle.setText("Drop-down refresh");
if(lastRefreshTime==null){
lastRefreshTime = TimeUtils.getCurrentTimeInString();
tvHeadTime.setText("Current refresh time:" + lastRefreshTime);
}else{
tvHeadTime.setText("Last refresh time:" + lastRefreshTime);
}
}
} else if (currentPos > mOffsetToRefresh && lastPos <= mOffsetToRefresh) {
if (isUnderTouch && status == PtrFrameLayout.PTR_STATUS_PREPARE) {
tvHeadTitle.setText("Release and refresh");
tvHeadTime.setText("Last refresh time:" + lastRefreshTime);
lastRefreshTime = TimeUtils.getCurrentTimeInString();
}
}
}
}
private WindmillHeader header;
private void initView() {
ptr= (PtrFrameLayout) findViewById(R.id.ptr_main);
//Create a custom header UI
header = new WindmillHeader(this);
/* Set refresh header view */
ptr.setHeaderView(header);
//Set callback
ptr.addPtrUIHandler(header);
ptr.disableWhenHorizontalMove(true);
ptr.setPtrHandler(new PtrDefaultHandler() {
@Override
public void onRefreshBegin(final PtrFrameLayout frame) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// ptr.refreshComplete();
getdata();
}
}, 3000);
}
@Override
public boolean checkCanDoRefresh(PtrFrameLayout frame,
View content, View header) {
return PtrDefaultHandler.checkContentCanBePulledDown(frame,
content, header);
}
});
/* Delay 100 seconds, automatic refresh */
ptr.postDelayed(new Runnable() {
@Override
public void run() {
ptr.autoRefresh(false);
}
}, 100);
}
Case 3
public class WindmillHeader extends FrameLayout implements PtrUIHandler {
private LayoutInflater inflater;
// Drop-down Refresh View (Header View)
private ViewGroup headView;
// Dropdown refresh text
private TextView tvHeadTitle;
// Drop-down Icon
private ImageView ivWindmill;
private WindmillDrawable drawable;
public WindmillHeader(Context context) {
this(context, null);
}
public WindmillHeader(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public WindmillHeader(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
/**
* Initialization
*
* @param context
*/
private void init(Context context) {
inflater = LayoutInflater.from(context);
/**
* head
*/
headView = (ViewGroup) inflater.inflate(R.layout.windmill_header, this, true);
ivWindmill = (ImageView) headView.findViewById(R.id.iv_windmill);
tvHeadTitle = (TextView) headView.findViewById(R.id.tv_head_title);
drawable = new WindmillDrawable(context, ivWindmill);
ivWindmill.setImageDrawable(drawable);
}
@Override
public void onUIReset(PtrFrameLayout ptrFrameLayout) {
tvHeadTitle.setText("Drop-down refresh");
drawable.stop();
}
@Override
public void onUIRefreshPrepare(PtrFrameLayout ptrFrameLayout) {
tvHeadTitle.setText("Drop-down refresh");
}
@Override
public void onUIRefreshBegin(PtrFrameLayout ptrFrameLayout) {
tvHeadTitle.setText("Refreshing");
drawable.start();
}
@Override
public void onUIRefreshComplete(PtrFrameLayout ptrFrameLayout) {
ivWindmill.clearAnimation();
tvHeadTitle.setText("Refresh finish");
}
@Override
public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, int lastPos, int currentPos, float oldPercent, float currentPercent) {
if (isUnderTouch && status == PtrFrameLayout.PTR_STATUS_PREPARE) {
drawable.postRotation(currentPos - lastPos);
invalidate();
}
final int mOffsetToRefresh = frame.getOffsetToRefresh();
if (currentPos < mOffsetToRefresh && lastPos >= mOffsetToRefresh) {
if (isUnderTouch && status == PtrFrameLayout.PTR_STATUS_PREPARE) {
tvHeadTitle.setText("Drop-down refresh");
}
} else if (currentPos > mOffsetToRefresh && lastPos <= mOffsetToRefresh) {
if (isUnderTouch && status == PtrFrameLayout.PTR_STATUS_PREPARE) {
tvHeadTitle.setText("Release and refresh");
}
}
}
}
public class WindmillDrawable extends Drawable implements Animatable {
private static final String TAG = WindmillDrawable.class.getSimpleName();
private Resources resources;
private Bitmap windmill;
private Matrix matrix;
private View parent;
private Animation animation;
private boolean isFirstDraw = true;
private boolean isAnimating;
public WindmillDrawable(Context context, View parent) {
resources = context.getResources();
windmill = BitmapFactory.decodeResource(resources, R.drawable.windmill);
matrix = new Matrix();
this.parent = parent;
animation = new RotateAnimation(360, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
animation.setInterpolator(new LinearInterpolator());
animation.setDuration(800);
animation.setRepeatMode(Animation.RESTART);
animation.setRepeatCount(Animation.INFINITE);
animation.setFillAfter(true);
}
@Override
public void draw(Canvas canvas) {
if (isFirstDraw) {
isFirstDraw = false;
matrix.setTranslate((getBounds().width() - windmill.getWidth()) / 2, (getBounds().height() - windmill.getHeight()) / 2);
}
Paint p = new Paint();
canvas.drawBitmap(windmill, matrix, p);
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter cf) {
}
@Override
public int getOpacity() {
return 0;
}
public void postRotation(int degree) {
matrix.postRotate(degree, getBounds().exactCenterX(), getBounds().exactCenterY());
invalidateSelf();
}
@Override
public void start() {
parent.startAnimation(animation);
isAnimating = true;
}
@Override
public void stop() {
parent.clearAnimation();
isAnimating = false;
}
@Override
public boolean isRunning() {
return isAnimating;
}
*/
public class ContentGridViewFragment extends Fragment {
private GridView gvMain;
private BaseAdapter adapter;
private PtrClassicFrameLayout ptr;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_content_grid_view, container, false);
initView(v);
return v;
}
private void initView(View v) {
gvMain = (GridView) v.findViewById(R.id.gv_main);
ptr = (PtrClassicFrameLayout) v.findViewById(R.id.ptr_main);
ptr.setPtrHandler(new PtrDefaultHandler() {
@Override
public void onRefreshBegin(PtrFrameLayout ptrFrameLayout) {
getData();
ptr.refreshComplete();
}
});
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
ptr.autoRefresh();
}
}, 100);
}
private void getData() {
adapter = new GradViewAdapter(getActivity(), Constants.SMALL_IMAGE_URLS);
gvMain.setAdapter(adapter);
}
}
Contact GitHub API Training Shop Blog About