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)了,但是后來(lái)發(fā)現(xiàn)了出了很多問(wèn)題:第一Android的分辨率太多了直接設(shè)置xxxdp難免有部分機(jī)型出現(xiàn)不適配的情況,第二我們與右邊這部分需要對(duì)齊的問(wèn)題這個(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è)沒(méi)有上面的線其中心標(biāo)記顏色也不一樣,最后一個(gè)沒(méi)有下面的線,所以我們需要提供兩個(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(); // 通過(guò)系統(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è)沒(méi)有上面的線其中心標(biāo)記顏色也不一樣,最后一個(gè)沒(méi)有下面的線,所以我們需要提供兩個(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 { // 開(kāi)始第一個(gè) START_STYLE, // 中間位置 CENTER_STYLE, // 最后一個(gè) END_STYLE }
以后希望自己有點(diǎn)空,就把自己做的一些東西寫下來(lái). 一方面鍛煉一下自己的寫文檔的能力,另一方面分享代碼的同時(shí)也希望能與大家交流一下技術(shù),共同學(xué)習(xí),共同進(jìn)步。因?yàn)殚_(kāi)發(fā)過(guò)程中遇到一些問(wèn)題我總會(huì)先在網(wǎng)上找一些例子參考一下,類似的代碼,可能有些達(dá)不到效果或是用不上,沒(méi)辦法也只能自己造輪子。
源碼下載地址:http://xiazai.jb51.net/201611/yuanma/AndroidTimeLine(jb51.net).rar
以上就是本文的全部?jī)?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 簡(jiǎn)易時(shí)間軸的實(shí)現(xiàn)方法
- Android自定義時(shí)間軸的實(shí)現(xiàn)過(guò)程
- 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)文章
Android自定義View實(shí)現(xiàn)抖音飄動(dòng)紅心效果
這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)抖音飄動(dòng)紅心效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05Android Flutter實(shí)現(xiàn)圖片滑動(dòng)切換效果
Flutter 為了簡(jiǎn)化開(kāi)發(fā),提供了不少轉(zhuǎn)換動(dòng)畫組件,這類組件通常命名為 xxTransition。本篇要介紹的就是 SlideTransition,并用它實(shí)現(xiàn)圖片滑動(dòng)切換效果,感興趣的可以了解一下2022-04-04Android如何讓W(xué)ebView中的HTML5頁(yè)面實(shí)現(xiàn)視頻全屏播放
最近在工作遇到一個(gè)需求,需要讓W(xué)ebView中的HTML5頁(yè)面實(shí)現(xiàn)視頻全屏播放的效果,通過(guò)查找相關(guān)的資料終于找到了解決的方法,所以想著分享給大家,所以本文介紹了關(guān)于Android如何讓W(xué)ebView中的HTML5頁(yè)面實(shí)現(xiàn)視頻全屏播放的相關(guān)資料,需要的朋友可以參考學(xué)習(xí)。2017-04-04andoid打包短信發(fā)送到gmail郵箱實(shí)現(xiàn)代碼
andriod短信整合備份發(fā)送到gmail郵箱,需要在andoid手機(jī)配置好gmail郵箱,下面是具體的實(shí)現(xiàn)代碼,感興趣的朋友可以參考下哈2013-06-06