Android 實戰開發總結(widget篇)

在日常開發中,常常因爲不同項目需求的共性,同時也是考慮到用戶使用方式的共性,會有許多複用性極高的代碼實現,這裏特地總結一下。

有圖有真相

實例描述

如上圖,這些都是日常開發中及常見APP中會遇到的樣式,有些看似簡單,實現起來卻較爲費勁;有些很常用,這裏只是提供一種思路,如果你有好意見,更好的實現方式,可以在評論中反饋哦!

這裏就按照圖中所示,從上到下依次展開來說

文本相關

  • 槓掉價(價格中間帶一條劃掉的橫向

    這個在購物類APP中算是常見的內容了,實現方式如下

/**
* 實現TextView 中間橫線效果
*/
        marketPrice.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
  • 價格精確到分

數字精確到分,其實從任何一種語言來說,都有很多實現方式,有很多自帶的API可以參考。這裏就從java語言來說兩種實現方式

/**
* 實現小數點後保留兩位
*/
        String valueStr = "88.8888";
        double valueDou = 88.8888;

        Price1.setText(ShoppingTools.FormatNum2(valueStr));
        Price2.setText(ShoppingTools.FormatNum2(valueDou));

這裏的Price1 和 Price2 分別是上圖中的88.88 和88.89,細心的你可能會說,爲什麼兩種不一樣。這裏我們可以看一下ShoppingTools類中的這兩個重載的靜態方法:

/**
     * 截取小數點後兩位,而不是四捨五入
     *
     * @param number
     * @return
     */
    public static String FormatNum2(String number) {
        String intNumber;
        if (number.contains(".")) {
            int dot_index = number.indexOf(".");

            System.err.println("the dot index is " + dot_index);

            try {
                intNumber = number.substring(0, dot_index + 3);
            } catch (Exception e) {
                intNumber = number + "0";

            }
            System.out.println(intNumber);
        } else {
            System.out.println(number);
            intNumber = number + ".00";

        }
        return intNumber;
    }

    /**
     * 小數點後保留兩位
     */
    public static String FormatNum2(double f) {
        BigDecimal bd = new BigDecimal(f);
        bd = bd.setScale(2, BigDecimal.ROUND_HALF_UP);
        System.err.println("------------" + bd);
        return bd.toString();

    }

這兩個重載的方法,分別就不同的入參做了小數點後保留兩位的操作,注意,這裏不是簡單的四捨五入,有時候四捨五入總有一方是要吃虧的。這裏,對於double類型的數據,暫時沒有想到可以直接截取兩位小數,不四捨五入的方法,做過的同學可以分享一下。

  • 簡單的富文本

    多樣化文本

對於上面這種文本變色的UI,就暫且叫做簡單的富文本吧。

這種UI,最笨的辦法就是幾個不同顏色TextView拼接起來。可能做一兩個你覺得無所謂,但是如果有需求需要你實現很多個這樣的拼接組合,你是不是想和產品聊聊呢。而且作爲一名程序猿,怎麼可以這樣呢?一定有什麼高大上的方法。方法的確是有,而且還不少。這裏就選兩種最常用的說說。

/**
* 實現TextView文本內變色
*/
        SpannableStringBuilder builder = new SpannableStringBuilder(richStyleTv.getText().toString());
        ForegroundColorSpan redSpan = new ForegroundColorSpan(Color.RED);
        ForegroundColorSpan greenSpan = new ForegroundColorSpan(Color.GREEN);
        builder.setSpan(redSpan, 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        builder.setSpan(greenSpan, 7, 8, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        richStyleTv.setText(builder);

好了,這麼長一大段代碼,就實現了上圖中第一行的變色文本。你可能覺得,寫這麼多,就實現那麼一行,還是不夠高大上呀。好了,下面就是簡單的寫法

richStyleTv1.setText(Html.fromHtml("第<font color=green></font>杯半價,第<font color=green></font>杯免費"));

這種寫法很簡短,而且還能很方便的設置字體。但如你所見,也有個很明顯的缺點,文本內容不可以動態修改,這一點上第一種寫法代碼雖多,卻沒有限制。關於SpannableStringBuilder,其實還有很多用法,這裏的用法只是冰山一角,有興趣的你可以去好好研究一番。

交互體驗

  • 密碼可見與否

    這個可以說是最常用的用戶體驗,登錄、註冊時都會用到。
    實現也是很簡單:

/**
         * 密碼明文顯示或密文顯示
         */
        show.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked) {
                    //明文顯示
                    passwordEdit.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
                } else {
                    passwordEdit.setTransformationMethod(PasswordTransformationMethod.getInstance());
                }
//這句話確保,點擊checkBox時,光標始終在最後,很有用呀               passwordEdit.setSelection(passwordEdit.getText().length());
            }
        });

這裏關於EditText光標始終保持在最後,也是一種友好的用戶體驗哦。

  • 驗證碼倒計時

    這種獲取驗證碼後倒計時的實現,一方面給用戶一種良好的體驗,同時也很大程度的避免了短信炸彈的問題

/**
         * 驗證碼倒計時實現
         */
        timer = new TimerCount(120, 1000, getCode);
        getCode.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (TextUtils.isEmpty(phoneNum.getText().toString())) {
                    T.showShort(mContext, "不能爲空");
                } else if (!ShoppingTools.isMobileNO(phoneNum.getText().toString())) {
                    T.showShort(mContext, "請輸入正確的手機號");
                } else {
                    timer.start();
                }

            }
        });

這裏首先判斷了輸入有效性,關於手機號有效性的判斷在網絡上有很多正則表達式實現,這裏就不再贅述。

我們看一下TimerCount類

public class TimerCount extends CountDownTimer {

    private Button bnt;

    public TimerCount(long millisInFuture, long countDownInterval, Button bnt) {
        super(millisInFuture*1000, countDownInterval);
        this.bnt = bnt;
    }


    @Override
    public void onFinish() {
        // TODO Auto-generated method stub
        bnt.setClickable(true);
        bnt.setBackgroundResource(R.color.addtocar);
        bnt.setText("獲取短信校驗碼");
    }

    @Override
    public void onTick(long arg0) {
        // TODO Auto-generated method stub
        bnt.setClickable(false);
        bnt.setBackgroundResource(R.color.yahui);
        bnt.setText("("+arg0 / 1000 + ")秒後重新獲取");
    }

}

這個類繼承自CountDownTimer ,並在其OnTick方法和onFinish方法中,實現構造函數中所使用View內容的動態變化。這裏以Button爲例,當然用ImageView也是OK 的,根據實際情況做調整即可,主要思路是一樣。

  • 動態驗證碼實現

對於這個動態驗證碼,在12306購買過火車票的同學一定不陌生,從登錄到購票,每一年爲了回家而搶票的那幾天,不知道輸了多少次驗證碼。當然了,現在的驗證碼已不像圖中這麼簡單,但在日常APP登錄驗證中用到的還是很多。

/**
         * 圖片驗證碼獲取及驗證
         */
        codeImg.setImageBitmap(SecurityCode.getInstance().createBitmap(300, 100, 15, mContext));
        /**
         * 點擊圖片生成新的驗證碼
         */
        codeImg.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                codeImg.setImageBitmap(SecurityCode.getInstance().createBitmap(300, 100, 15, mContext));
            }
        });

        verifyCode.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (SecurityCode.getInstance().Verification(inputCode.getText().toString().trim())) {
                    T.showShort(mContext, "OK");
                } else {
                    T.showShort(mContext, "WRONG");
                }
            }
        });

這裏看一下SecurityCode這個類。

public class SecurityCode {

    private static final char[] CHARS = { '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
            'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D',
            'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };

    private static SecurityCode bmpCode;

    public static SecurityCode getInstance() {
        if (bmpCode == null)
            bmpCode = new SecurityCode();
        return bmpCode;
    }

    private static final int DEFAULT_CODE_LENGTH = 4;// 隨機字符的個數

    private String code;
    private Random random = new Random();

    /**
     * 生成驗證碼圖片
     * 
     * @param width 寬度
     * @param height 高度
     * @param size 字體大小(以sp爲單位計算)
     * @param context
     * @return
     */
    public Bitmap createBitmap(int width, int height, int size, Context context) {

        int textSize = DensityUtils.sp2px(context, size);

        Bitmap codeBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(codeBitmap);

        TextPaint textPaint = new TextPaint();
        textPaint.setAntiAlias(true);
        textPaint.setTextSize(textSize);
        textPaint.setStrokeWidth(3);
        textPaint.setStyle(Paint.Style.STROKE);
        textPaint.setTextAlign(Paint.Align.CENTER);

        code = createCode();
        int x = (width - textSize * 3) / 2;
        int y = (height + textSize) / 2;
        for (int index = 0; index < code.length(); index++) {
            textPaint.setColor(randomColor(1));
            canvas.drawText(code.charAt(index) + "", (x + textSize * index), y, textPaint);
        }
        Random random = new Random();
        for (int i = 0; i < 5; i++) {
            textPaint.setStrokeWidth(2);
            textPaint.setColor(randomColor(1));
            canvas.drawLine(random.nextInt(width), random.nextInt(height), random.nextInt(width),
                    random.nextInt(height), textPaint);
        }
        canvas.save(Canvas.ALL_SAVE_FLAG);
        canvas.restore();
        return codeBitmap;
    }

    public String getCode() {
        return code;
    }

    public boolean Verification(String input){
        if (TextUtils.isEmpty(code))
            return false;

        if (TextUtils.isEmpty(input))
            return false;

        return code.equalsIgnoreCase(input);
    }

    // 驗證碼
    private String createCode() {
        StringBuilder buffer = new StringBuilder();
        for (int i = 0; i < DEFAULT_CODE_LENGTH; i++) {
            buffer.append(CHARS[random.nextInt(CHARS.length)]);
        }
        return buffer.toString();
    }

    // 隨機顏色
    private int randomColor(int rate) {
        int red = random.nextInt(256) / rate;
        int green = random.nextInt(256) / rate;
        int blue = random.nextInt(256) / rate;
        return Color.rgb(red, green, blue);
    }

}

對於這個實現的整體思路很簡單,就是從定義好的數組中隨機獲取4個 (這裏的默認值,當然也可以設定)字符,分別設置隨機的4個顏色,使用Canvas繪製出一副圖片。

當然了,在實際開發中,在本地動態的生成驗證碼並完成校驗,完全就是此地無銀三百兩的一種做法。更好的方式是,從服務器獲取圖片,並且由服務器完成用戶輸入校驗。這裏只是去了解了一下這種圖片驗證碼實現方式,以備不時之需。

  • BadgeView

這個BadgeView 也是很常見,每天打開手機,桌面上各種未讀消息都會以各種小紅圈加數字的方式提醒我們,趕緊去打開APP(尤其是對於某些強迫症患者)

/**
 * 角標更新
*/

        BadgeView numView = new BadgeView(mContext);
        numView.setBackground(9, getResources().getColor(R.color.enablebtn));
        numView.setTargetView(shopCarTab);
        numView.setHideOnNull(false);
        numView.setBadgeCount(0);

        plusImg.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int value = Integer.valueOf(numTv.getText().toString());
                value++;
                numTv.setText(String.valueOf(value));
                numView.setBadgeCount(value);
            }
        });

        subImg.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int value = Integer.valueOf(numTv.getText().toString());
                if (value > 1) {
                    value--;
                }
                numTv.setText(String.valueOf(value));
                numView.setBadgeCount(value);
            }
        });

這裏簡單模擬下購物車添加商品時,車內商品數量的變化。BadgeView作爲Github上有名的開源項目,代碼就不再這裏貼出。


好了,widget的第一次總結就先到這裏。

發佈了47 篇原創文章 · 獲贊 23 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章