初来乍到,写点东西,方便自己以后用
首先要感谢鸿洋大神的自定义view攻略
自定义view分成几个部分,我自己选择的是顺序是:1view属性确定;2创建view并在构造方法中获取到属性;3重写onDraw; 4重写onMeasure;
View属性确定:
res/values中创建attr文件,里面写明的是自己需要填写的属性
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="bgColor" format="color"></attr>
<attr name="itemPadding" format="dimension"></attr>
<attr name="unPic" format="reference"></attr>
<attr name="inPic" format="reference"></attr>
<attr name="needNum" format="integer"></attr>
<declare-styleable name="PersonalView">
<attr name="bgColor"></attr>
<attr name="itemPadding"></attr>
<attr name="unPic"></attr>
<attr name="inPic"></attr>
<attr name="needNum"></attr>
</declare-styleable>
</resources>
可以从代码中看到,其中name为属性名,format为属性所需的值(其中dimesion为尺寸值如dp、sp,reference指的是指定值,例如R.drawable.****,其余的可以百度)
declare-styleable name 为自定义view的名称
然后我们在需要所在的activity的xml中可以写成如下
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="com.example.administrator.gasprogress.MainActivity">
<com.example.administrator.gasprogress.PersonalView
android:id="@+id/pView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:bgColor="@color/white"
app:itemPadding="7dp"
app:unPic="@drawable/ic_gray"
app:inPic="@drawable/ic_yellow"
app:needNum="15"
android:layout_centerInParent="true"
/>
</RelativeLayout>
view构造方法
public class PersonalView extends View {
private int mBgColor;
private int mPadding;
private Drawable mUnBg;
private Drawable mInBg;
private int mNum;
private Paint mPaint;
private Rect mBound;
private int LeastGas;
public int getLeastGas() {
return LeastGas;
}
public void setLeastGas(int leastGas) {
LeastGas = leastGas;
}
public PersonalView(Context context) {
this(context,null);
}
public PersonalView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public PersonalView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs,R.styleable.PersonalView,defStyleAttr,0);
int n = a.getIndexCount();
for(int i = 0;i<n;i++){
int attr = a.getIndex(i);
switch (attr){
case R.styleable.PersonalView_bgColor:
mBgColor = a.getColor(attr, Color.BLACK);
break;
case R.styleable.PersonalView_itemPadding:
mPadding = a.getDimensionPixelSize(attr,(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,5,getResources().getDisplayMetrics()));
break;
case R.styleable.PersonalView_unPic:
mUnBg = a.getDrawable(attr);
break;
case R.styleable.PersonalView_inPic:
mInBg = a.getDrawable(attr);
break;
case R.styleable.PersonalView_needNum:
mNum = a.getInt(attr,5);
break;
}
}
a.recycle();
mPaint = new Paint();
mBound = new Rect();
}
,这个参数就是在xml中获取的数值的调用,我个人理解就是,xml中付的值将通过这个参数在这里返还个自定义view,并使其可以调用,第三个参数defStyleAttr,这个
是一个默认的style,一般不会调用,具体大家可以自行百度。
重写OnDraw()
我这里是做一个类似音量条的一个view,所以其中主要是需要两个图层(因为是最基版,所以并没有加入拖动功能,也没有考虑特别全面,以后应该会完善),这里说明一下@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setColor(mBgColor); BitmapDrawable bgB = (BitmapDrawable)mUnBg; canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mPaint); // for(int x = 0;x<mNum;x++){ canvas.drawBitmap(bgB.getBitmap(),0+x*(bgB.getBitmap().getWidth()+mPadding),getHeight()/2-bgB.getBitmap().getHeight()/2,null); } BitmapDrawable fb = (BitmapDrawable)mInBg; canvas.saveLayer(0,0,0,0,null,Canvas.FULL_COLOR_LAYER_SAVE_FLAG); for(int x = 0;x <getLeastGas(); x++){ canvas.drawBitmap(fb.getBitmap(),0+x*(fb.getBitmap().getWidth()+mPadding),getHeight()/2-fb.getBitmap().getHeight()/2,null); } canvas.restore(); }
canvas如果要创建一个新图层,需要用到saveLayer这个方法,通过创建新图层,然后再还原最初图层,就可以得到一个覆盖的效果
重写onMeasure()
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { BitmapDrawable bit = (BitmapDrawable)mUnBg; int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int width; int height; if(widthMode == MeasureSpec.EXACTLY){ width = widthSize; }else { width = (bit.getBitmap().getWidth()+mPadding)*mNum-mPadding; } if(heightMode == MeasureSpec.EXACTLY){ height = heightSize; }else { height = bit.getBitmap().getHeight(); } setMeasuredDimension(width, height); }
EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
UNSPECIFIED:表示子布局想要多大就多大,很少使用
就这样一个很基本的自定view(音量条),就完成了,效果如图