編輯:關於Android編程
StepView(步驟流程的view)
效果圖如下:
該控件可以支持這種步驟的操作view展示,像快遞app的流程。
1.首先有在xml布局:
2 .一個自定義的HorizontalStepView:
public class HorizontalStepView extends LinearLayout implements HorizontalStepsViewIndicator.OnDrawIndicatorListener
{
private RelativeLayout mTextContainer;
private HorizontalStepsViewIndicator mStepsViewIndicator;
private List mTexts;
private int mComplectingPosition;
private int mUnComplectedTextColor = ContextCompat.getColor(getContext(), R.color.uncompleted_text_color);//定義默認未完成文字的顏色;
private int mComplectedTextColor = ContextCompat.getColor(getContext(), android.R.color.white);//定義默認完成文字的顏色;
public HorizontalStepView(Context context)
{
this(context, null);
}
public HorizontalStepView(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public HorizontalStepView(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
init();
}
private void init()
{
View rootView = LayoutInflater.from(getContext()).inflate(R.layout.widget_horizontal_stepsview, this);
mStepsViewIndicator = (HorizontalStepsViewIndicator) rootView.findViewById(R.id.steps_indicator);
mStepsViewIndicator.setOnDrawListener(this);
mTextContainer = (RelativeLayout) rootView.findViewById(R.id.rl_text_container);
mTextContainer.removeAllViews();
}
/**
* 設置顯示的文字
*
* @param texts
* @return
*/
public HorizontalStepView setStepViewTexts(List texts)
{
mTexts = texts;
mStepsViewIndicator.setStepNum(mTexts.size());
return this;
}
/**
* 設置正在進行的position
*
* @param complectingPosition
* @return
*/
public HorizontalStepView setStepsViewIndicatorComplectingPosition(int complectingPosition)
{
mComplectingPosition = complectingPosition;
mStepsViewIndicator.setComplectingPosition(complectingPosition);
return this;
}
/**
* 設置未完成文字的顏色
*
* @param unComplectedTextColor
* @return
*/
public HorizontalStepView setStepViewUnComplectedTextColor(int unComplectedTextColor)
{
mUnComplectedTextColor = unComplectedTextColor;
return this;
}
/**
* 設置完成文字的顏色
*
* @param complectedTextColor
* @return
*/
public HorizontalStepView setStepViewComplectedTextColor(int complectedTextColor)
{
this.mComplectedTextColor = complectedTextColor;
return this;
}
/**
* 設置StepsViewIndicator未完成線的顏色
*
* @param unCompletedLineColor
* @return
*/
public HorizontalStepView setStepsViewIndicatorUnCompletedLineColor(int unCompletedLineColor)
{
mStepsViewIndicator.setUnCompletedLineColor(unCompletedLineColor);
return this;
}
/**
* 設置StepsViewIndicator完成線的顏色
*
* @param completedLineColor
* @return
*/
public HorizontalStepView setStepsViewIndicatorCompletedLineColor(int completedLineColor)
{
mStepsViewIndicator.setCompletedLineColor(completedLineColor);
return this;
}
/**
* 設置StepsViewIndicator默認圖片
*
* @param defaultIcon
*/
public HorizontalStepView setStepsViewIndicatorDefaultIcon(Drawable defaultIcon)
{
mStepsViewIndicator.setDefaultIcon(defaultIcon);
return this;
}
/**
* 設置StepsViewIndicator已完成圖片
*
* @param completeIcon
*/
public HorizontalStepView setStepsViewIndicatorCompleteIcon(Drawable completeIcon)
{
mStepsViewIndicator.setCompleteIcon(completeIcon);
return this;
}
/**
* 設置StepsViewIndicator正在進行中的圖片
*
* @param attentionIcon
*/
public HorizontalStepView setStepsViewIndicatorAttentionIcon(Drawable attentionIcon)
{
mStepsViewIndicator.setAttentionIcon(attentionIcon);
return this;
}
@Override
public void ondrawIndicator()
{
List complectedXPosition = mStepsViewIndicator.getCircleCenterPointPositionList();
if(mTexts != null)
{
for(int i = 0; i < mTexts.size(); i++)
{
TextView textView = new TextView(getContext());
textView.setText(mTexts.get(i));
textView.setX(complectedXPosition.get(i) - mStepsViewIndicator.getCircleRadius() - 10);//這裡的-10是將文字進行調整居中,稍後再動態修改
textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
if(i <= mComplectingPosition)
{
textView.setTypeface(null, Typeface.BOLD);
textView.setTextColor(mComplectedTextColor);
} else
{
textView.setTextColor(mUnComplectedTextColor);
}
mTextContainer.addView(textView);
}
}
}
}
該view把需要設置的東西屬性,都通過set進去。提供了好多需要的公共方法屬性。
3.HorizontalStepView中包括了兩個view一個是繪制圖標的view(HorizontalStepsViewIndicator)和一個包含所有的文字的view(RelativeLayout)
其中HorizontalStepsViewIndicator的代碼如下:
public class HorizontalStepsViewIndicator extends View
{
//定義默認的高度 definition default height
private int defaultStepIndicatorNum = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 40, getResources().getDisplayMetrics());
private float mCompletedLineHeight;//完成線的高度 definition completed line height
private float mCircleRadius;//圓的半徑 definition circle radius
private Drawable mCompleteIcon;//完成的默認圖片 definition default completed icon
private Drawable mAttentionIcon;//正在進行的默認圖片 definition default underway icon
private Drawable mDefaultIcon;//默認的背景圖 definition default unCompleted icon
private float mCenterY;//該view的Y軸中間位置 definition view centerY position
private float mLeftY;//左上方的Y位置 definition rectangle LeftY position
private float mRightY;//右下方的位置 definition rectangle RightY position
private int mStepNum = 0;//當前有幾部流程 there are currently few step
private float mLinePadding;//兩條連線之間的間距 definition the spacing between the two circles
private List mCircleCenterPointPositionList;//定義所有圓的圓心點位置的集合 definition all of circles center point list
private Paint mUnCompletedPaint;//未完成Paint definition mUnCompletedPaint
private Paint mCompletedPaint;//完成paint definition mCompletedPaint
private int mUnCompletedLineColor = ContextCompat.getColor(getContext(), R.color.uncompleted_color);//定義默認未完成線的顏色 definition mUnCompletedLineColor
private int mCompletedLineColor = Color.WHITE;//定義默認完成線的顏色 definition mCompletedLineColor
private PathEffect mEffects;
private int mComplectingPosition;//正在進行position underway position
private Path mPath;
private OnDrawIndicatorListener mOnDrawListener;
/**
* 設置監聽
*
* @param onDrawListener
*/
public void setOnDrawListener(OnDrawIndicatorListener onDrawListener)
{
mOnDrawListener = onDrawListener;
}
/**
* get圓的半徑 get circle radius
*
* @return
*/
public float getCircleRadius()
{
return mCircleRadius;
}
public HorizontalStepsViewIndicator(Context context)
{
this(context, null);
}
public HorizontalStepsViewIndicator(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public HorizontalStepsViewIndicator(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
init();
}
/**
* init
*/
private void init()
{
mPath = new Path();
mEffects = new DashPathEffect(new float[]{8, 8, 8, 8}, 1);
mCircleCenterPointPositionList = new ArrayList<>();//初始化
mUnCompletedPaint = new Paint();
mCompletedPaint = new Paint();
mUnCompletedPaint.setAntiAlias(true);
mUnCompletedPaint.setColor(mUnCompletedLineColor);
mUnCompletedPaint.setStyle(Paint.Style.STROKE);
mUnCompletedPaint.setStrokeWidth(2);
mCompletedPaint.setAntiAlias(true);
mCompletedPaint.setColor(mCompletedLineColor);
mCompletedPaint.setStyle(Paint.Style.STROKE);
mCompletedPaint.setStrokeWidth(2);
mUnCompletedPaint.setPathEffect(mEffects);
mCompletedPaint.setStyle(Paint.Style.FILL);
//已經完成線的寬高 set mCompletedLineHeight
mCompletedLineHeight = 0.05f * defaultStepIndicatorNum;
//圓的半徑 set mCircleRadius
mCircleRadius = 0.28f * defaultStepIndicatorNum;
//線與線之間的間距 set mLinePadding
mLinePadding = 0.85f * defaultStepIndicatorNum;
mCompleteIcon = ContextCompat.getDrawable(getContext(), R.drawable.complted);//已經完成的icon
mAttentionIcon = ContextCompat.getDrawable(getContext(), R.drawable.attention);//正在進行的icon
mDefaultIcon = ContextCompat.getDrawable(getContext(), R.drawable.default_icon);//未完成的icon
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int width = defaultStepIndicatorNum * 2;
if(MeasureSpec.UNSPECIFIED != MeasureSpec.getMode(widthMeasureSpec))
{
width = MeasureSpec.getSize(widthMeasureSpec);
}
int height = defaultStepIndicatorNum;
if(MeasureSpec.UNSPECIFIED != MeasureSpec.getMode(heightMeasureSpec))
{
height = Math.min(height, MeasureSpec.getSize(heightMeasureSpec));
}
setMeasuredDimension(width, height);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
//獲取中間的高度,目的是為了讓該view繪制的線和圓在該view垂直居中 get view centerY,keep current stepview center vertical
mCenterY = 0.5f * getHeight();
//獲取左上方Y的位置,獲取該點的意義是為了方便畫矩形左上的Y位置
mLeftY = mCenterY - (mCompletedLineHeight / 2);
//獲取右下方Y的位置,獲取該點的意義是為了方便畫矩形右下的Y位置
mRightY = mCenterY + mCompletedLineHeight / 2;
for(int i = 0; i < mStepNum; i++)
{
//先計算全部最左邊的padding值(getWidth()-(圓形直徑+兩圓之間距離)*2)
float paddingLeft = (getWidth() - mStepNum * mCircleRadius * 2 - (mStepNum - 1) * mLinePadding) / 2;
//add to list
mCircleCenterPointPositionList.add(paddingLeft + mCircleRadius + i * mCircleRadius * 2 + i * mLinePadding);
}
/**
* set listener
*/
mOnDrawListener.ondrawIndicator();
}
@Override
protected synchronized void onDraw(Canvas canvas)
{
super.onDraw(canvas);
mOnDrawListener.ondrawIndicator();
mUnCompletedPaint.setColor(mUnCompletedLineColor);
mCompletedPaint.setColor(mCompletedLineColor);
//-----------------------畫線-------draw line-----------------------------------------------
for(int i = 0; i < mCircleCenterPointPositionList.size() - 1; i++)
{
//前一個ComplectedXPosition
final float preComplectedXPosition = mCircleCenterPointPositionList.get(i);
//後一個ComplectedXPosition
final float afterComplectedXPosition = mCircleCenterPointPositionList.get(i + 1);
if(i < mComplectingPosition)//判斷在完成之前的所有點
{
//判斷在完成之前的所有點,畫完成的線,這裡是矩形,很細的矩形,類似線,為了做區分,好看些
canvas.drawRect(preComplectedXPosition + mCircleRadius - 10, mLeftY, afterComplectedXPosition - mCircleRadius + 10, mRightY, mCompletedPaint);
} else
{
mPath.moveTo(preComplectedXPosition + mCircleRadius, mCenterY);
mPath.lineTo(afterComplectedXPosition - mCircleRadius, mCenterY);
canvas.drawPath(mPath, mUnCompletedPaint);
}
}
//-----------------------畫線-------draw line-----------------------------------------------
//-----------------------畫圖標-----draw icon-----------------------------------------------
for(int i = 0; i < mCircleCenterPointPositionList.size(); i++)
{
final float currentComplectedXPosition = mCircleCenterPointPositionList.get(i);
Rect rect = new Rect((int) (currentComplectedXPosition - mCircleRadius), (int) (mCenterY - mCircleRadius), (int) (currentComplectedXPosition + mCircleRadius), (int) (mCenterY + mCircleRadius));
if(i < mComplectingPosition)
{
mCompleteIcon.setBounds(rect);
mCompleteIcon.draw(canvas);
} else if(i == mComplectingPosition && mCircleCenterPointPositionList.size() != 1)
{
mCompletedPaint.setColor(Color.WHITE);
canvas.drawCircle(currentComplectedXPosition, mCenterY, mCircleRadius * 1.1f, mCompletedPaint);
mAttentionIcon.setBounds(rect);
mAttentionIcon.draw(canvas);
} else
{
mDefaultIcon.setBounds(rect);
mDefaultIcon.draw(canvas);
}
}
//-----------------------畫圖標-----draw icon-----------------------------------------------
}
/**
* 得到所有圓點所在的位置
*
* @return
*/
public List getCircleCenterPointPositionList()
{
return mCircleCenterPointPositionList;
}
/**
* 設置流程步數
*
* @param stepNum 流程步數
*/
public void setStepNum(int stepNum)
{
this.mStepNum = stepNum;
invalidate();
}
/**
* 設置正在進行position
*
* @param complectingPosition
*/
public void setComplectingPosition(int complectingPosition)
{
this.mComplectingPosition = complectingPosition;
invalidate();
}
/**
* 設置未完成線的顏色
*
* @param unCompletedLineColor
*/
public void setUnCompletedLineColor(int unCompletedLineColor)
{
this.mUnCompletedLineColor = unCompletedLineColor;
}
/**
* 設置已完成線的顏色
*
* @param completedLineColor
*/
public void setCompletedLineColor(int completedLineColor)
{
this.mCompletedLineColor = completedLineColor;
}
/**
* 設置默認圖片
*
* @param defaultIcon
*/
public void setDefaultIcon(Drawable defaultIcon)
{
this.mDefaultIcon = defaultIcon;
}
/**
* 設置已完成圖片
*
* @param completeIcon
*/
public void setCompleteIcon(Drawable completeIcon)
{
this.mCompleteIcon = completeIcon;
}
/**
* 設置正在進行中的圖片
*
* @param attentionIcon
*/
public void setAttentionIcon(Drawable attentionIcon)
{
this.mAttentionIcon = attentionIcon;
}
/**
* 設置對view監聽
*/
public interface OnDrawIndicatorListener
{
void ondrawIndicator();
}
}
這個類是關鍵點,其中onDraw方法中 就是繪制圖標核心:
//-----------------------畫線-------draw line-----------------------------------------------
for(int i = 0; i < mCircleCenterPointPositionList.size() - 1; i++)
{
//前一個ComplectedXPosition
final float preComplectedXPosition = mCircleCenterPointPositionList.get(i);
//後一個ComplectedXPosition
final float afterComplectedXPosition = mCircleCenterPointPositionList.get(i + 1);
if(i < mComplectingPosition)//判斷在完成之前的所有點
{
//判斷在完成之前的所有點,畫完成的線,這裡是矩形,很細的矩形,類似線,為了做區分,好看些
canvas.drawRect(preComplectedXPosition + mCircleRadius - 10, mLeftY, afterComplectedXPosition - mCircleRadius + 10, mRightY, mCompletedPaint);
} else
{
mPath.moveTo(preComplectedXPosition + mCircleRadius, mCenterY);
mPath.lineTo(afterComplectedXPosition - mCircleRadius, mCenterY);
canvas.drawPath(mPath, mUnCompletedPaint);
}
}
//-----------------------畫線-------draw line-----------------------------------------------
//-----------------------畫圖標-----draw icon-----------------------------------------------
for(int i = 0; i < mCircleCenterPointPositionList.size(); i++)
{
final float currentComplectedXPosition = mCircleCenterPointPositionList.get(i);
Rect rect = new Rect((int) (currentComplectedXPosition - mCircleRadius), (int) (mCenterY - mCircleRadius), (int) (currentComplectedXPosition + mCircleRadius), (int) (mCenterY + mCircleRadius));
if(i < mComplectingPosition)
{
mCompleteIcon.setBounds(rect);
mCompleteIcon.draw(canvas);
} else if(i == mComplectingPosition && mCircleCenterPointPositionList.size() != 1)
{
mCompletedPaint.setColor(Color.WHITE);
canvas.drawCircle(currentComplectedXPosition, mCenterY, mCircleRadius * 1.1f, mCompletedPaint);
mAttentionIcon.setBounds(rect);
mAttentionIcon.draw(canvas);
} else
{
mDefaultIcon.setBounds(rect);
mDefaultIcon.draw(canvas);
}
}
//-----------------------畫圖標-----draw icon-----------------------------------------------
這裡把畫線和畫圖標分開了。
到此該view的基本功能都已實現,具體還可以拓展的,以後在說,在學習。
事件分發在Android中非常重要,在滑動沖突,下拉刷新,嵌套滑動的時候都需要非常清楚事件分發的機制,才能寫好對應的處理代碼。曾經以為我對事件分發已經很清楚了,也寫過幾篇
我們經常看到使用了ViewPager的App,在每頁上面都會有一個滑塊來標志當前處於哪一頁。在PagerView包裡有android.support.v4.view.Pa
要畫這種圓形帶陰影的頭像,個人分解成三個圖層1,先畫頭像邊緣的漸變RadialGradient gradient = new RadialGradient(j/2,k/2
什麼是RecyclerViewRecyclerView是Android 5.0 materials design中的組件之一,相應的還有CardView、Palette等