移植自定义View过程中遇到的问题及解决方法
2012-01-12
问题背景:最近在做camera界面调整的时候,界面需要参考2.3.5的switcher控件,如下:
功能是相机和摄像机相互切换,在移植到SP8825平台上时,发现布局出现颠倒现象,变为:
跟踪到相应布局文件,发现最外层LinearLayout的orientation是vertical即垂直布局,改成水平的horizontal后布局变成:
再次查看图片,发现图片是垂直的,再次把图片旋转,这次布局正常了,但是发现里面小圆圈开关滑动到右侧的时候就消失了,怎么调也调不出来,在这里卡住了很久,今天终于完美解决,问题现象如下:
滑动小圆圈开关--> 继续滑动-->
再滑动--> 再往右滑就变成--> 小圆圈开关消失
期间加了很多Log跟踪调试,定位问题在自定义view的Switcher.java文件中,发现控件的getWidth()值和getHeight()的值均是57,这里发现就是小圆圈的长宽,getWidth()这个是View.java中的方法,布局代码如下:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/camera_switch_set"
android:orientation="horizontal"
android:layout_alignParentRight="true"
android:layout_marginBottom="30dp"
android:layout_centerInParent="true"
android:layout_height="wrap_content"
android:layout_width="wrap_content">
<com.android.camera.RotateImageViewandroid:id="@+id/video_switch_icon"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/btn_ic_mode_switch_video"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="70dp"
android:layout_height="35dp"
android:background="@drawable/btn_mode_switch_bg">
<com.android.camera.Switcher–>切换控件
android:id="@+id/camera_switch"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:src="@drawable/btn_mode_switch_knob" />
</LinearLayout>
<com.android.camera.RotateImageView
android:id="@+id/camera_switch_icon"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginBottom="3dp"
android:src="@drawable/btn_ic_mode_switch_camera"/>
</LinearLayout>
Switcher继承的是ImageView类,如果在Switcher.java文件中调用getWidth()方法,得到的应该是上述代码中标记为浅蓝色LinearLayout的背景的宽度,也即btn_mode_switch_bg这张图片的宽度,而实际结果并不是如此。
于是重新看了一下自定义View的一些事项:
发现自定义view中有一个onMeasure()方法,查看该方法的作用:
onMeasure方法在控件的父元素正要放置它的子控件时调用。它会问一个问题,“你想要用多大地方啊?”,然后传入两个参数——widthMeasureSpec和heightMeasureSpec。
它们指明控件可获得的空间以及关于这个空间描述的元数据。
比返回一个结果要好的方法是你传递View的高度和宽度到setMeasuredDimension方法里。
接下来的代码片段给出了如何重写onMeasure。注意,调用的本地空方法是来计算高度和宽度的。它们会译解widthHeightSpec和heightMeasureSpec值,并计算出合适的高度和宽度值。
查看后明白:要解决此问题,必须要重写这个方法:
@Override
protectedvoid onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getMeasuredLength(widthMeasureSpec,true),getMeasuredLength(heightMeasureSpec, false));
}
private int getMeasuredLength(int length,boolean isWidth) {
intspecMode = MeasureSpec.getMode(length);
intspecSize = MeasureSpec.getSize(length);
intsize;
intpadding = isWidth ? getPaddingLeft() + getPaddingRight()
:getPaddingTop() + getPaddingBottom();
if(specMode == MeasureSpec.EXACTLY) {
size= specSize;
}else {
size = isWidth ? padding + getDrawable().getIntrinsicWidth()* 2 : getDrawable().getIntrinsicHeight() + padding;//这里指定相应的宽度和高度
if(specMode == MeasureSpec.AT_MOST) {
size= Math.min(size, specSize);
}
}
returnsize;
}
至此,这个问题终于解决完成了~