APP Practical Development - Customize your own drop-down refresh header

Keywords: Android github less xml

  1. 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

Demo

Posted by brodywx on Fri, 29 Mar 2019 17:03:28 -0700