不引入扩展包,使用SwipeRefreshLayout样式下拉刷新(Canva绘制)
2017-01-14 00:00
387 查看
import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.util.Log; import android.view.MotionEvent; import android.view.View; import org.json.JSONException; import org.json.JSONObject; /** * Created by DCloud on 2017/1/6. */ public class PullRefreshCircleView extends View { CircleRefreshDrawer drawer = null; public PullRefreshCircleView(Context context) { super(context); // setBackgroundColor(Color.RED); drawer = new CircleRefreshDrawer(this, new CircleRefreshDrawer.OnRefreshListener() { @Override public void onRefreshing(int state) { Log.d("PullRefreshCircleView","启动刷新 state=" + state); postDelayed(new Runnable() { @Override public void run() { drawer.endRefresh(); } },5000); } }); try { int pw = getResources().getDisplayMetrics().widthPixels; int ph = getResources().getDisplayMetrics().heightPixels; float scale = getResources().getDisplayMetrics().density; drawer.parseData(new JSONObject("{height:'100',range:'200',offset:'50'}"),pw,ph,scale); } catch (JSONException e) { e.printStackTrace(); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(720,1210); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); drawer.onDraw(canvas); } @Override public boolean onTouchEvent(MotionEvent event) { boolean ret = drawer.onTouchEvent(event); if(ret){ invalidate(); return true; }else{ return super.onTouchEvent(event); } } } import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Rect; import android.graphics.RectF; import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; import android.view.MotionEvent; import android.view.View; import org.json.JSONObject; /** * Created by DCloud on 2017/1/5. */ class CircleRefreshDrawer { Paint paint = new Paint(); /**整个下拉刷新的位置*/ float mDrawerX,mDrawerY,mDrawerYDefault; /**怎个个下拉刷新的高度*/ float mDrawerWidth,mDrawerHeight; static final int State_Normal = 0; static final int State_Enable = 1; static final int State_Refreshing = 2; static final int State_Refresh_End = 3; //刷新状态数据 int mRefreshState = State_Normal; int mRefreshEnableOffsetY = 100,mRefreshRefreshingOffsetMaxY = 100; //控件底部y轴值 int mRefreshOffsetY; //控件底部开始出现时的y轴值 int mOffsetY; int mAutoBackV; // 刷新圆弧 RectF mArcRectF = null; int mRefreshArcStartAngle,mRefreshArcSweepAngle,mRefreshArcX,mRefreshArcY,mRefreshArcWidth,mRefreshArcHeight; int mCha,mArcColor,mArcRotateAngle,mArcColorAlpha; final int F_ArcColorAlphaMin = 100; int mRefreshArcSweepAngleMax = 280; float mArcStrokeWidth ; float mCircleShadeStrokeWidth; int mCircleShadeColor; float mLastMoveY; View mBindView = null; //箭头 int mArrowHeight = 0; int F_Arrow_Max_Height; int mArrowColor; Path mArrowPath = new Path(); JSONObject mJsonData = null; int mParentWidth,mParentHeight; private DisplayMetrics mDisplayMetrics; OnRefreshListener mListener = null; CircleRefreshDrawer(View adaWebview,OnRefreshListener listener){ mBindView = adaWebview; mListener = listener; } float px2dp(float px){ if(null==mDisplayMetrics){ mDisplayMetrics = mBindView.getResources().getDisplayMetrics(); } return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, px, mDisplayMetrics); } void parseData(JSONObject obj,int parentWidth,int parentHeight,float scale){ scale = 3.0f; mJsonData = obj; mParentWidth = parentWidth; mParentHeight = parentHeight; mArcColor = 0xff2BD009; mArrowColor = mArcColor; mCircleShadeColor = 0xDDDDDDDD; mDrawerWidth = px2dp(40); mDrawerHeight = px2dp(40); mArcStrokeWidth = px2dp(2); mCircleShadeStrokeWidth = px2dp(2f); F_Arrow_Max_Height = (int)px2dp(5); mCha = (int)px2dp(11); mAutoBackV = (int)px2dp(7); mArcRectF = new RectF(); mRefreshEnableOffsetY = convertToScreenInt(obj.optString("height"), parentWidth, mRefreshEnableOffsetY, scale); mRefreshRefreshingOffsetMaxY = convertToScreenInt(obj.optString("range"), parentWidth, mRefreshRefreshingOffsetMaxY, scale); mOffsetY = convertToScreenInt(obj.optString("offset"), parentWidth, mOffsetY, scale); mRefreshOffsetY = 0; reset(); mDrawerYDefault = mDrawerY; } private void reset(){ mDrawerX = (mParentWidth - mDrawerWidth ) / 2; mDrawerY = mOffsetY - mDrawerHeight;//绘制位置 mRefreshArcX = (int)mDrawerX + mCha; mRefreshArcY = (int)mDrawerY + mCha; mRefreshArcSweepAngle = 0; mRefreshArcWidth = (int)mDrawerWidth - mCha * 2; mRefreshArcHeight = (int)mDrawerHeight - mCha * 2; mRefreshOffsetY = mOffsetY; mArcRotateAngle = 0; mRefreshRotate = 0; mArrowHeight = 0; mArcScale = 1f; mArcColorAlpha = F_ArcColorAlphaMin; mArcRectF.left = mRefreshArcX; mArcRectF.right = mRefreshArcX + mRefreshArcWidth; mArcRectF.top = mRefreshArcY; mArcRectF.bottom = mRefreshArcY + mRefreshArcHeight; mHandle = false; } public void onResize(int parentWidth,int parentHeight,float scale){ parseData(mJsonData,parentWidth,parentHeight,scale); } protected void paint(Canvas canvas,int left, int top) { canvas.save(); canvas.translate(left, top); onDraw(canvas); canvas.restore(); } boolean isRefreshing(){ return mRefreshState == State_Refresh_End || mRefreshState == State_Refreshing; } protected void onDraw(Canvas canvas) { if(mArcScale < 0){ return; } canvas.save(); // Rect rect = new Rect(); // mBindView.getDrawingRect(rect); canvas.translate(mBindView.getScrollX() + mBindView.getLeft(), mBindView.getScrollY() + mBindView.getTop()); // canvas.translate(rect.left, rect.top); canvas.clipRect(mDrawerX - mArcStrokeWidth, mOffsetY, mDrawerX + mDrawerWidth + mArcStrokeWidth, mRefreshRefreshingOffsetMaxY + mDrawerHeight); // canvas.clipRect(mDrawerX, mRefreshOffsetY, mDrawerX + mDrawerWidth, mRefreshOffsetY + mDrawerHeight); {//调试 数据 // paint.setColor(Color.BLUE); // canvas.drawLine(0, mDrawerY, mParentWidth, mDrawerY, paint); // canvas.drawLine(0, mOffsetY, mParentWidth, mOffsetY, paint); // paint.setColor(Color.RED); // canvas.drawLine(0, mRefreshOffsetY, mParentWidth, mRefreshOffsetY, paint); // paint.setColor(Color.BLUE); // canvas.drawLine(0, mRefreshEnableOffsetY, mParentWidth, mRefreshEnableOffsetY, paint); // canvas.drawLine(0, mRefreshRefreshingOffsetMaxY, mParentWidth, mRefreshRefreshingOffsetMaxY, paint); // // paint.setColor(Color.BLACK); // paint.setStyle(Paint.Style.STROKE); // canvas.drawRect(mDrawerX, mOffsetY, mDrawerX + mDrawerWidth, mRefreshRefreshingOffsetMaxY + mDrawerHeight, paint); } // Logger.d("Drawer", "mArcRotateAngle=" + mArcRotateAngle + ";mArcRectF=" + mArcRectF + ";mDrawerY=" + mDrawerY + ";mAutoBack=" + mAutoBack + ";mRefreshRotate=" + mRefreshRotate); if(mRefreshState == State_Refresh_End ) { canvas.scale(mArcScale, mArcScale, mArcRectF.left + mArcRectF.width() / 2, mArcRectF.top + mArcRectF.height() / 2); mRunnableEndReFresh.run(); } if(mAutoBack){ mRunnableEndReFresh.run(); } drawCircleShade(canvas); canvas.rotate(mRefreshRotate, mDrawerX + mDrawerWidth / 2, mDrawerY + mDrawerHeight / 2); drawRefresh(canvas); canvas.restore(); if(mRefreshState == State_Refreshing){ mRunnableRefresh.run(); } } private void drawCircleShade(Canvas canvas){ paint.reset(); paint.setAntiAlias(true); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(mCircleShadeStrokeWidth); paint.setColor(mCircleShadeColor); canvas.drawCircle(mDrawerX + mDrawerWidth / 2, mDrawerY + mDrawerHeight / 2 + mCircleShadeStrokeWidth / 3 , mDrawerWidth / 2 - mCircleShadeStrokeWidth /2, paint);//绘制阴影 // paint.setColor(mCircleShadeColor | 0xFFCCCCCC); // canvas.drawCircle(mDrawerX + mDrawerWidth / 2, mDrawerY + mDrawerHeight / 2, mDrawerWidth / 2 - mCircleShadeStrokeWidth/2, paint);//绘制阴影 paint.setStyle(Paint.Style.FILL); paint.setColor(Color.WHITE); canvas.drawCircle(mDrawerX + mDrawerWidth / 2, mDrawerY + mDrawerHeight / 2, mDrawerWidth / 2 - mCircleShadeStrokeWidth /2, paint);//y 方向起始位置为0 } private void drawRefresh(Canvas canvas){ canvas.save(); mArcRectF.bottom = mRefreshArcY + mArcRectF.height(); mArcRectF.top = mRefreshArcY ; //设置整个旋转角度 canvas.rotate(mArcRotateAngle - 45, mArcRectF.left + mArcRectF.width() / 2, mArcRectF.top + mArcRectF.height() / 2); drawRefreshArc(canvas); if(mRefreshOffsetY != mRefreshEnableOffsetY // 未处在可刷新位置 ||( mRefreshState != State_Refreshing && mArcScale == 1)) {//刷新中,消失中均不绘制箭头 drawArrow(canvas); } canvas.restore(); } private void drawRefreshArc(Canvas canvas){ paint.reset(); paint.setColor(Color.argb(mArcColorAlpha, Color.red(mArcColor), Color.green(mArcColor), Color.blue(mArcColor))); paint.setAntiAlias(true); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(mArcStrokeWidth); canvas.drawArc(mArcRectF, mRefreshArcStartAngle, mRefreshArcSweepAngle, false, paint); } private void drawArrow(Canvas canvas){ canvas.save(); canvas.rotate(mRefreshArcSweepAngle, mArcRectF.left + mArcRectF.width() / 2, mArcRectF.top + mArcRectF.height() / 2);//进行旋转,与箭头尾巴随拖动转 canvas.translate(mArcRectF.right, mArcRectF.top + mArcRectF.height() / 2); paint.setAntiAlias(true); //绘制箭头 paint.setStyle(Paint.Style.FILL); mArrowPath.reset(); //等边直角三角形 mArrowPath.lineTo(-mArrowHeight, 0); mArrowPath.lineTo(0, mArrowHeight); mArrowPath.lineTo(mArrowHeight, 0); mArrowPath.close(); paint.setColor(Color.argb(mArcColorAlpha,Color.red(mArcColor),Color.green(mArcColor),Color.blue(mArcColor))); canvas.drawPath(mArrowPath, paint); canvas.restore(); } float mTouchDownX,mTouchDownY; boolean mHandle = false; public boolean onTouchEvent(MotionEvent event) { if(mRefreshState == State_Refreshing) return false; int action = event.getAction(); switch (action){ case MotionEvent.ACTION_DOWN: mTouchDownX = event.getX(); mLastMoveY = mTouchDownY = event.getY(); reset(); mHandle = true; break; case MotionEvent.ACTION_UP: if(mRefreshState == State_Enable){ setRefreshState(State_Refreshing); }else{ endRefresh(); } break; case MotionEvent.ACTION_MOVE: //change松手后的状态 if(event.getY() > mTouchDownY && event.getX() - mTouchDownX < 10){ mHandle = true; } mArcScale = 1; update(event.getX(),event.getY()); if(mRefreshOffsetY > mRefreshEnableOffsetY){//移动距离大于可刷新位置 refreshRotate(); setRefreshState(State_Enable); }else{ mRefreshState = State_Normal; } invalidate(); Log.d("Drawer","mDrawerY=" + mDrawerY + ";mRefreshOffsetY=" + mRefreshOffsetY + ";mRefreshArcSweepAngle=" + mRefreshArcSweepAngle + ";mArcRotateAngle=" + mArcRotateAngle); break; } return mHandle; } private void invalidate(){ // mBindView.invalidate(); mBindView.invalidate((int)mDrawerX, (int)mOffsetY, (int)(mDrawerX + mDrawerWidth), (int)(mRefreshRefreshingOffsetMaxY + mDrawerHeight)); // mBindView.invalidate((int)mDrawerX, (int)mRefreshOffsetY, (int)(mDrawerX + mDrawerWidth), (int)(mRefreshOffsetY + mDrawerHeight)); // mBindView.invalidate((int)mDrawerX, (int)mOffsetY, (int)(mDrawerX + mDrawerWidth), (int)(mDrawerX + mDrawerHeight)); } final static int mRefreshColorChangeAngle = 270; private int refreshColorRatio(){ return (255 - F_ArcColorAlphaMin) / (mRefreshArcSweepAngleMax - mRefreshColorChangeAngle); } private void updateRefreshColor(float moveY){ if(mRefreshArcSweepAngle > mRefreshColorChangeAngle) { mArcColorAlpha = F_ArcColorAlphaMin + (mRefreshArcSweepAngle - mRefreshColorChangeAngle) * refreshColorRatio(); if (mArcColorAlpha > 255) { mArcColorAlpha = 255; } else if (mArcColorAlpha < F_ArcColorAlphaMin) { mArcColorAlpha = F_ArcColorAlphaMin; } } } final static int mArrowHeightChangeAngle = 90; private float arrowHeightRatio(){ return (float)F_Arrow_Max_Height / (mRefreshArcSweepAngleMax - mArrowHeightChangeAngle) ; } private void updateArrowHeight(float moveY){ if(mRefreshArcSweepAngle > mArrowHeightChangeAngle) { mArrowHeight = (int)((mRefreshArcSweepAngle - mArrowHeightChangeAngle) * arrowHeightRatio());//计算箭头高度 if (mArrowHeight > F_Arrow_Max_Height) { mArrowHeight = F_Arrow_Max_Height; } else if (mArrowHeight < 0) { mArrowHeight = 0; } } } private void updateRefreshArcSweepAngle(){ float offsetY = (mRefreshOffsetY - mOffsetY); mRefreshArcSweepAngle = (int)( (offsetY) * arcRatio() ); if(mRefreshArcSweepAngle > mRefreshArcSweepAngleMax) { mRefreshArcSweepAngle = mRefreshArcSweepAngleMax; }else if(mRefreshArcSweepAngle < 0){ mRefreshArcSweepAngle = 0; } } private float yRatio(){ return 1.0f; } private float arcRatio(){ return (float) mRefreshArcSweepAngleMax / (mRefreshEnableOffsetY - mOffsetY) ; } private void update(float moveTouchX, float moveTouchY){ float offsetY = moveTouchY - mLastMoveY; float changeY = (int)((offsetY) * yRatio()); mRefreshOffsetY += changeY; if(mRefreshOffsetY > mRefreshRefreshingOffsetMaxY){ mRefreshOffsetY = mRefreshRefreshingOffsetMaxY; mDrawerY += (mRefreshRefreshingOffsetMaxY - mRefreshOffsetY); }else{ mDrawerY += changeY;//移动位置 } if(mRefreshOffsetY <= mRefreshRefreshingOffsetMaxY) { updateRefreshArcSweepAngle(); updateArrowHeight(moveTouchY); updateRefreshColor(moveTouchY); // Log.d("Drawer", "update mDrawerY=" + mDrawerY + ";mRefreshOffsetY=" + mRefreshOffsetY + ";mRefreshArcSweepAngle=" + mRefreshArcSweepAngle + ";mArcRotateAngle=" + mArcRotateAngle); } mRefreshArcY = (int) mDrawerY + mCha; mLastMoveY = moveTouchY; } private void setRefreshState(int state){ int t = mRefreshState; mRefreshState = state; if(t != state){ onRefreshStateChange(state); } } void endRefresh(){ if(mRefreshState == State_Refreshing){ setRefreshState(State_Refresh_End); }else{ mRunnableEndReFresh.run(); } } float mArcScale = 1; boolean mAutoBack = false; Runnable mRunnableEndReFresh = new Runnable() { @Override public void run() { // Log.d("Drawer","mArcScale=" + mArcScale + ";mDrawerY=" + mDrawerY); if(mRefreshState == State_Refresh_End) { if(mArcScale >= 0) { //缩放消失 mArcScale = mArcScale - 0.1f; refreshingRotate(); }else{ setRefreshState(State_Normal); } }else{ if(mDrawerY > mDrawerYDefault){//结束刷新 mAutoBack = true; update(-1, mLastMoveY - mAutoBackV); }else{ mAutoBack = false; setRefreshState(State_Normal); } } invalidate(); } }; boolean mSweepAngleUp = false; private void refreshingRotate(){ mArcRotateAngle += 7;//扭动画布 if(mArcRotateAngle >= 360){ mArcRotateAngle = 0; } if(mRefreshState == State_Refreshing) { if (mSweepAngleUp) { mRefreshArcSweepAngle += 5; if (mRefreshArcSweepAngle > mRefreshArcSweepAngleMax) { mRefreshArcSweepAngle = mRefreshArcSweepAngleMax; mSweepAngleUp = false; } } else { mRefreshArcSweepAngle -= 5; if (mRefreshArcSweepAngle < 50) { mRefreshArcSweepAngle = 50; mSweepAngleUp = true; } } }else{ mSweepAngleUp = false; } } int mRefreshRotate = 0; private void refreshRotate(){ int offset = (int)((mRefreshOffsetY - mRefreshEnableOffsetY) * refreshRotateRatio()); mRefreshRotate = offset; } private float refreshRotateRatio(){ return 270f / (mRefreshRefreshingOffsetMaxY - mRefreshEnableOffsetY); } Runnable mRunnableRefresh = new Runnable() { @Override public void run() { if (mRefreshState == State_Refreshing){ if(mRefreshOffsetY > mRefreshEnableOffsetY){//回退到松手可刷新位置 update(-1, mLastMoveY - mAutoBackV); if(mRefreshOffsetY - mRefreshEnableOffsetY < mAutoBackV){ mRefreshOffsetY = mRefreshEnableOffsetY; } }else{//在松手可刷新位置进行 转圈刷新 refreshingRotate(); } invalidate(); } } }; static final String STATE_CHANGED_TEMPLATE = "{status:'%s'}"; private void onRefreshStateChange(int newState){ switch (newState){ case State_Normal: reset(); // Log.d("Drawer","普通状态"); break; case State_Enable: // Log.d("Drawer","可刷新"); break; case State_Refreshing://启动刷新 mRunnableRefresh.run(); // Log.d("Drawer", "正在刷新"); mListener.onRefreshing(3); // mBindView.postDelayed(new Runnable() { // @Override // public void run() { // endRefresh(); // } // },3000); break; case State_Refresh_End:{ mRunnableEndReFresh.run(); // Log.d("Drawer","刷新结束"); break; } } } public static int convertToScreenInt(String pStrInt, int pRelInt, int pDeft,float scale){ try { if(pStrInt == null) return pDeft; if(pStrInt.endsWith("px")){ pStrInt = pStrInt.substring(0,pStrInt.length() - 2); if (pStrInt != null && pStrInt.contains(".")) { return (int)(Float.parseFloat(pStrInt) * scale); } return (int)(Integer.parseInt(pStrInt) * scale); } if(pStrInt.endsWith("%")){ pStrInt = pStrInt.substring(0,pStrInt.length() - 1); try { return pRelInt * Integer.parseInt(pStrInt) / 100; } catch (NumberFormatException e1) { return pDeft; } }else{//解决当pStrInt 为45.0时,Integer.parseInt异常的问题 return (int)(Double.parseDouble(pStrInt) * scale); } } catch (Exception e) {//非px值时 return pDeft; } } interface OnRefreshListener{ void onRefreshing(int state); } }
相关文章推荐
- Python:使用pycha快速绘制办公常用图二(使用样式定制个性化图表)
- Android项目:使用pulltorefresh开源项目扩展为下拉刷新上拉加载更多的处理方法,监听listview滚动方向 推荐
- RecyclerView支持下拉刷新上划加载,多种布局样式。RV集成框架使用(一)
- HBuilder MUI 使用扩展图标样式问题解决
- C# WinForm开发系列之c# 通过.net自带的chart控件绘制饼图,柱形图和折线图的基础使用和扩展
- 窗体样式使用WS_EX_LAYERED后,无法绘制windows控件的解决办法
- css三种样式引入方法,html链接,html中<table>的使用方法
- Android 更改下拉刷新(使用PulltoRefresh)的下拉动画样式
- C# WinForm开发系列之c# 通过.net自带的chart控件绘制饼图,柱形图和折线图的基础使用和扩展
- sencha touch 扩展篇之使用sass自定义主题样式 (上)使用官方的api修改主题样式
- android app开发,如何使用/引入第三方扩展jar
- iOS UITableView扩展样式使用之初级剑客篇(欢迎提建议和分享遇到的问题)
- 关于polymer app无法再子页面内使用父页面引入的样式(更新中)
- 使用jTopo给Html5 Canva中绘制的元素添加鼠标事件_html5教程技巧
- Python:使用pycha快速绘制办公常用图二(使用样式定制个性化图表)
- Android项目:使用pulltorefresh开源项目扩展为下拉刷新上拉加载更多的处理方法,监听listview滚动方向
- sencha touch 扩展篇之使用sass自定义主题样式 (下)通过css修改官方组件样式以及自定义图标
- C# WinForm开发系列之c# 通过.net自带的chart控件绘制饼图,柱形图和折线图的基础使用和扩展
- 使用jTopo给Html5 Canva中绘制的元素添加鼠标事件_html5教程技巧
- sencha touch 扩展篇之使用sass自定义主题样式 (上)使用官方的api修改主题样式