Android開發之天氣趨勢折線圖_Android

來源:互聯網
上載者:User

先來看下效果:

控制項內容比較簡單,就是一個普通的折線圖,上下分別帶有數字,點擊的時候顯示當天溫度的差值。 

建立一個類繼承自View,並添加兩個構造方法:

public class TrendGraph extends View {  public TrendGraph(Context context) { // 在java代碼中建立調用    super(context);  }  public TrendGraph(Context context, AttributeSet attrs) { // 在xml中建立調用    super(context, attrs);  }} 

因為這裡不需要考慮wrap_content的情況,所以onMeasure方法不需重寫,關鍵的是onDraw,而onDraw方法其實也不困難,只需要確定好每個點的具體位置就好,因為連線也是需要點的座標,代碼比較囉嗦,可以略過:

   @Override   protected void onDraw(Canvas canvas) {     super.onDraw(canvas);     if (mElements == null || mElements.size() == 0) {       return;     }     double max_up = getMaxUp();     double min_down = getMinDown();     canvas.setDrawFilter(mDrawFilter);     mPaint.setStrokeWidth(lineWeith);     float width = getWidth();     float grap = width / mElements.size();     float textSize = mTextPaint.getTextSize();     int textMargin = circleRadius * 2;     float margin_top = textSize + 2 * textMargin;     Log.d(TAG, "onDraw: " + margin_top + "|" + textSize);     float height = getHeight() - 2 * margin_top;      for (int i = 0; i < mElements.size() - 1; i++) {       float startX = i * grap + grap / 2;       float stopX = (i + 1) * grap + grap / 2;       float startY = (float) (max_up - mElements.get(i).getUp()) / (float) (max_up -           min_down) * height + margin_top;       float stopY = (float) (max_up - mElements.get(i + 1).getUp()) / (float) (max_up -           min_down) * height + margin_top;        canvas.drawText((int) mElements.get(i).getUp() + "℃", startX - textSize, startY -           textMargin, mTextPaint);       canvas.drawCircle(startX, startY, circleRadius, mPaint);       canvas.drawLine(startX, startY, stopX, stopY, mPaint);       if (i == mElements.size() - 2) {         canvas.drawText((int) mElements.get(i + 1).getUp() + "℃", stopX - textSize, stopY             - textMargin, mTextPaint);         canvas.drawCircle(stopX, stopY, circleRadius, mPaint);       }        startY = (float) (max_up - mElements.get(i).getDown()) / (float) (max_up - min_down) *           height + margin_top;       stopY = (float) (max_up - mElements.get(i + 1).getDown()) / (float) (max_up -           min_down) * height + margin_top;       canvas.drawText((int) mElements.get(i).getDown() + "℃", startX - textSize, startY +           textSize + textMargin, mTextPaint);       canvas.drawCircle(startX, startY, circleRadius, mPaint);       canvas.drawLine(startX, startY, stopX, stopY, mPaint);       if (i == mElements.size() - 2) {         canvas.drawText((int) mElements.get(i + 1).getDown() + "℃", stopX - textSize,             stopY + textSize + textMargin, mTextPaint);         canvas.drawCircle(stopX, stopY, circleRadius, mPaint);       }     }   }

考慮到需要允許使用者進行簡單的設定,例如點的大小,文字大小等等,所以定義一些自訂屬性(res/values/attr.xml):

<?xml version="1.0" encoding="utf-8"?><resources>  <declare-styleable name="TrendGraph">    <attr name="lineWidth" format="dimension"/>    <attr name="circleRadius" format="dimension" />    <attr name="textSize" format="dimension" />    <attr name="textColor" format="reference" />  </declare-styleable></resources>

format指該屬性的格式,指定為dimension則是尺寸,取值單位是dp、sp或px等等,而reference則是引用,即一般在xml中引用其他資源的寫法,如@string/app_name。還有其他類型,可以自行尋找文檔。 

對自訂屬性進行解析得到,這個解析需要在上面定義的第二個構造方法中進行,代碼如下:

  public TrendGraph(Context context, AttributeSet attrs) {    super(context, attrs);    TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.TrendGraph);    circleRadius = array.getDimensionPixelSize(R.styleable.TrendGraph_circleRadius, 5);    lineWeith = array.getDimensionPixelSize(R.styleable.TrendGraph_lineWidth, 3);    mTextPaint.setTextSize(array.getDimensionPixelSize(R.styleable.TrendGraph_textSize, 35));    mTextPaint.setColor(array.getColor(R.styleable.TrendGraph_textColor, Color.BLACK));    array.recycle();  }

getDimensionPixelSize方法則是通過傳入的值,轉換為具體的像素(px)值,也就免去我們手動轉換的麻煩。但是要注意,其中的defaultValue依然是px。

接著,就可以通過xml指定這些屬性,在布局中加入命名空間:

xmlns:app=http://schemas.android.com/apk/res-auto

Android Studio會自動引入,並且可以補全得到,具體使用:

  <com.fndroid.byweather.views.TrendGraph    android:id="@+id/tg"    android:layout_width="match_parent"    app:textColor="@color/colorAccent"    app:textSize="22sp"    app:circleRadius="2dp"    android:layout_height="200dp"/>

最後,添加一個事件監聽,在點擊View的時候進行回調:

① 定義介面:

  public interface onItemClickListener{    void onItemClick(View view, Element element);  }

② 在View中添加介面對象,並設定setter方法:

public class TrendGraph extends View {  private onItemClickListener mOnItemClickListener;  // 省略代碼  public void setOnItemClickListener(onItemClickListener onItemClickListener) {    mOnItemClickListener = onItemClickListener;  }} 

③ 處理onTouchEvent,重寫該方法,代碼如下:

  @Override  public boolean onTouchEvent(MotionEvent event) {    int viewWidth = getWidth();    int itemWidth = viewWidth / mElements.size();    int viewHeight = getHeight();    boolean isMove = false; // 介面中最外層為一個NestedScrollView,所以為了避免滑動時也觸發,加入變數處理    switch (event.getAction()) {      case MotionEvent.ACTION_MOVE:        isMove = true;        break;      case MotionEvent.ACTION_UP:        if (!isMove){ // 判斷只有點擊時進行回調          int position = (int) (event.getX() / itemWidth); // 取得點擊的位置          mOnItemClickListener.onItemClick(this, mElements.get(position)); // 回調        }        break;    }    return true;  }

④ 在Activity中,進行監聽設定,並處理:

  historyGraph.setOnItemClickListener(this);  @Override  public void onItemClick(View view, TrendGraph.Element element) {    int dt = (int) (element.getUp() - element.getDown());    Snackbar.make(root, "當天溫差為:" + dt + "℃", Snackbar.LENGTH_SHORT).show();  }

總結

效果完成!如果有疑問歡迎大家交流討論,希望本文對大家開發Android能有所協助。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.