最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android自定義View實(shí)現(xiàn)垂直時(shí)間軸布局

 更新時(shí)間:2020年08月26日 14:23:44   作者:shineflowers  
這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)垂直時(shí)間軸布局的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

時(shí)間軸,顧名思義就是將發(fā)生的事件按照時(shí)間順序羅列起來(lái),給用戶帶來(lái)一種更加直觀的體驗(yàn)。京東和淘寶的物流順序就是一個(gè)時(shí)間軸,想必大家都不陌生,如下圖:

分析

實(shí)現(xiàn)這個(gè)最常用的一個(gè)方法就是用ListView,我這里用繼承LinearLayout的方式來(lái)實(shí)現(xiàn)。首先定義了一些自定義屬性:

attrs.xml

<?xml version="1.0" encoding="utf-8"?> 
<resources> 
 <declare-styleable name="TimelineLayout"> 
  <!--時(shí)間軸左偏移值--> 
  <attr name="line_margin_left" format="dimension"/> 
  <!--時(shí)間軸上偏移值--> 
  <attr name="line_margin_top" format="dimension"/> 
  <!--線寬--> 
  <attr name="line_stroke_width" format="dimension"/> 
  <!--線的顏色--> 
  <attr name="line_color" format="color"/> 
  <!--點(diǎn)的大小--> 
  <attr name="point_size" format="dimension"/> 
  <!--點(diǎn)的顏色--> 
  <attr name="point_color" format="color"/> 
  <!--圖標(biāo)--> 
  <attr name="icon_src" format="reference"/> 
 </declare-styleable> 
</resources> 

TimelineLayout.java

package com.jackie.timeline; 
 
import android.content.Context; 
import android.content.res.TypedArray; 
import android.graphics.Bitmap; 
import android.graphics.Canvas; 
import android.graphics.Paint; 
import android.graphics.drawable.BitmapDrawable; 
import android.support.annotation.Nullable; 
import android.util.AttributeSet; 
import android.view.View; 
import android.widget.LinearLayout; 
 
/** 
 * Created by Jackie on 2017/3/8. 
 * 時(shí)間軸控件 
 */ 
 
public class TimelineLayout extends LinearLayout { 
 private Context mContext; 
 
 private int mLineMarginLeft; 
 private int mLineMarginTop; 
 private int mLineStrokeWidth; 
 private int mLineColor;; 
 private int mPointSize; 
 private int mPointColor; 
 private Bitmap mIcon; 
 
 private Paint mLinePaint; //線的畫(huà)筆 
 private Paint mPointPaint; //點(diǎn)的畫(huà)筆 
  
 
 //第一個(gè)點(diǎn)的位置 
 private int mFirstX; 
 private int mFirstY; 
 //最后一個(gè)圖標(biāo)的位置 
 private int mLastX; 
 private int mLastY; 
 
 public TimelineLayout(Context context) { 
  this(context, null); 
 } 
 
 public TimelineLayout(Context context, @Nullable AttributeSet attrs) { 
  this(context, attrs, 0); 
 } 
 
 public TimelineLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 
  super(context, attrs, defStyleAttr); 
  TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TimelineLayout); 
  mLineMarginLeft = ta.getDimensionPixelOffset(R.styleable.TimelineLayout_line_margin_left, 10); 
  mLineMarginTop = ta.getDimensionPixelOffset(R.styleable.TimelineLayout_line_margin_top, 0); 
  mLineStrokeWidth = ta.getDimensionPixelOffset(R.styleable.TimelineLayout_line_stroke_width, 2); 
  mLineColor = ta.getColor(R.styleable.TimelineLayout_line_color, 0xff3dd1a5); 
  mPointSize = ta.getDimensionPixelSize(R.styleable.TimelineLayout_point_size, 8); 
  mPointColor = ta.getDimensionPixelOffset(R.styleable.TimelineLayout_point_color, 0xff3dd1a5); 
 
  int iconRes = ta.getResourceId(R.styleable.TimelineLayout_icon_src, R.drawable.ic_ok); 
  BitmapDrawable drawable = (BitmapDrawable) context.getResources().getDrawable(iconRes); 
  if (drawable != null) { 
   mIcon = drawable.getBitmap(); 
  } 
 
  ta.recycle(); 
 
  setWillNotDraw(false); 
  initView(context); 
 } 
 
 private void initView(Context context) { 
  this.mContext = context; 
 
  mLinePaint = new Paint(); 
  mLinePaint.setAntiAlias(true); 
  mLinePaint.setDither(true); 
  mLinePaint.setColor(mLineColor); 
  mLinePaint.setStrokeWidth(mLineStrokeWidth); 
  mLinePaint.setStyle(Paint.Style.FILL_AND_STROKE); 
 
  mPointPaint = new Paint(); 
  mPointPaint.setAntiAlias(true); 
  mPointPaint.setDither(true); 
  mPointPaint.setColor(mPointColor); 
  mPointPaint.setStyle(Paint.Style.FILL); 
 } 
 
 @Override 
 protected void onDraw(Canvas canvas) { 
  super.onDraw(canvas); 
   
  drawTimeline(canvas); 
 } 
 
 private void drawTimeline(Canvas canvas) { 
  int childCount = getChildCount(); 
 
  if (childCount > 0) { 
   if (childCount > 1) { 
    //大于1,證明至少有2個(gè),也就是第一個(gè)和第二個(gè)之間連成線,第一個(gè)和最后一個(gè)分別有點(diǎn)和icon 
    drawFirstPoint(canvas); 
    drawLastIcon(canvas); 
    drawBetweenLine(canvas); 
   } else if (childCount == 1) { 
    drawFirstPoint(canvas); 
   } 
  } 
 } 
 
 private void drawFirstPoint(Canvas canvas) { 
  View child = getChildAt(0); 
  if (child != null) { 
   int top = child.getTop(); 
   mFirstX = mLineMarginLeft; 
   mFirstY = top + child.getPaddingTop() + mLineMarginTop; 
 
   //畫(huà)圓 
   canvas.drawCircle(mFirstX, mFirstY, mPointSize, mPointPaint); 
  } 
 } 
 
 private void drawLastIcon(Canvas canvas) { 
  View child = getChildAt(getChildCount() - 1); 
  if (child != null) { 
   int top = child.getTop(); 
   mLastX = mLineMarginLeft; 
   mLastY = top + child.getPaddingTop() + mLineMarginTop; 
 
   //畫(huà)圖 
   canvas.drawBitmap(mIcon, mLastX - (mIcon.getWidth() >> 1), mLastY, null); 
  } 
 } 
 
 private void drawBetweenLine(Canvas canvas) { 
  //從開(kāi)始的點(diǎn)到最后的圖標(biāo)之間,畫(huà)一條線 
  canvas.drawLine(mFirstX, mFirstY, mLastX, mLastY, mLinePaint); 
  for (int i = 0; i < getChildCount() - 1; i++) { 
   //畫(huà)圓 
   int top = getChildAt(i).getTop(); 
   int y = top + getChildAt(i).getPaddingTop() + mLineMarginTop; 
   canvas.drawCircle(mFirstX, y, mPointSize, mPointPaint); 
  } 
 } 
 
 public int getLineMarginLeft() { 
  return mLineMarginLeft; 
 } 
 
 public void setLineMarginLeft(int lineMarginLeft) { 
  this.mLineMarginLeft = lineMarginLeft; 
  invalidate(); 
 } 
} 

從上面的代碼可以看出,分三步繪制,首先繪制開(kāi)始的實(shí)心圓,然后繪制結(jié)束的圖標(biāo),然后在開(kāi)始和結(jié)束之間先繪制一條線,然后在線上在繪制每個(gè)步驟的實(shí)心圓。
activity_main.xml

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
 xmlns:app="http://schemas.android.com/apk/res-auto" 
 android:layout_width="match_parent" 
 android:layout_height="match_parent" 
 android:orientation="vertical"> 
 
 <LinearLayout 
  android:layout_width="match_parent" 
  android:layout_height="50dp" 
  android:weightSum="2"> 
 
  <Button 
   android:id="@+id/add_item" 
   android:layout_width="0dp" 
   android:layout_height="match_parent" 
   android:layout_weight="1" 
   android:text="add"/> 
 
  <Button 
   android:id="@+id/sub_item" 
   android:layout_width="0dp" 
   android:layout_height="match_parent" 
   android:layout_weight="1" 
   android:text="sub"/> 
 </LinearLayout> 
 
 <LinearLayout 
  android:layout_width="match_parent" 
  android:layout_height="wrap_content" 
  android:orientation="horizontal" 
  android:weightSum="2"> 
 
  <Button 
   android:id="@+id/add_margin" 
   android:layout_width="0dp" 
   android:layout_weight="1" 
   android:layout_height="wrap_content" 
   android:text="+"/> 
 
  <Button 
   android:id="@+id/sub_margin" 
   android:layout_width="0dp" 
   android:layout_weight="1" 
   android:layout_height="wrap_content" 
   android:text="-"/> 
 </LinearLayout> 
 
 <TextView 
  android:id="@+id/current_margin" 
  android:layout_width="match_parent" 
  android:layout_height="40dp" 
  android:gravity="center" 
  android:text="current line margin left is 25dp"/> 
 
 <ScrollView 
  android:layout_width="match_parent" 
  android:layout_height="wrap_content" 
  android:scrollbars="none"> 
 
  <com.jackie.timeline.TimelineLayout 
   android:id="@+id/timeline_layout" 
   android:layout_width="match_parent" 
   android:layout_height="wrap_content" 
   app:line_margin_left="25dp" 
   app:line_margin_top="8dp" 
   android:orientation="vertical" 
   android:background="@android:color/white"> 
  </com.jackie.timeline.TimelineLayout> 
 </ScrollView> 
</LinearLayout> 

MainActivity.java

package com.jackie.timeline; 
 
import android.os.Bundle; 
import android.support.v7.app.AppCompatActivity; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.widget.Button; 
import android.widget.TextView; 
 
public class MainActivity extends AppCompatActivity implements View.OnClickListener { 
 private Button addItemButton; 
 private Button subItemButton; 
 private Button addMarginButton; 
 private Button subMarginButton; 
 private TextView mCurrentMargin; 
 
 private TimelineLayout mTimelineLayout; 
 
 @Override 
 protected void onCreate(Bundle savedInstanceState) { 
  super.onCreate(savedInstanceState); 
  setContentView(R.layout.activity_main); 
 
  initView(); 
 } 
 
 private void initView() { 
  addItemButton = (Button) findViewById(R.id.add_item); 
  subItemButton = (Button) findViewById(R.id.sub_item); 
  addMarginButton= (Button) findViewById(R.id.add_margin); 
  subMarginButton= (Button) findViewById(R.id.sub_margin); 
  mCurrentMargin= (TextView) findViewById(R.id.current_margin); 
  mTimelineLayout = (TimelineLayout) findViewById(R.id.timeline_layout); 
 
  addItemButton.setOnClickListener(this); 
  subItemButton.setOnClickListener(this); 
  addMarginButton.setOnClickListener(this); 
  subMarginButton.setOnClickListener(this); 
 } 
 
 private int index = 0; 
 private void addItem() { 
  View view = LayoutInflater.from(this).inflate(R.layout.item_timeline, mTimelineLayout, false); 
  ((TextView) view.findViewById(R.id.tv_action)).setText("步驟" + index); 
  ((TextView) view.findViewById(R.id.tv_action_time)).setText("2017年3月8日16:55:04"); 
  ((TextView) view.findViewById(R.id.tv_action_status)).setText("完成"); 
  mTimelineLayout.addView(view); 
  index++; 
 } 
 
 private void subItem() { 
  if (mTimelineLayout.getChildCount() > 0) { 
   mTimelineLayout.removeViews(mTimelineLayout.getChildCount() - 1, 1); 
   index--; 
  } 
 } 
 
 @Override 
 public void onClick(View v) { 
  switch (v.getId()){ 
   case R.id.add_item: 
    addItem(); 
    break; 
   case R.id.sub_item: 
    subItem(); 
    break; 
   case R.id.add_margin: 
    int currentMargin = UIHelper.pxToDip(this, mTimelineLayout.getLineMarginLeft()); 
    mTimelineLayout.setLineMarginLeft(UIHelper.dipToPx(this, ++currentMargin)); 
    mCurrentMargin.setText("current line margin left is " + currentMargin + "dp"); 
    break; 
   case R.id.sub_margin: 
    currentMargin = UIHelper.pxToDip(this, mTimelineLayout.getLineMarginLeft()); 
    mTimelineLayout.setLineMarginLeft(UIHelper.dipToPx(this, --currentMargin)); 
    mCurrentMargin.setText("current line margin left is " + currentMargin + "dp"); 
    break; 
   default: 
    break; 
  } 
 } 
} 

item_timeline.xml

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout 
 xmlns:android="http://schemas.android.com/apk/res/android" 
 android:layout_width="match_parent" 
 android:layout_height="wrap_content" 
 android:paddingLeft="65dp" 
 android:paddingTop="20dp" 
 android:paddingRight="20dp" 
 android:paddingBottom="20dp"> 
 
 <TextView 
  android:id="@+id/tv_action" 
  android:layout_width="wrap_content" 
  android:layout_height="wrap_content" 
  android:textSize="14sp" 
  android:textColor="#1a1a1a" 
  android:text="測(cè)試一"/> 
 
 <TextView 
  android:id="@+id/tv_action_time" 
  android:layout_width="wrap_content" 
  android:layout_height="wrap_content" 
  android:textSize="12sp" 
  android:textColor="#8e8e8e" 
  android:layout_below="@id/tv_action" 
  android:layout_marginTop="10dp" 
  android:text="2017年3月8日16:49:12"/> 
 
 <TextView 
  android:id="@+id/tv_action_status" 
  android:layout_width="wrap_content" 
  android:layout_height="wrap_content" 
  android:textSize="14sp" 
  android:textColor="#3dd1a5" 
  android:layout_alignParentRight="true" 
  android:text="完成"/> 
 
</RelativeLayout> 

附上像素工具轉(zhuǎn)化的工具類:

package com.jackie.timeline; 
 
import android.content.Context; 
 
/** 
 * Created by Jackie on 2017/3/8. 
 */ 
public final class UIHelper { 
 
 private UIHelper() throws InstantiationException { 
  throw new InstantiationException("This class is not for instantiation"); 
 } 
 
 /** 
  * dip轉(zhuǎn)px 
  */ 
 public static int dipToPx(Context context, float dip) { 
  return (int) (dip * context.getResources().getDisplayMetrics().density + 0.5f); 
 } 
 
 /** 
  * px轉(zhuǎn)dip 
  */ 
 public static int pxToDip(Context context, float pxValue) { 
  final float scale = context.getResources().getDisplayMetrics().density; 
  return (int) (pxValue / scale + 0.5f); 
 } 
} 

效果圖如下:

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Android webview實(shí)現(xiàn)拍照的方法

    Android webview實(shí)現(xiàn)拍照的方法

    這篇文章主要介紹了Android webview實(shí)現(xiàn)拍照的方法的相關(guān)資料,希望通過(guò)本文能幫助到大家實(shí)現(xiàn)這樣的功能,需要的朋友可以參考下
    2017-10-10
  • Android ListView 滾動(dòng)條的設(shè)置詳解及實(shí)例代碼

    Android ListView 滾動(dòng)條的設(shè)置詳解及實(shí)例代碼

    這篇文章主要介紹了 ListView等滾動(dòng)條的設(shè)置詳解詳解及實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • Android中GPS坐標(biāo)轉(zhuǎn)換為高德地圖坐標(biāo)詳解

    Android中GPS坐標(biāo)轉(zhuǎn)換為高德地圖坐標(biāo)詳解

    最近因?yàn)楣拘枨?,在做GPS定位,并且將獲得的坐標(biāo)顯示在高德地圖上,但是實(shí)際效果跟我們期望的是有偏差的。通過(guò)查閱資料,才知道有地球坐標(biāo)、火星坐標(biāo)之說(shuō)。下面這篇文章就詳細(xì)介紹了Android中GPS坐標(biāo)轉(zhuǎn)換為高德地圖坐標(biāo)的方法,需要的朋友可以參考下。
    2017-01-01
  • Android使用SlidingPaneLayout 實(shí)現(xiàn)仿微信的滑動(dòng)返回

    Android使用SlidingPaneLayout 實(shí)現(xiàn)仿微信的滑動(dòng)返回

    這篇文章主要介紹了Android使用SlidingPaneLayout 實(shí)現(xiàn)仿微信的滑動(dòng)返回,需要的朋友可以參考下
    2018-04-04
  • Flutter啟動(dòng)流程的深入解析

    Flutter啟動(dòng)流程的深入解析

    這篇文章主要給大家介紹了關(guān)于Flutter啟動(dòng)流程的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Flutter具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • Android顯示系統(tǒng)SurfaceFlinger詳解

    Android顯示系統(tǒng)SurfaceFlinger詳解

    本文詳細(xì)講解了Android顯示系統(tǒng)SurfaceFlinger,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-12-12
  • Android中使用ScrollView指定view的頂部懸停效果

    Android中使用ScrollView指定view的頂部懸停效果

    在項(xiàng)目開(kāi)發(fā)中遇到這樣的需求,需要實(shí)現(xiàn)scrollview頂部的懸停效果,實(shí)現(xiàn)原理非常簡(jiǎn)單,下面小編通過(guò)本文給大家分享實(shí)例代碼,需要的朋友參考下
    2017-04-04
  • Android中TelephonyManager類的用法案例詳解

    Android中TelephonyManager類的用法案例詳解

    這篇文章主要介紹了Android中TelephonyManager類的用法,以獲取Android手機(jī)硬件信息為例詳細(xì)分析了TelephonyManager類的使用技巧,需要的朋友可以參考下
    2015-09-09
  • Android 中ViewPager中使用WebView的注意事項(xiàng)

    Android 中ViewPager中使用WebView的注意事項(xiàng)

    這篇文章主要介紹了Android 中ViewPager中使用WebView的注意事項(xiàng)的相關(guān)資料,希望通過(guò)本文大家在使用過(guò)程中遇到這樣的問(wèn)題解決,需要的朋友可以參考下
    2017-09-09
  • Android實(shí)現(xiàn)簡(jiǎn)單的加載進(jìn)度條

    Android實(shí)現(xiàn)簡(jiǎn)單的加載進(jìn)度條

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)簡(jiǎn)單的加載進(jìn)度條,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-05-05

最新評(píng)論

酒泉市| 东安县| 尼勒克县| 九龙县| 济源市| 高尔夫| 吉首市| 江山市| 仪陇县| 汤原县| 进贤县| 务川| 阿荣旗| 永寿县| 莱阳市| 扶风县| 沿河| 朝阳区| 英超| 元江| 忻州市| 漳浦县| 高雄市| 合阳县| 永修县| 元阳县| 姜堰市| 中山市| 孟连| 宜阳县| 稷山县| 灌南县| 内江市| 辽源市| 郓城县| 琼结县| 前郭尔| 汶上县| 金湖县| 乐亭县| 台东市|