Android時(shí)光軸實(shí)現(xiàn)淘寶物流信息瀏覽效果
本文實(shí)例為大家分享了Android時(shí)光軸的制作方法,供大家參考,具體內(nèi)容如下
1. 效果

2.分析和實(shí)現(xiàn)
2.1效果實(shí)現(xiàn):
之前想了一下這種效果,因?yàn)橹恍枰玫阶约旱捻?xiàng)目中所以采用圖片直接布局的形式去實(shí)現(xiàn)效果,雖然效果實(shí)現(xiàn)了,但是后來發(fā)現(xiàn)了出了很多問題:第一Android的分辨率太多了直接設(shè)置xxxdp難免有部分機(jī)型出現(xiàn)不適配的情況,第二我們與右邊這部分需要對(duì)齊的問題這個(gè)就比較頭大。
所以目前的實(shí)現(xiàn)效果方式是這樣子的:
1.自定義TimerLineMarker,根據(jù)自定義屬性獲取點(diǎn)和線的背景資源或是顏色以及寬度等等,在onMeasure中計(jì)算布局的寬度和高度;
2.在Item布居中我們給需要對(duì)齊那個(gè)View設(shè)置一個(gè)id為need_align_view,我們?cè)趏nSizeChanged中去找到并計(jì)算對(duì)齊View距頭部的高度;
3.當(dāng)我們得到對(duì)齊View的高度后,我們計(jì)算上面Line,中間Marker以及下面Line需要繪制的矩形區(qū)域,調(diào)用invalidate()然后在onDraw方法中分別繪制這三個(gè)部分;
4.很顯然我們需要顯示的方式是有些不同的,比如第一個(gè)沒有上面的線其中心標(biāo)記顏色也不一樣,最后一個(gè)沒有下面的線,所以我們需要提供兩個(gè)方法:setStyle()設(shè)置顯示風(fēng)格;setMarker(int resouceId)設(shè)置中間標(biāo)記的資源
2.2分步實(shí)現(xiàn):
1.自定義TimerLineMarker,根據(jù)自定義屬性獲取點(diǎn)和線的背景資源或是顏色以及寬度等等,在onMeasure中計(jì)算布局的寬度和高度
public class TimerLineMarker extends View {
// 3個(gè)部分的drawable
private Drawable mBeginLine, mEndLine, mMarker;
// 顯示大小
private int mMarkerSize = 26, mLineSize = 4;
// 距離頭部的微調(diào)
private int mMarkerMarginTop = 0;
public TimerLineMarker(Context context) {
this(context, null);
}
public TimerLineMarker(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TimerLineMarker(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttribute(attrs);
}
/**
* 初始化自定義屬性
*/
private void initAttribute(AttributeSet attrs) {
final TypedArray typedArray = getContext().obtainStyledAttributes(
attrs, R.styleable.TimerLineMarker);
// 獲取size
mMarkerSize = typedArray.getDimensionPixelSize(
R.styleable.TimerLineMarker_markerSize, mMarkerSize);
mLineSize = typedArray.getDimensionPixelSize(
R.styleable.TimerLineMarker_lineSize, mLineSize);
// 獲取drawable
mBeginLine = typedArray
.getDrawable(R.styleable.TimerLineMarker_beginLine);
mEndLine = typedArray.getDrawable(R.styleable.TimerLineMarker_endLine);
mMarker = typedArray.getDrawable(R.styleable.TimerLineMarker_marker);
mMarkerMarginTop = typedArray.getDimensionPixelSize(
R.styleable.TimerLineMarker_markerMarginTop, mMarkerMarginTop);
typedArray.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 測(cè)量本View的寬高里面子控件的寬度
int with = mMarkerSize + getPaddingLeft() + getPaddingRight();
int height = mMarkerSize + getPaddingTop() + getPaddingBottom();
// 通過系統(tǒng)的一個(gè)方法做決策最終決定寬高
int withSize = resolveSizeAndState(with, widthMeasureSpec, 0);
int heightSize = resolveSizeAndState(height, heightMeasureSpec, 0);
// 設(shè)置寬高
setMeasuredDimension(withSize, heightSize);
}
}
2.在Item布居中我們給需要對(duì)齊那個(gè)View設(shè)置一個(gè)id為need_align_view,我們?cè)趏nSizeChanged中去找到并計(jì)算對(duì)齊View距頭部的高度;
// 標(biāo)記距離頭部的位置
private int mMarkerTopDistance;
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
initAlignViewHeight();
// 當(dāng)View顯示的時(shí)候回調(diào)
// 定位到當(dāng)前幾個(gè)draw able的坐標(biāo),然后繪制
initDrawable();
}
/**
* 初始化獲取需要對(duì)齊的View高度
*/
private void initAlignViewHeight() {
// 獲取需要對(duì)齊的View
ViewGroup parent = (ViewGroup) this.getParent();
mNeedAlignView = findNeedAlignView(parent);
// 獲取需要對(duì)齊的View距離頂部的高度
if (mNeedAlignView != null) {
mMarkerTopDistance = 0;
// 與需要對(duì)齊View的中心點(diǎn)對(duì)齊
mMarkerTopDistance += calcViewTop(mNeedAlignView)
+ mNeedAlignView.getMeasuredHeight() / 2;
}
}
/**
* 循環(huán)獲取距頂部的距離
*/
private int calcViewTop(View view) {
final ViewGroup parentView = (ViewGroup) view.getParent();
final int childCount = parentView.getChildCount();
// 先加上paddingTop
int topDistance = parentView.getPaddingTop();
for (int i = 0; i < childCount; i++) {
final View childView = parentView.getChildAt(i);
final ViewGroup.LayoutParams params = (ViewGroup.LayoutParams) childView
.getLayoutParams();
topDistance = addTopMargin(topDistance, params);
if (childView == view) {
return topDistance;
}
topDistance = addBottomMargin(topDistance, params);
topDistance += childView.getMeasuredHeight();
}
return topDistance;
}
/**
* 累加底部的margin高度
*/
private int addBottomMargin(int topDistance, ViewGroup.LayoutParams params) {
if (params instanceof RelativeLayout.LayoutParams) {
RelativeLayout.LayoutParams param = (RelativeLayout.LayoutParams) params;
topDistance += param.bottomMargin;
}
if (params instanceof LinearLayout.LayoutParams) {
LinearLayout.LayoutParams param = (LinearLayout.LayoutParams) params;
topDistance += param.bottomMargin;
}
if (params instanceof FrameLayout.LayoutParams) {
FrameLayout.LayoutParams param = (FrameLayout.LayoutParams) params;
topDistance += param.bottomMargin;
}
if (params instanceof TableLayout.LayoutParams) {
TableLayout.LayoutParams param = (TableLayout.LayoutParams) params;
topDistance += param.bottomMargin;
}
return topDistance;
}
/**
* 累加頭部margin高度
*/
private int addTopMargin(int topDistance, ViewGroup.LayoutParams params) {
if (params instanceof RelativeLayout.LayoutParams) {
RelativeLayout.LayoutParams param = (RelativeLayout.LayoutParams) params;
topDistance += param.topMargin;
}
if (params instanceof LinearLayout.LayoutParams) {
LinearLayout.LayoutParams param = (LinearLayout.LayoutParams) params;
topDistance += param.topMargin;
}
if (params instanceof FrameLayout.LayoutParams) {
FrameLayout.LayoutParams param = (FrameLayout.LayoutParams) params;
topDistance += param.topMargin;
}
if (params instanceof TableLayout.LayoutParams) {
TableLayout.LayoutParams param = (TableLayout.LayoutParams) params;
topDistance += param.topMargin;
}
return topDistance;
}
3.當(dāng)我們得到對(duì)齊View的高度后,我們計(jì)算上面Line,中間Marker以及下面Line需要繪制的矩形區(qū)域,調(diào)用invalidate()然后在onDraw方法中分別繪制這三個(gè)部分;
/**
* 初始化Draw able
*/
private void initDrawable() {
initMarkerBounds();
initLineBounds();
postInvalidate();
}
/**
* 初始化時(shí)光線Bounds
*/
private void initLineBounds() {
int height = getHeight();
Rect bounds = mMarker.getBounds();
int lineLeft = bounds.centerX() - (mLineSize >> 1);
if (mBeginLine != null)
mBeginLine.setBounds(lineLeft, 0, lineLeft + mLineSize, bounds.top);
if (mEndLine != null)
mEndLine.setBounds(lineLeft, bounds.bottom, lineLeft + mLineSize,
height);
}
/**
* 初始化標(biāo)記Bounds
*/
private void initMarkerBounds() {
int pLeft = getPaddingLeft();
int pRight = getPaddingRight();
int pBottom = getPaddingBottom();
int pTop = getPaddingTop();
int width = getWidth();
int height = getHeight();
int cWidth = width - pLeft - pRight;
int cHeight = height - pTop - pBottom;
mMarkerSize = Math.min(mMarkerSize, Math.min(cWidth, cHeight));
mMarkerTopDistance = mMarkerTopDistance - mMarkerSize / 2;
if (mMarkerMarginTop < 0) {
mMarkerMarginTop = 0;
}
mMarker.setBounds(pLeft, mMarkerTopDistance + mMarkerMarginTop, pLeft
+ mMarkerSize, mMarkerTopDistance + mMarkerMarginTop
+ mMarkerSize);
}
@Override
protected void onDraw(Canvas canvas) {
if (mMarker.getBounds().right <= 0) {
// 如果bounds被弄丟了
assignValue();
}
if (mMarkerStyle != MarkerStyle.START_STYLE) {
if (mBeginLine != null)
mBeginLine.draw(canvas);
}
mMarker.draw(canvas);
if (mMarkerStyle != MarkerStyle.END_STYLE) {
if (mEndLine != null)
mEndLine.draw(canvas);
}
}
/**
* 從新賦值
*/
private void assignValue() {
initAlignViewHeight();
initMarkerBounds();
initLineBounds();
}
4.很顯然我們需要顯示的方式是有些不同的,比如第一個(gè)沒有上面的線其中心標(biāo)記顏色也不一樣,最后一個(gè)沒有下面的線,所以我們需要提供兩個(gè)方法:setStyle()設(shè)置顯示風(fēng)格;setMarker(int resouceId)設(shè)置中間標(biāo)記的資源。
/**
* 設(shè)置顯示的分隔
*/
public void setStyle(MarkerStyle markerStyle) {
this.mMarkerStyle = markerStyle;
invalidate();
}
/**
* 設(shè)置標(biāo)記的Draw able
*/
public void setMarker(Drawable marker) {
this.mMarker = marker;
postInvalidate();
}
/**
* 設(shè)置標(biāo)記資源
*
* @param resouceId
* 資源id
*/
public void setMarker(int resouceId) {
this.mMarker = getResources().getDrawable(resouceId);
postInvalidate();
}
/**
* 時(shí)光軸顯示風(fēng)格
*/
public enum MarkerStyle {
// 開始第一個(gè)
START_STYLE,
// 中間位置
CENTER_STYLE,
// 最后一個(gè)
END_STYLE
}
以后希望自己有點(diǎn)空,就把自己做的一些東西寫下來. 一方面鍛煉一下自己的寫文檔的能力,另一方面分享代碼的同時(shí)也希望能與大家交流一下技術(shù),共同學(xué)習(xí),共同進(jìn)步。因?yàn)殚_發(fā)過程中遇到一些問題我總會(huì)先在網(wǎng)上找一些例子參考一下,類似的代碼,可能有些達(dá)不到效果或是用不上,沒辦法也只能自己造輪子。
源碼下載地址:http://xiazai.jb51.net/201611/yuanma/AndroidTimeLine(jb51.net).rar
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android之RecyclerView實(shí)現(xiàn)時(shí)光軸效果示例
- Android自定義View實(shí)現(xiàn)垂直時(shí)間軸布局
- Android控件之使用ListView實(shí)現(xiàn)時(shí)間軸效果
- Android自定義view仿淘寶快遞物流信息時(shí)間軸
- 教你3分鐘了解Android 簡易時(shí)間軸的實(shí)現(xiàn)方法
- Android自定義時(shí)間軸的實(shí)現(xiàn)過程
- Android實(shí)現(xiàn)列表時(shí)間軸
- Android TimeLine 時(shí)間節(jié)點(diǎn)軸的實(shí)現(xiàn)實(shí)例代碼
- Android實(shí)現(xiàn)快遞物流時(shí)間軸效果
- Android自定義recyclerView實(shí)現(xiàn)時(shí)光軸效果
相關(guān)文章
Flutter加載圖片流程之ImageProvider源碼示例解析
這篇文章主要為大家介紹了Flutter加載圖片流程之ImageProvider源碼示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04
Android中FloatingActionButton的顯示與隱藏示例
本篇文章主要介紹了Android中FloatingActionButton的顯示與隱藏示例,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-10-10
android基礎(chǔ)總結(jié)篇之二:Activity的四種launchMode
這篇文章主要介紹了android基礎(chǔ)總結(jié)篇之二:Activity的四種launchMode,有需要的可以了解一下。2016-11-11
Android實(shí)現(xiàn)軟件列表的點(diǎn)擊啟動(dòng)另外一個(gè)程序功能【附demo源碼下載】
這篇文章主要介紹了Android實(shí)現(xiàn)軟件列表的點(diǎn)擊啟動(dòng)另外一個(gè)程序功能,涉及Android針對(duì)應(yīng)用程序的讀取、加載、啟動(dòng)等操作相關(guān)技巧,需要的朋友可以參考下2016-07-07
Android使用KeyStore對(duì)數(shù)據(jù)進(jìn)行加密的示例代碼
這篇文章主要介紹了Android使用KeyStore對(duì)數(shù)據(jù)進(jìn)行加密的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-01-01
Android編程之客戶端通過socket與服務(wù)器通信的方法
這篇文章主要介紹了Android編程之客戶端通過socket與服務(wù)器通信的方法,結(jié)合實(shí)例形式分析了Android基于socket通訊的具體步驟與相關(guān)使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11
Android日期時(shí)間格式國際化的實(shí)現(xiàn)代碼
本篇文章是對(duì)在Android中 日期時(shí)間格式國際化的實(shí)現(xiàn)代碼進(jìn)行了分析介紹。需要的朋友參考下2013-05-05

