android自定義控件實現簡易時間軸(1)
本文實例為大傢分享瞭android自定義控件實現簡易時間軸的具體代碼,供大傢參考,具體內容如下
之前項目需要寫一個消費記錄,類似於時間軸似的控件,自身在自定義控件這裡不咋地(…),最後搞瞭一個這個demo
效果圖:
這裡就是繪制圓和上下兩條線
1.資源文件,定義一些基本的屬性:
<?xml version="1.0" encoding="utf-8"?> <resources> <attr name="textSize" format="dimension" /> <attr name="textColor" format="color" /> <attr name="textTitle" format="string" /> <attr name="borderColor" format="color" /> <attr name="borderWidth" format="dimension" /> <attr name="lineColor" format="color" /> <attr name="lineWidth" format="dimension" /> <attr name="bgColor" format="color" /> <attr name="mRadius" format="dimension"/> <declare-styleable name="CustomCicleView"> <attr name="textSize" /> <attr name="textColor" /> <attr name="textTitle" /> <attr name="lineColor" /> <attr name="lineWidth" /> <attr name="bgColor" /> <attr name="borderColor" /> <attr name="borderWidth" /> <attr name="mRadius" /> </declare-styleable> </resources>
2.獲取屬性:
int attr=a.getIndex(i); switch (attr) { case R.styleable.CustomCicleView_textSize: // 默認設置為16sp,TypeValue也可以把sp轉化為px mTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_PX, 14, getResources().getDisplayMetrics())); break; case R.styleable.CustomCicleView_textColor: mTextColor=a.getColor(attr, Color.BLACK); break; case R.styleable.CustomCicleView_lineWidth: mLineWidth= a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_PX, 2, getResources().getDisplayMetrics())); break; case R.styleable.CustomCicleView_lineColor: mLineColor=a.getColor(attr, lineColr); break; case R.styleable.CustomCicleView_borderWidth: mBorderWidth= a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_PX, 2, getResources().getDisplayMetrics())); break; case R.styleable.CustomCicleView_borderColor: mBorderColor=a.getColor(attr, borderColor); break; case R.styleable.CustomCicleView_bgColor: mBgColor=a.getColor(attr, bgColor); break; }
這裡主要釋放資源方便回收:
a.recycle(); //官方API的解釋是:給回一個先前的提取的數組,為以後復用,,就是當前的對象回收,下次要用的時候就不用重新再new一個新的對象瞭,直接從它的回收池裡面拿就行。 public void recycle (): Give back a previously retrieved array, for later re-use
3.重要繪制代碼:
super.onDraw(canvas); int centre = getWidth() / 2; // 獲取圓心的x坐標 //半徑比較 int mixWidth=getMeasuredWidth()>getMeasuredHeight()?getMeasuredHeight():getMeasuredWidth(); mRadius =mRadius>(mixWidth)?(mixWidth):mRadius; mBorderWidth =mRadius/2>=(mBorderWidth)?(mBorderWidth):mRadius/10;//最終的效果要不是自己設置的要不就是半徑的1/5 int radius = mRadius/2 - mBorderWidth / 2;// 半徑 mLineHeight=Math.abs(getHeight()/2-radius);//這個地方要判斷設置正負 if(lineLocation!=-1){ drawLine(canvas,centre); } //繪制背景 bgPaint.setColor(Color.parseColor("#00000000")); bgPaint.setTextSize(mTextSize); canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), bgPaint); //繪制圓 bgPaint.setAntiAlias(true); // 消除鋸齒 bgPaint.setColor(mBgColor); bgPaint.setStyle(Paint.Style.FILL); // 設置實心 canvas.drawCircle(centre, centre, radius, bgPaint); //繪制圓環 borderPaint.setStrokeWidth(mBorderWidth); // 設置圓環的寬度 borderPaint.setAntiAlias(true); // 消除鋸齒 if (mBorderColor != 0) { borderPaint.setColor(mBorderColor); } else { borderPaint.setColor(borderColor); } borderPaint.setStyle(Paint.Style.STROKE); // 設置實心 canvas.drawCircle(centre,centre, radius - mBorderWidth / 2+mLineWidth/2, borderPaint); //繪制文本 bgPaint.setColor(mTextColor); textPaint.getTextBounds(mTextTitle, 0, mTextTitle.length(), textRect); canvas.drawText(mTextTitle, centre -textRect.width()/2, centre + textRect.height() / 2, bgPaint);
這裡給瞭一個int值來判斷當前需要繪制那個位置的line;值是0隻需繪制 上方line,值是 1隻需繪制下方line,值是2同事繪制上下方line,值是-1不需繪制line;這個值由用戶使用的時候傳遞過來這樣就可以繪制對應的line
//0 上方 1 下方 2 上下兩個 private void drawLine(Canvas canvas, float centre) { linePaint.setColor(borderColor); linePaint.setStrokeWidth(mLineWidth); if (lineLocation == 0) { // canvas.drawLine(centre, 0.5F*centre-mLineHeight, centre, centre, linePaint); canvas.drawLine(centre, 0, centre, mLineHeight*2, linePaint); } else if (lineLocation == 1) { canvas.drawLine(centre, centre, centre, centre * 2F + mLineHeight, linePaint); } else if (lineLocation == 2) { // canvas.drawLine(centre, mRadius * 0.5F - mLineHeight-mBorderWidth, centre, mLineHeight, linePaint); canvas.drawLine(centre, 0, centre, mLineHeight*2, linePaint); canvas.drawLine(centre, centre, centre, centre * 2F + mLineHeight, linePaint); } }
4.使用
這裡的使用有兩種,一種是在xml中直接佈局,設置屬性,一種是在代碼中初始化然後根據提供的set方法來設置相應的屬性。
在你佈局中使用的時候要加上
xmlns:app=”http://schemas.android.com/apk/res/com.example.circleview”
com.example.circleview:是包名
這樣你就可以設置這個控件的屬性瞭
<com.example.circleview.CircleImg android:id="@+id/itemImg" android:layout_width="100dp" android:layout_height="100dp" android:layout_margin="2dp" app:bgColor="#f88" app:borderColor="#138ddd" app:textColor="#fff" app:textSize="12dp" />
最終效果:
基本的一個圓就好瞭,現在來實現開始的時候的效果圖,基本就是用listView實現:
佈局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res/com.example.circleview" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="5dp" android:orientation="vertical" tools:context="com.example.circleview.MainActivity" > <ListView android:id="@+id/listView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:divider="#00000000" android:dividerHeight="0dp" > </ListView> </LinearLayout>
MainActivity.java:
public class MainActivity extends Activity { private List<String> list=new ArrayList<String>(); ListView listView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initData(); listView=(ListView) findViewById(R.id.listView); listView.setAdapter(new TimeLineAdapter(list, this)); } private void initData() { for (int i =11; i >1; i--) {//時間從小到大 list.add("05/"+i); } } }
Adapter:
public class TimeLineAdapter extends BaseAdapter { private static final int[] COLOR = new int[] { 0xff33b5e5, 0xffaa66cc, 0xff99cc00, 0xffffbb33, 0xffff4444,0xff009933,0xffff9988, 0xffffddcc,0xff00ffff,0xffffff00 }; private List<String> list; private Context context; private ViewHolder holder; public TimeLineAdapter(List<String> list, Context context) { super(); this.list = list; this.context = context; } @Override public int getCount() { // TODO Auto-generated method stub return list.size(); } @Override public Object getItem(int position) { // TODO Auto-generated method stub return list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { int type = getItemViewType(position); if(convertView==null){ convertView=View.inflate(context, R.layout.item,null); holder=new ViewHolder(); convertView.setTag(holder); holder.img=(CircleImg) convertView.findViewById(R.id.itemImg); holder.item=(TextView) convertView.findViewById(R.id.itemText); }else{ holder=(ViewHolder) convertView.getTag(); } holder.img.setBgAndBorderColor(COLOR[position%10]); holder.img.invalidate();//記得重繪 holder.img.setLineLocation(type); holder.img.setmTextTitle(list.get(position)); holder.item.setText("哈哈哈哈哈哈哈哈"); return convertView; } @Override public int getItemViewType(int position) { final int size = list.size() - 1; if (size == 0) return ItemType.ATOM; else if (position == 0) return ItemType.FOOTER; else if (position == size) return ItemType.HEADER; else return ItemType.NORMAL; } class ViewHolder{ TextView item; CircleImg img; } }
這裡繪制上下line的時候是通過getItemViewType()返回的view id值來判斷的,ItemType中有四個變量:
public final static int NORMAL = 2; //表示繪制上下方 public final static int HEADER = 0; //表示繪制下方 public final static int FOOTER = 1; //表示繪制上方 public final static int ATOM = -1; //表示不繪制
然後通過holder.img.setLineLocation(type);來設置當前繪制的line。
CIcleVIew.java下:
/** * Created by yqy on 2016/11/28. */ public class CircleImg extends View { //畫筆 private Paint bgPaint, linePaint, borderPaint,textPaint; private Rect bgRect, textRect; //基本屬性 private int mTextSize; private int mTextColor; private String mTextTitle; private int lineColr = Color.parseColor("#AAAAAA"); private int borderColor = Color.parseColor("#AAAAAA"); private int bgColor = Color.parseColor("#138DDD"); private int mBorderColor; private int mBorderWidth = 2; private int mLineColor; private int mLineWidth = 2; private int mLineHeight; private int mBgColor; //line繪制 private int lineLocation = -1;//0 上方 1 下方 2 上下兩個 private int mRadius = 40; public CircleImg(Context context) { this(context, null); } //設置line的位置 0 上方 1 下方 2 上下兩個 public void setLineLocation(int lineLocation) { this.lineLocation = lineLocation; } //設置純色的整圓形,包括背景 public void setBgAndBooderCOlor(int color) { this.mBorderColor = color; this.mBgColor = color; } public void setmTextTitle(String mTextTitle) { this.mTextTitle = mTextTitle; } public void setmRadius(int mRadius) { this.mRadius = mRadius; } public CircleImg(Context context, AttributeSet attrs) { this(context, attrs, 0); // TODO Auto-generated constructor stub } public CircleImg(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomCicleView, defStyle, 0); int n = a.getIndexCount(); for (int i = 0; i < n; i++) { int attr = a.getIndex(i); switch (attr) { case R.styleable.CustomCicleView_textSize: // 默認設置為16sp,TypeValue也可以把sp轉化為px mTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_PX, 14, getResources().getDisplayMetrics())); break; case R.styleable.CustomCicleView_textColor: mTextColor = a.getColor(attr, Color.BLACK); break; case R.styleable.CustomCicleView_textTitle: mTextTitle = a.getString(attr); break; case R.styleable.CustomCicleView_lineWidth: mLineWidth = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_PX, 2, getResources().getDisplayMetrics())); break; case R.styleable.CustomCicleView_lineColor: mLineColor = a.getColor(attr, lineColr); break; case R.styleable.CustomCicleView_mRadius: mRadius=a.getInt(attr,40); break; case R.styleable.CustomCicleView_borderWidth: mBorderWidth = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_PX, 2, getResources().getDisplayMetrics())); break; case R.styleable.CustomCicleView_borderColor: mBorderColor = a.getColor(attr, borderColor); break; case R.styleable.CustomCicleView_bgColor: mBgColor = a.getColor(attr, bgColor); break; } } a.recycle(); bgPaint = new Paint(); borderPaint = new Paint(); linePaint = new Paint(); textPaint = new Paint(); textRect = new Rect(); textPaint.setTextSize(mTextSize); } //暫時不計算 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int w = getPaddingLeft() + getPaddingRight(); int h = getPaddingTop() + getPaddingBottom(); if (bgPaint != null) { w += mRadius; h += mRadius; } w = Math.max(w, getMeasuredWidth()); h = Math.max(h, getMeasuredHeight()); int widthSize = resolveSizeAndState(w, widthMeasureSpec, 0); int heightSize = resolveSizeAndState(h, heightMeasureSpec, 0); setMeasuredDimension(widthSize, heightSize); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int centre = getWidth() / 2; // 獲取圓心的x坐標 int radius = mRadius - mBorderWidth / 2;// 半徑 mLineHeight=getHeight()/2-radius;//這個地方要判斷設置正負 if(lineLocation!=-1){ drawLine(canvas,centre); } //繪制背景 bgPaint.setColor(Color.parseColor("#00000000")); bgPaint.setTextSize(mTextSize); canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), bgPaint); //繪制圓 bgPaint.setAntiAlias(true); // 消除鋸齒 bgPaint.setColor(mBgColor); bgPaint.setStyle(Paint.Style.FILL); // 設置實心 canvas.drawCircle(centre, centre, radius, bgPaint); //繪制圓環 borderPaint.setStrokeWidth(mBorderWidth); // 設置圓環的寬度 borderPaint.setAntiAlias(true); // 消除鋸齒 if (mBorderColor != 0) { borderPaint.setColor(mBorderColor); } else { borderPaint.setColor(borderColor); } borderPaint.setStyle(Paint.Style.STROKE); // 設置實心 canvas.drawCircle(centre,centre, radius - mBorderWidth / 2+mLineWidth/2, borderPaint); //繪制文本 bgPaint.setColor(mTextColor); textPaint.getTextBounds(mTextTitle, 0, mTextTitle.length(), textRect); canvas.drawText(mTextTitle, centre -textRect.width()/2, centre + textRect.height() / 2, bgPaint); } //0 上方 1 下方 2 上下兩個 private void drawLine(Canvas canvas, float centre) { linePaint.setColor(borderColor); linePaint.setStrokeWidth(mLineWidth); if (lineLocation == 0) { canvas.drawLine(centre, centre, centre, centre * 2F + mLineHeight, linePaint); } else if (lineLocation == 1) { canvas.drawLine(centre, 0, centre, mLineHeight*2, linePaint); } else if (lineLocation == 2) { canvas.drawLine(centre, 0, centre, mLineHeight*2, linePaint); canvas.drawLine(centre, centre, centre, centre * 2F + mLineHeight, linePaint); } } }
styleable.xml:
<?xml version="1.0" encoding="utf-8"?> <resources> <attr name="textSize" format="dimension" /> <attr name="textColor" format="color" /> <attr name="textTitle" format="string" /> <attr name="borderColor" format="color" /> <attr name="borderWidth" format="dimension" /> <attr name="lineColor" format="color" /> <attr name="lineWidth" format="dimension" /> <attr name="bgColor" format="color" /> <attr name="mRadius" format="dimension"/> <declare-styleable name="CustomCicleView"> <attr name="textSize" /> <attr name="textColor" /> <attr name="textTitle" /> <attr name="lineColor" /> <attr name="lineWidth" /> <attr name="bgColor" /> <attr name="borderColor" /> <attr name="borderWidth" /> <attr name="mRadius" /> </declare-styleable> </resources>
簡易時間軸二
以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。
推薦閱讀:
- android自定義控件實現簡易時間軸(2)
- android自定義帶箭頭對話框
- Android如何實現動態滾動波形圖(心電圖)功能
- Android 實現數字九宮格軟鍵盤
- Android自定義view實現圓環進度條效果