安卓自定义view学习_1

首先感谢

http://blog.csdn.net/lmj623565791/article/details/24252901

http://blog.csdn.net/linghu_java/article/details/8532931

http://blog.csdn.net/xuwei527/article/details/11993103

文章的引导


首先是自定义属性文件:/res/values/attrs.xml

<resources>

    <attr name="titleText" format="string"></attr> //公共的属性名称 (就算在不同的<span style="font-family: Arial, Helvetica, sans-serif;"><declare-styleable ....></...>中也不能有同名的属性定义)</span>

    <!--
    <attr name="titleTextColor" format="color">@android:color/black</attr>
    <attr name="titleTextSize" format="dimension" >18sp</attr>
    -->

    <declare-styleable name="CustomTitleView">
        <attr name="titleText" /> //包含的公共的属性定义
        <attr name="titleTextColor" format="color" />
        <attr name="titleTextSize" format="dimension" />
    </declare-styleable>
    <declare-styleable name="TitleLayout">
        <attr name="borderWidth" format="dimension"></attr>
        <attr name="borderColor" format="color"></attr>
        <attr name="titleColor" format="color"></attr>
        <attr name="titleText"></attr>
    </declare-styleable>

</resources>

布局文件中要使用自定义属性时需要加  xmlns:custom="http://schemas.android.com/apk/res/应用包名“


自定义View

继承了View或者View的子类后,系统会提示需要实现三个构造方法中的一个,3个都实现,默认情况下(非用户new)会调用public  TitleFrameLayout(Context context, AttributeSet attrs)这个构造方法,若要在某个构造方法中去读取自定义属性值,则其他的构造方法需要调用这个构造方法,一般含有自定义属性的,都是在含有2个或含有3个参数的构造方法中读取自定义属性值。

构造方法取值

public TitleFrameLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
		Log.d("view test", "new 2");
		setWillNotDraw(false); //若继承的ViewGroup及其子类,则需要设置该方法,否则不会调用onDraw(...)
		TypedArray arr = context.obtainStyledAttributes(attrs,
				R.styleable.TitleLayout);//获得属性数组
		titleText = arr.getString(R.styleable.TitleLayout_titleText);//根据attrs.xml中定义的属性组名和属性名获取相应的值
		titleColor = arr.getColor(R.styleable.TitleLayout_titleColor,
				Color.BLACK);//获取颜色值,第二个参数为默认
		borderColor = arr.getColor(R.styleable.TitleLayout_borderColor,
				Color.BLACK);
		borderWidth = arr.getDimensionPixelSize(
				R.styleable.TitleLayout_borderWidth, (int) TypedValue
						.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 18,
								getResources().getDisplayMetrics()));//TypedValue.applyDimension(....)方法会根据第二个参数<span style="white-space:pre">												</span>//所给定的值使用第一个参数(即dip,sp)转换,第三个参数(根<span style="white-space:pre">												</span>//据屏幕分辨率等)进行缩放,从而得到给定的值在该分辨率下所<span style="white-space:pre">												</span>//显示出来的实际值
		arr.recycle();//完成读取值后,需要调用此方法
		mPaint = new Paint();//这个对象可以管理之后绘图要用到的颜色、字体、字体大小等信息
		titlePaint = new TextPaint();//专门用来处理文字绘制的Paint
		titlePaint.setTextSize(TypedValue.applyDimension(
				TypedValue.COMPLEX_UNIT_SP, 20, getResources()
						.getDisplayMetrics()));//设置文本字体大小
		titlePaint.density = getResources().getDisplayMetrics().density;//设置屏幕密度,用来后面计算文本所占的高宽面积
		titlePaint.setColor(titleColor);//设置绘制颜色
	}


主要重写方法onDraw(Canvas canvas)进行图像绘制

@Override
	protected void onDraw(Canvas canvas) {
		// super.onDraw(canvas);
		FontMetrics fm = titlePaint.getFontMetrics();//得到文本的字体相关属性
		Log.d("view test", fm.ascent + " a-d " + fm.descent);
		float textHeight = fm.descent - fm.ascent;//文本高度
		float textWidth = Layout.getDesiredWidth(titleText, titlePaint);//文本宽度
		float textStartX = getWidth() * 0.2f;
		float textEndX = textStartX + textWidth;
		float startY = textHeight * 2 / 3 + 0.5f;
		mPaint.setColor(borderColor);
		canvas.drawLine(0, startY, textStartX - 1, startY, mPaint);//绘制一根直线,这里的x/y坐标为相对本控件的x/y坐标,即左上角坐标为(0,0)
		canvas.drawLine(textEndX + 1, startY, getWidth() - 1, startY, mPaint);
		canvas.drawLine(0, startY, 0, getHeight() - 1, mPaint);
		canvas.drawLine(0, getHeight() - 1, getWidth() - 1, getHeight() - 1,
				mPaint);
		canvas.drawLine(getWidth() - 1, startY, getWidth() - 1,
				getHeight() - 1, mPaint);
		canvas.drawText(titleText, textStartX, textHeight, titlePaint);//绘制文本
	}

另外,若是继承ViewGroup及其子类,也许还需要控制其中子视图的绘制位置,需要重写onLayout(...)方法

@Override
	protected void onLayout(boolean changed, int left, int top, int right,
			int bottom) {
		FontMetrics fm = titlePaint.getFontMetrics();
		float textHeight = fm.descent - fm.ascent;
		Log.d("view test", "height - " + textHeight);
		layoutChildren(left, (int) (top + textHeight), right, bottom, true);
		// super.onLayout(changed, left, (int) (top + textHeight), right,
		// bottom);
		Log.d("view test", "onlayout - 	" + changed + " - " + left + " - "
				+ top + " - " + right + " - " + bottom);
	}

	void layoutChildren(int left, int top, int right, int bottom,
			boolean forceLeftGravity) {//拷贝FrameLayout中的方法,主要用来绘制子视图
		final int count = getChildCount();

		final int parentLeft = 1;
		final int parentRight = right - left - 1;

		final int parentTop = top;
		final int parentBottom = bottom - top - 1;

		for (int i = 0; i < count; i++) {
			final View child = getChildAt(i);
			if (child.getVisibility() != GONE) {
				final LayoutParams lp = (LayoutParams) child.getLayoutParams();

				final int width = child.getMeasuredWidth();
				final int height = child.getMeasuredHeight();

				int childLeft;
				int childTop;

				int gravity = lp.gravity;
				if (gravity == -1) {
					gravity = Gravity.TOP | Gravity.START;
				}

				// final int layoutDirection =
				// mMarginParams.getLayoutDirection();
				// final int absoluteGravity =
				// Gravity.getAbsoluteGravity(gravity,
				// layoutDirection);
				final int verticalGravity = gravity
						& Gravity.VERTICAL_GRAVITY_MASK;
				//
				// switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
				// case Gravity.CENTER_HORIZONTAL:
				// childLeft = parentLeft + (parentRight - parentLeft - width)
				// / 2 + lp.leftMargin - lp.rightMargin;
				// break;
				// case Gravity.RIGHT:
				// if (!forceLeftGravity) {
				// childLeft = parentRight - width - lp.rightMargin;
				// break;
				// }
				// case Gravity.LEFT:
				// default:
				// childLeft = parentLeft + lp.leftMargin;
				// }

				switch (verticalGravity) {
				case Gravity.TOP:
					childTop = parentTop + lp.topMargin;
					break;
				case Gravity.CENTER_VERTICAL:
					childTop = parentTop + (parentBottom - parentTop - height)
							/ 2 + lp.topMargin - lp.bottomMargin;
					break;
				case Gravity.BOTTOM:
					childTop = parentBottom - height - lp.bottomMargin;
					break;
				default:
					childTop = parentTop + lp.topMargin;
				}

				child.layout(parentLeft, childTop, parentLeft + width - 1,
						childTop + height - 1);
			}
		}
	}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值