自定义控件的高级自定义属性
Posted pszh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义控件的高级自定义属性相关的知识,希望对你有一定的参考价值。
情人节,代码和我可能更配吧。
看了标题肯定小伙伴们肯定会狠狠的鄙视一把,丢下一句 不就是自定义控件的自定义属性么拉倒了,这玩意谁不会,会一点自定义的谁都会了,然后就要关掉网页了,客官不急,请看下图,系统view调用自定义View的属性
实现的效果是:
这个时候 如果你对这个已经了解了 ,那就请丢下你的那句话,然后关掉这个网页吧,然后留下的吃瓜群众我们接着看
首先说下我们的实现思路
1.通过给有自定义属性的系统View嵌套一层控件,
2.获取到xml中给系统view赋值的属性值
3.然后把自定义的View的属性丢给这个控件,控件去实现这个自定义的属性就可以了
ok,完了 ,就是这么的简单,就是这么的easy,(那边的群众放下手中的西瓜刀,不要急躁,听小司机慢慢道来具体的实现)
准备工作:
a.首先我们要定义一个ViewGroup(继承自LinearLayout的CustomViewLinearLayout)用来包裹系统的View,
b. 自定义的属性的申明,(这里也啰嗦下)在valus下建立一个attrs文件,然后
<!--isChange 是否做个旋转动画 beginColor 开始的颜色 finishColor 结束的颜色-->
<declare-styleable name="customViewLinear">
<attr name="isChange" format="boolean"></attr>
<attr name="beginColor" format="color"></attr>
<attr name="finishColor" format="color"></attr>
</declare-styleable>
c.自定义个控件CoverFragment,实现系统view含有的自定义的属性的效果,这里贴下代码
public class CoverFragment extends FrameLayout
Handler handler = new Handler()
@Override
public void handleMessage(Message msg)
super.handleMessage(msg);
iniView();
;
private boolean isChange;
private int beginColor;
private int finishColor;
public void setChange(boolean change)
isChange = change;
public void setBeginColor(int beginColor)
this.beginColor = beginColor;
public void setFinishColor(int finishColor)
this.finishColor = finishColor;
public CoverFragment(Context context)
super(context);
//这里为了看到效果,做了下延迟,不然initView执行的时候判断都是错的
handler.sendEmptyMessage(1000);
public CoverFragment(Context context, AttributeSet attrs)
super(context, attrs);
//初始化
public void iniView()
if(isChange)//做一次旋转吧
float fromXScale = 1.0f;
float toScaleX = 0.5f;
float fromYScale = 1.0f;
float toScaleY = 0.5f;
float pivotX = getWidth() / 2;
float pivotY = getHeight() / 2;
Animation animate = new ScaleAnimation(fromXScale, toScaleX, fromYScale, toScaleY,pivotX, pivotY );
animate.setDuration(3000);
startAnimation(animate);
if(beginColor!=-1&&finishColor!=-1)//做一个颜色的渐变
if(Build.VERSION.SDK_INT >= 21)
ValueAnimator valueAnimator = ValueAnimator.ofArgb(beginColor, finishColor);
valueAnimator.setDuration(3000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
@Override
public void onAnimationUpdate(ValueAnimator animation)
int color = (int)animation.getAnimatedValue();
setBackgroundColor(color);
);
valueAnimator.start();
好了进入我们的主题了
1.给自定义Viewgroup的系统View套一层CoverFragment
这个里面用到的方法是addView(View child, int index, ViewGroup.LayoutParams params) ,不考虑到性能代码是
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params)
CoverFragment cf = new CoverFragment(getContext());//给原始控件嵌套一层的Fragment,
cf.addView(child);
super.addView(cf, index, params);
2.获取到xml中给系统view赋值的属性值
这里我们联想到的是LinearLayout怎么获取xml中的属性,应该是LinearLayout.LayoutParams对的吧,然后是通过generateLayoutParams(AttributeSet attrs),ok,没毛病吧,那我们也按照这个来进行仿写吧,首先自定义个layoutParams
//自定义LayoutParams,用来获取自定义的属性
public static class CustomViewLayoutParams extends LinearLayout.LayoutParams
public boolean isChange;
public int beginColor;
public int finishColor;
public CustomViewLayoutParams(Context context, AttributeSet attrs)
super(context, attrs);
TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.customViewLinear);
isChange = ta.getBoolean(R.styleable.customViewLinear_isChange,false);
beginColor = ta.getColor(R.styleable.customViewLinear_beginColor, -1);
finishColor = ta.getColor(R.styleable.customViewLinear_finishColor,-1);
ta.recycle();
然后改写 generateLayoutParams(AttributeSet attrs)方法
//拿到child里面的自定义属性
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs)
//返回自定义的LayoutParams
return new CustomViewLayoutParams(getContext(),attrs);
好,接下来第三步了
3.系统View获取到的自定义属性赋值给CoverFragment
依旧是在addView方法中,由于generateLayoutParams()方法是在addView()之前进行的,所以,这个时候params是带有属性的
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params)
CustomViewLayoutParams layoutParams = (CustomViewLayoutParams) params;
if(isCustomProperty(layoutParams))//有自定义属性的才给他嵌套控件,并复制值给那个控件
CoverFragment cf = new CoverFragment(getContext());//给原始控件嵌套一层的Fragment,
//复制属性给CoverFragment
cf.setChange(layoutParams.isChange);
cf.setBeginColor(layoutParams.beginColor);
cf.setFinishColor(layoutParams.finishColor);
cf.addView(child);
super.addView(cf, index, params);
else
super.addView(child, index, params);
ok这样就大功告成了 最后贴一下整个CustomViewLinearLayout的代码吧,
最后说下: 项目中的代码实现在这个demo中看起来很恶心。。。
1.比如为什么要给系统View去套一层view;不可以直接去让系统的View去实现那个属性的效果么
2.在包裹的控件自定义方法中使用handle,(这里的作用是为了让 系统的自定义的属性值能赋值到嵌套的控件上,在addView()中自定义嵌套控件的时候立刻执行initView方法是没有自定义的属性值的,所以延迟1秒让后面的赋值操作完成,)。
这个问题在你自定义一个滑动的控件的时候,当滑动到显示那个系统控件才做自定义属性的操作时,按照demo中的3个步骤就是没错的。而在这个demo中最好的方式是不嵌套view的,我不过是为了走这3步而写出来的。。。
以上是关于自定义控件的高级自定义属性的主要内容,如果未能解决你的问题,请参考以下文章