Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 仿淘寶物流信息控件

仿淘寶物流信息控件

編輯:關於Android編程

先看下效果吧

效果vcrH1+7E0bXEoaO+zcjDztLDx7+qyry7rbXa0ru49sz1xL+wyaOswvWz9tXi1+7E0bXE0ruyvTwvcD4NCjxwPruttdrSu7j2zPXEv6OsztLDx9Ky0qrPyLfWzvbPwtT1w7S7raOsytfRoc7Sw8fSqsi3tqjSu7j2zPXEv7XEv+22yLjftsijrL/ttsjV4sDvysfGwcS7tcS/7bbIo6y437bIuduy7MzUsaa1xM7vwfe/2Lz+o6zM9cS/tcS437bI08nJz835z8LKx9PJICZyc3F1bzvQxc+ivuDA68z1xL+2pbK/tcRtYXJnaW4gKyDQxc+itcS437bIICsgyrG85LrN0MXPorXEbWFyZ2luICsgyrG85LXEuN+2yCArIMqxvOS+4MDrzPXEv7XXsr+1xG1hcmdpbiZsc3F1bzsgubmzyaGjyLe2qMHLuN+2yKOhvdPXxc7Sw8e+zb/J0tS7rcHLo6zPyLutxMS49rarzvfL5tLiyseyu8rHo6zL+dLUwLS/qsq8u62wyTwvcD4NCjxwcmUgY2xhc3M9"brush:java;"> public class WuliuView extends View { private int mMaginTop; //物流信息距離頂部magin private int mMaginMsg; //時間距離物流信息magin private int mWidth; //屏幕寬度 private int mLineWidth; //豎直線占條目的寬度 private TextPaint mTextPaint; //畫物流信息的畫筆 private int mTextHeight; //物流信息的高度 private int mMaginBottom; //時間距離條目底部的寬度 private int mHeight; //條目高度 private StaticLayout mStaticLayout; private Rect mBound; private String mMsg; private Paint mTimePaint; //時間畫筆 private int mTimeHeight; //時間文字高度 public WuliuView(Context context) { super(context); init(); } public WuliuView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public WuliuView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mMaginTop = dp2px(15); //15dp mMaginBottom = mMaginTop; mMaginMsg = dp2px(5); //時間和信息距離5dp mLineWidth = dp2px(40); //豎直線占40dp mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); //抗鋸齒 mTextPaint.setDither(true); //仿抖動 mTextPaint.setColor(0xFF00FF00); mTextPaint.setTextSize(dp2px(13)); // mTextPaint.setTextAlign(Paint.Align.LEFT); //左下角對齊 mMsg = "【大天朝】已經簽收,簽收人是趙日天"; mBound = new Rect(); //通過邊框可以獲得文字的高度 mTextPaint.getTextBounds(mMsg, 0, mMsg.length(), mBound); mTextHeight = mBound.height(); //得到文字高度 mTimePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mTimePaint.setDither(true); mTimePaint.setColor(0xFF00FF00); mTimePaint.setTextSize(dp2px(10)); mTimePaint.setTextAlign(Paint.Align.LEFT); mTimePaint.setTypeface(Typeface.DEFAULT_BOLD); Rect boun = new Rect(); //同上理得到時間文字的高度 mTimePaint.getTextBounds("7",0,1,boun); mTimeHeight = boun.height(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { mWidth = MeasureSpec.getSize(widthMeasureSpec); mHeight = mMaginTop + mTextHeight + mMaginMsg + mTimeHeight + mMaginBottom;//條目高度 setMeasuredDimension(mWidth, mHeight); //由此確定條目的高度 } // @Override protected void onDraw(Canvas canvas) { mTimePaint.setColor(0xFF00FF00); canvas.drawText(mMsg,mLineWidth,mMaginTop+mTextHeight,mTextPaint); //畫信息 canvas.drawText(getFormateTime(new Date(System.currentTimeMillis())), mLineWidth, mMaginTop + mTextHeight + mMaginMsg + mTimeHeight, mTimePaint);//畫時間 mTimePaint.setColor(Color.GRAY);//左邊那條線 //參數一線起點x坐標,參數二線起點y坐標,參數3,4是終點坐標 canvas.drawLine(mLineWidth/2,mMaginTop + mBound.height(),mLineWidth/2,mHeight,mTimePaint); mTimePaint.setColor(0x550AE93E);//外面的更大的圓,但帶點透明 canvas.drawCircle(mLineWidth/2,mMaginTop + mBound.height() /2,mBound.height()/2,mTimePaint); mTimePaint.setColor(0xFF00FF00); //內部更小的圓不透明和外面圓形成光暈 canvas.drawCircle(mLineWidth/2,mMaginTop + mBound.height() /2,mBound.height()/2 - dp2px(2),mTimePaint); mTimePaint.setColor(Color.GRAY); //畫底部那條線 canvas.drawLine(mLineWidth,mHeight,mWidth,mHeight,mTimePaint); } public int dp2px(float dp) { return (int) (getResources().getDisplayMetrics().density * dp + .5f); } public String getFormateTime(Date date) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return sdf.format(date); } }

效果
這樣一看,好像解決了是不是,我們來試試多一點文字看一看

mMsg = "【大天朝】已經簽收,簽收人是趙日天,感謝使用飛毛腿快遞,期待再次為您服務什麼鬼啊,我了個去,你大爺的啊,怎麼會這樣子呢,一點都不科學13177786453sdawdsadwfawadwawddfsa";

效果
我靠,不換行啊,是不是瞬間感覺谷歌太不靠譜了。。。。然後這裡我也不會了,但是textview是View啊,它可以支持換行,所以一定有換行的方法,點進去看看源碼,我了個草,谷歌的當然是大神,但是再大的神,尼瑪那代碼也不忍直視,基本沒注釋,有注釋也是英文不詳細,沒過六級的表示壓力有點大,上網搜吧,去網上搜說StaticLayout這個東東可以換行,所以這個問題就可以解決了,來看看這個東東的用法

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        mWidth = MeasureSpec.getSize(widthMeasureSpec);

        mStaticLayout = new StaticLayout(mMsg,
                mTextPaint, mWidth - mLineWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 1.0f, false);

        mTextHeight = mStaticLayout.getHeight();


        mHeight = mMaginTop + mTextHeight + mMaginMsg + mTimeHeight + mMaginBottom;//條目高度


        setMeasuredDimension(mWidth, mHeight); //由此確定條目的高度

    }


    //
    @Override
    protected void onDraw(Canvas canvas) {


        mTimePaint.setColor(0xFF00FF00);
        canvas.save();

        canvas.translate(mLineWidth, mMaginTop);

        mStaticLayout.draw(canvas);  //畫信息

        canvas.restore();


        canvas.drawText(getFormateTime(new Date(System.currentTimeMillis())), mLineWidth, mMaginTop + mTextHeight +
                mMaginMsg + mTimeHeight, mTimePaint);//畫時間

先看構造函數

mStaticLayout = new StaticLayout(mMsg,
                mTextPaint, mWidth - mLineWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 1.0f, false);

第一個參數是要畫的信息;第二個參數是對應的畫筆;第三個參數是畫一行的長度;第四個是畫的方式,正常就是從左上角開始畫,我們原來的canvas.drawText默認是從左下角開始畫的;第五個參數,網上人說是列間距,第六個參數網上說是行間距,第七個不解,後面這三個參數對於我們這個控件沒影響,我也不知道干嘛用的,我改變了參數值好像沒什麼變化啊,我沒看出來,點進去看源碼也沒有介紹,所以真心覺得是大坑。。。然後來看它在onDraw是怎麼畫的

 canvas.save();

        canvas.translate(mLineWidth, mMaginTop);

        mStaticLayout.draw(canvas);  //畫信息

        canvas.restore();

這裡canvas.translate(mLineWidth, mMaginTop);畫板要下移mMaginTop是因為StaticLayout.draw(canvas)默認是在畫板的(0,0)點畫的,我們修改不了畫的點,而且它是從字的左上角開始畫的,所以根據我們畫的物流信息是要距離條目頂部mMaginTop的距離,距離左邊mLineWidth,所以畫板下移mMaginTop,右移mLineWidth這時就畫在我們像畫的那個位置了,畫完後,再讓畫板canvas.restore();恢復原來canvas.save();的位置,這裡可能有人會想,畫板都移回去了,那不是物流信息也移回去了,你前面還移個什麼勁浪費表情。這裡是不對的,其實畫板每次畫一個東西是畫在一個圖層上而不是畫在畫板上的,畫板一開始默認和你的view坐標系一樣,這兩者之間有一個圖層,我們每次畫一個東西,畫在這個圖層上,然後圖層在顯示在view上,當再畫一個東西的時候,又有一個新的圖層再中間,畫完,在與原來的view結合形成新的view。依次循環。因為我們的StaticLayout.draw(canvas)它只能畫在畫板的(0,0)點,一開始畫板與圖層坐標系對應,所以當我們把它canvas.translate(mLineWidth, mMaginTop)這樣子畫板的(0.0)點就對應圖層的(mLineWidth, mMaginTop)的點了,畫是畫在圖層上的,不是畫在畫板上的,所以這正是我們想要的!。一般我們是不會去移的,因為坐標系對應,這裡沒辦法只能移,後面畫的東西坐標系要對應,所以我們要恢復,讓它坐標系對應。好了,這就是我的理解,說了這麼多來看看效果吧
er
對了,我上面的文字高度改成了這樣

 mTextHeight = mStaticLayout.getHeight();

因為通過mBoung.hright()獲得的只是一行的高度。 嗯,看到效果圖發現有問題,很難看是不是,是這樣子的StaticLayout不允許字母截斷,什麼鳥意思呢,就是說它很聰明,認為你的字母是一個單詞,截斷了就破壞意思了!改改吧

mMsg = "【大天朝】已經簽收,簽收人是趙日天,感謝使用飛毛腿快遞,期待再次為您服務什麼鬼啊,我了個去,你大爺的啊,怎麼會這樣子呢,一點都不科學13177786453saddfsa";

效果
當然我們的物流信息也不會有那麼多字母,說實話,我就沒看過超過三個字母。好了,最難得一步是不是被我們完成了。其實就是這麼簡單是不是。沒做過真的不知道啊。然後就是畫多條條目了,這我就直接貼代碼了吧,裡面也有注釋。有興趣的要下載源碼的,我會在審核通過後再評論區把下載路徑貼出來

/**
 * Created by Root on 2016/7/8.
 */
public class WuliuView extends View {


    private int mMaginTop;          //物流信息距離頂部magin
    private int mMaginMsg;          //時間距離物流信息magin
    private int mWidth;             //屏幕寬度
    private int mLineWidth;         //豎直線占條目的寬度
    private TextPaint mTextPaint;   //畫物流信息的畫筆

    private int mTextHeight;        //物流信息的高度
    private int mMaginBottom;       //時間距離條目底部的寬度
    private int mHeight;                    //條目高度
    private Rect mBound;
    private String mMsg;
    private Paint mTimePaint;        //時間畫筆
    private int mTimeHeight;         //時間文字高度

    private ArrayList mDatas;
    private ArrayList mStaticLayoutList;

    public WuliuView(Context context, ArrayList datas) {
        super(context);
        init(datas);
    }


    private void init(ArrayList datas) {

        mMaginTop = dp2px(15);
        mMaginBottom = mMaginTop;

        mMaginMsg = dp2px(5);  //時間和信息距離5dp

        mLineWidth = dp2px(40);

        mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        mTextPaint.setDither(true);
        mTextPaint.setColor(0xFF00FF00);
        mTextPaint.setTextSize(dp2px(13));
        mTextPaint.setTextAlign(Paint.Align.LEFT);

       mMsg = "【大天朝】已經簽收,簽收人是趙日天,感謝使用飛毛腿快遞,期待再次為您服務什麼鬼啊,我了個去,你大爺的啊,怎麼會這樣子呢,一點都不科學13177786453sdaw";

        mBound = new Rect();
        mTextPaint.getTextBounds(mMsg, 0, mMsg.length(), mBound);

        mTimePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mTimePaint.setDither(true);
        mTimePaint.setColor(0xFF00FF00);
        mTimePaint.setTextSize(dp2px(10));
        mTimePaint.setTextAlign(Paint.Align.LEFT);
        mTimePaint.setTypeface(Typeface.DEFAULT_BOLD);

        Rect boun = new Rect();
        mTimePaint.getTextBounds("7",0,1,boun);
        mTimeHeight = boun.height();

        mDatas = datas;          //物流數據

        mStaticLayoutList = new ArrayList();

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        mWidth = MeasureSpec.getSize(widthMeasureSpec);

        mStaticLayoutList.clear();   //這裡會重復測量幾次,所以我們每次進來的時候需要清零一下
        mHeight = 0;
        for (int i = mDatas.size() - 1; i >= 0; i--) {  //因為數據要從後面時間的往前面的時間繪制

            mStaticLayoutList.add(new StaticLayout(mDatas.get(i).mMsg,mTextPaint,mWidth - mLineWidth, Layout
 .Alignment.ALIGN_NORMAL,1.0f,1.0f,true));
        }

        for (int i = 0; i < mStaticLayoutList.size(); i++) { //每個條目的高度

            mTextHeight = mStaticLayoutList.get(i).getHeight();
            mHeight += mMaginTop + mTextHeight + mMaginMsg + mTimeHeight +mMaginBottom; //從左到右依次為最頂上margin,描述信息高度,時間與描述的margin,時間文字高度,與底部的margin
        }

        setMeasuredDimension(mWidth, mHeight);

    }

    @Override
    protected void onDraw(Canvas canvas) {

        mHeight = 0;
        for (int i = 0; i < mStaticLayoutList.size(); i++) {

            StaticLayout staticLayout = mStaticLayoutList.get(i);
            if (i == 0){      //第一次因為要改變一些顏色,所以這裡簡單點直接分開處理
                mTimePaint.setColor(0xFF00FF00);
                mTextPaint.setColor(0xFF00FF00);
                canvas.save();

                canvas.translate(mLineWidth, mMaginTop);

                staticLayout.draw(canvas);  //畫描述信息

                canvas.restore();

                mTextHeight = staticLayout.getHeight();
                mHeight += mMaginTop + mTextHeight + mMaginMsg + mTimeHeight + mMaginBottom;


                canvas.drawText(mDatas.get(i).mTime, mLineWidth, mHeight - mMaginBottom, mTimePaint);

                mTimePaint.setColor(Color.GRAY);


                canvas.drawLine(mLineWidth/2,mMaginTop + mBound.height(),mLineWidth/2,mHeight,mTimePaint); //豎直線

                mTimePaint.setColor(0x550AE93E);
                canvas.drawCircle(mLineWidth/2,mMaginTop + mBound.height() /2,mBound.height()/2,mTimePaint);//最近的信息圓,帶透明

                mTimePaint.setColor(0xFF00FF00);
                canvas.drawCircle(mLineWidth/2,mMaginTop + mBound.height() /2,mBound.height()/2 - dp2px(2),
 mTimePaint);//小一點,不透明

                mTimePaint.setColor(Color.GRAY);
                canvas.drawLine(mLineWidth,mHeight,mWidth,mHeight,mTimePaint);//底部線

                mTextPaint.setColor(Color.GRAY);
            }else { //不是第一個條目,這裡不改變顏色了


                canvas.save();

                canvas.translate(mLineWidth, mMaginTop + mHeight);

                staticLayout.draw(canvas);

                canvas.restore();

                mTextHeight = staticLayout.getHeight();

                int addHeight = mMaginTop + mTextHeight + mMaginMsg + mTimeHeight + mMaginBottom;
                mHeight += addHeight;


                canvas.drawText(mDatas.get(i).mTime, mLineWidth, mHeight - mMaginBottom, mTimePaint); //畫時間

                //              起點橫坐標       起點縱坐標         終點橫坐標   終點縱坐標
                canvas.drawLine(mLineWidth/2,mHeight - addHeight,mLineWidth/2,mHeight,mTimePaint); //豎直線

                canvas.drawLine(mLineWidth,mHeight,mWidth,mHeight,mTimePaint);//底部線
            }
        }


    }

    public int dp2px(float dp) {

        return (int) (getResources().getDisplayMetrics().density * dp + .5f);
    }

    public  String getFormateTime(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(date);
    }

}
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved