Android-自定義View-自定義屬性之第三方Banner看一看

上一篇我們簡單實(shí)踐了下自定義屬性部分Android-自定義View-自定義屬性,現(xiàn)在我們看看第三方的自定義控件源碼,混個(gè)眼熟先。

Like,youth5201314/banner,下載一下zip包,然后解壓,AS導(dǎo)入module即可:

image

1. 從我們經(jīng)常使用的類(Banner)+配置入手(app:)

     <com.youth.banner.Banner
        android:id="@+id/finba_banner"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="8dp"
        app:banner_default_image="@drawable/home_list_img_default"
        app:banner_layout="@layout/banner_me"
        app:image_scale_type="center_crop"
        app:indicator_drawable_selected="@drawable/banner_rectangle_white_radius"
        app:indicator_drawable_unselected="@drawable/banner_rectangle_gray_radius"
        app:indicator_height="4dp"
        app:indicator_margin="3dp"
        app:indicator_width="10dp"
        app:title_textsize="16sp" />
image

2. 看構(gòu)造函數(shù) - 是不是會(huì)有之前相識(shí)的感覺妮?

 public Banner(Context context) {
        this(context, null);
    }

    public Banner(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public Banner(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.context = context;
        titles = new ArrayList<>();
        imageUrls = new ArrayList<>();
        imageViews = new ArrayList<>();
        indicatorImages = new ArrayList<>();
        dm = context.getResources().getDisplayMetrics();
        indicatorSize = dm.widthPixels / 80;
        initView(context, attrs);
    }

這個(gè)地方?jīng)]有第四個(gè)構(gòu)造函數(shù),因?yàn)榈谒膫€(gè)是5.0以后新增的,所以這個(gè)暫時(shí)不需要也沒關(guān)系。你看上面的寫法,是不是和之前我們了解的一樣。或許我們今后開始自定義做自己的自定義控件就是這樣的方式吧!

3. 重點(diǎn)看下自定義View的部分的具體操作 - handleTypedArray(...)

image

Banner.java

    private void handleTypedArray(Context context, AttributeSet attrs) {
        if (attrs == null) {
            return;
        }
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.Banner);
        mIndicatorWidth = typedArray.getDimensionPixelSize(R.styleable.Banner_indicator_width, indicatorSize);
        mIndicatorHeight = typedArray.getDimensionPixelSize(R.styleable.Banner_indicator_height, indicatorSize);
        mIndicatorMargin = typedArray.getDimensionPixelSize(R.styleable.Banner_indicator_margin, BannerConfig.PADDING_SIZE);
        mIndicatorSelectedResId = typedArray.getResourceId(R.styleable.Banner_indicator_drawable_selected, R.drawable.gray_radius);
        mIndicatorUnselectedResId = typedArray.getResourceId(R.styleable.Banner_indicator_drawable_unselected, R.drawable.white_radius);
        scaleType = typedArray.getInt(R.styleable.Banner_image_scale_type, scaleType);
        delayTime = typedArray.getInt(R.styleable.Banner_delay_time, BannerConfig.TIME);
        scrollTime = typedArray.getInt(R.styleable.Banner_scroll_time, BannerConfig.DURATION);
        isAutoPlay = typedArray.getBoolean(R.styleable.Banner_is_auto_play, BannerConfig.IS_AUTO_PLAY);
        titleBackground = typedArray.getColor(R.styleable.Banner_title_background, BannerConfig.TITLE_BACKGROUND);
        titleHeight = typedArray.getDimensionPixelSize(R.styleable.Banner_title_height, BannerConfig.TITLE_HEIGHT);
        titleTextColor = typedArray.getColor(R.styleable.Banner_title_textcolor, BannerConfig.TITLE_TEXT_COLOR);
        titleTextSize = typedArray.getDimensionPixelSize(R.styleable.Banner_title_textsize, BannerConfig.TITLE_TEXT_SIZE);
        mLayoutResId = typedArray.getResourceId(R.styleable.Banner_banner_layout, mLayoutResId);
        bannerBackgroundImage = typedArray.getResourceId(R.styleable.Banner_banner_default_image, R.drawable.no_banner);
        typedArray.recycle();
    }

其實(shí)就是獲取我們使用banner進(jìn)行配置時(shí)的一些個(gè)屬性。同時(shí)如果你不設(shè)置也是有默認(rèn)值的。獲取如下配置喲....TypedArray,不就是我們之前了解過的獲取方式么。

image

其中有一個(gè)屬性app:banner_layout我特別提一下(因?yàn)楹芏鄷r(shí)候可以自定義banner的樣式滿足產(chǎn)品需求,所以我們有必要關(guān)注;同時(shí)banner的一些個(gè)源碼我也自定義過一些實(shí)現(xiàn),所以我覺得加深對(duì)框架的理解還是蠻重要的)

image

3.1 然后你可以看看它如下的布局呀,屬性配置文件呀,基本也就熟套了...

image

**3.2 **其他的文件也可以過過眼,有時(shí)間一定要研究一下,因?yàn)槲募痛a不多,所以相對(duì)來講還好。而且你如果利用Viewpaper實(shí)現(xiàn)過banner無限輪播控件的話,看起這個(gè)應(yīng)該不會(huì)那么的難了。

image

主要是幾個(gè)部分:Banner(具體的控件實(shí)現(xiàn),對(duì)外提供) + 滑動(dòng)動(dòng)畫(transformer) + 圖片加載器....其中BannerScroller部分用到了ViewPaper的一個(gè)方法mScroller,這個(gè)方法是通過反射獲取 - 所以關(guān)于反射的知識(shí)有必要學(xué)習(xí),我前面有文章了解過Android-自定義注解-反射基礎(chǔ)

     private void initViewPagerScroll() {
        try {
            Field mField = ViewPager.class.getDeclaredField("mScroller");
            mField.setAccessible(true);
            mScroller = new BannerScroller(viewPager.getContext());
            mScroller.setDuration(scrollTime);
            mField.set(viewPager, mScroller);
        } catch (Exception e) {
            Log.e(tag, e.getMessage());
        }
    }

4. 最后關(guān)于我改動(dòng)的地方,提一下,就是一個(gè)文本顯示關(guān)鍵字高亮背景的效果

image

主要就是利用SpannableString進(jìn)行背景顏色文本顯示。

先看高亮工具類 HighLightKeyWordUtil.java

package com.youth.banner;

import android.content.Context;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class HighLightKeyWordUtil {
    /**
     * @param color 關(guān)鍵字顏色
     * @param text 文本
     * @param keyword 關(guān)鍵字
     * @return
     */
    public static SpannableString getHighLightKeyWord(int color, String text, String keyword) {
        SpannableString s = new SpannableString(text);
        Pattern p = Pattern.compile(keyword);
        Matcher m = p.matcher(s);
        while (m.find()) {
            int start = m.start();
            int end = m.end();
            s.setSpan(new ForegroundColorSpan(color), start, end,
                    Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
        return s;
    }

    /**
     * @param color 關(guān)鍵字顏色
     * @param text 文本
     * @param keyword 多個(gè)關(guān)鍵字
     * @return
     */
    public static SpannableString getHighLightKeyWord(int color, String text,String[] keyword) {
        SpannableString s = new SpannableString(text);
        for (int i = 0; i < keyword.length; i++) {
            Pattern p = Pattern.compile(keyword[i]);
            Matcher m = p.matcher(s);
            while (m.find()) {
                int start = m.start();
                int end = m.end();
                s.setSpan(new ForegroundColorSpan(color), start, end,
                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }
        return s;
    }

    /**
     * @param color 關(guān)鍵字背景顏色
     * @param text 文本
     * @param keyword 關(guān)鍵字
     * @return
     */
    public static SpannableString getBackgroudKeyWord(int tvcolor, int color, String text, String keyword) {
        SpannableString s = new SpannableString(text);
        Pattern p = Pattern.compile(keyword);
        Matcher m = p.matcher(s);
        //while (m.find()) {
        if (m.find()) {
            int start = m.start();
            int end = m.end();
            s.setSpan(new RoundBackgroundColorSpan(color, tvcolor, 10), start, end,
                    Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
        return s;
    }

    /**
     * @param color 關(guān)鍵字背景顏色
     * @param text 文本
     * @param keywords 多個(gè)關(guān)鍵字
     * @return
     */
    public static SpannableString getBackgroudKeyWord(int[] tvcolor, int[] color, String text, String[] keywords) {
        SpannableString s = new SpannableString(text);
        int strLength = 0;
        for (int i = 0; i < keywords.length; i++) {
            ///< 必須是開頭的才標(biāo)記背景,所以索引必須小于開頭內(nèi)容長度
            strLength += keywords[i].length();

            Pattern p = Pattern.compile(keywords[i]);
            Matcher m = p.matcher(s);
            ///< 只找開頭的,標(biāo)題中的不找
            //while (m.find()) {
            //if (m.find()) {
            if (m.find() && m.start() < strLength) {
                int start = m.start();
                int end = m.end();
                s.setSpan(new RoundBackgroundColorSpan(color[i], tvcolor[i], 10), start, end,
                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }
        return s;
    }
}

**然后使用的地方Banner.java --- **//bannerTitle.setText(titles.get(position - 1));是之前的寫法

   @Override
    public void onPageSelected(int position) {
        ......
         case BannerConfig.CIRCLE_INDICATOR_TITLE:
                bannerTitle.setText(HighLightKeyWordUtil.getBackgroudKeyWord(
                        new int[]{Color.parseColor("#ffffff"), Color.parseColor("#ffffff")},
                        new int[]{Color.parseColor("#febc48"), Color.parseColor("#f13b2f")},
                        titles.get(position - 1), new String[]{"獨(dú)家", "首發(fā)"}));
                //bannerTitle.setText(titles.get(position - 1));
                break;
        ......
    }

Last,基本的自定義屬性和獲取我們大概來講下。這個(gè)框架相對(duì)還好,不是特別復(fù)雜。有些框架就復(fù)雜了,不僅僅是這點(diǎn)代碼了。而且可能還融合了其他的優(yōu)秀的第三方,所以看起來相對(duì)更難一些。 不過我們慢慢來嘛。順便也已多看看別人做框架是怎么做的,怎么別人如此優(yōu)秀,而自己菜的像渣渣妮...

不是心靈雞湯 -- 輕輕的我將離開你,請(qǐng)將眼角的淚拭去.....嘿嘿!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容