上一篇我们简单实践了下自定义属性部分Android-自定义View-自定义属性,现在我们看看第三方的自定义控件源码,混个眼熟先。
Like,youth5201314/banner,下载一下zip包,然后解压,AS导入module即可:
image1. 从我们经常使用的类(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. 看构造函数 - 是不是会有之前相识的感觉妮?
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);
}
这个地方没有第四个构造函数,因为第四个是5.0以后新增的,所以这个暂时不需要也没关系。你看上面的写法,是不是和之前我们了解的一样。或许我们今后开始自定义做自己的自定义控件就是这样的方式吧!
3. 重点看下自定义View的部分的具体操作 - handleTypedArray(...)
image 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();
}
其实就是获取我们使用banner进行配置时的一些个属性。同时如果你不设置也是有默认值的。获取如下配置哟....TypedArray,不就是我们之前了解过的获取方式么。
image其中有一个属性app:banner_layout我特别提一下(因为很多时候可以自定义banner的样式满足产品需求,所以我们有必要关注;同时banner的一些个源码我也自定义过一些实现,所以我觉得加深对框架的理解还是蛮重要的)
image3.1 然后你可以看看它如下的布局呀,属性配置文件呀,基本也就熟套了...
image**3.2 **其他的文件也可以过过眼,有时间一定要研究一下,因为文件和代码不多,所以相对来讲还好。而且你如果利用Viewpaper实现过banner无限轮播控件的话,看起这个应该不会那么的难了。
image主要是几个部分:Banner(具体的控件实现,对外提供) + 滑动动画(transformer) + 图片加载器....其中BannerScroller部分用到了ViewPaper的一个方法mScroller,这个方法是通过反射获取 - 所以关于反射的知识有必要学习,我前面有文章了解过Android-自定义注解-反射基础:
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. 最后关于我改动的地方,提一下,就是一个文本显示关键字高亮背景的效果
image主要就是利用SpannableString进行背景颜色文本显示。
先看高亮工具类 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 关键字颜色
* @param text 文本
* @param keyword 关键字
* @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 关键字颜色
* @param text 文本
* @param keyword 多个关键字
* @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 关键字背景颜色
* @param text 文本
* @param keyword 关键字
* @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 关键字背景颜色
* @param text 文本
* @param keywords 多个关键字
* @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++) {
///< 必须是开头的才标记背景,所以索引必须小于开头内容长度
strLength += keywords[i].length();
Pattern p = Pattern.compile(keywords[i]);
Matcher m = p.matcher(s);
///< 只找开头的,标题中的不找
//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[]{"独家", "首发"}));
//bannerTitle.setText(titles.get(position - 1));
break;
......
}
Last,基本的自定义属性和获取我们大概来讲下。这个框架相对还好,不是特别复杂。有些框架就复杂了,不仅仅是这点代码了。而且可能还融合了其他的优秀的第三方,所以看起来相对更难一些。 不过我们慢慢来嘛。顺便也已多看看别人做框架是怎么做的,怎么别人如此优秀,而自己菜的像渣渣妮...
不是心灵鸡汤 -- 轻轻的我将离开你,请将眼角的泪拭去.....嘿嘿!
网友评论