移植自定义View过程中遇到的问题及解决方法

时间:2021-01-16 16:32:52

移植自定义View过程中遇到的问题及解决方法

2012-01-12

问题背景:最近在做camera界面调整的时候,界面需要参考2.3.5的switcher控件,如下:

移植自定义View过程中遇到的问题及解决方法

功能是相机和摄像机相互切换,在移植到SP8825平台上时,发现布局出现颠倒现象,变为:

移植自定义View过程中遇到的问题及解决方法

跟踪到相应布局文件,发现最外层LinearLayout的orientation是vertical即垂直布局,改成水平的horizontal后布局变成:

移植自定义View过程中遇到的问题及解决方法

再次查看图片,发现图片是垂直的,再次把图片旋转,这次布局正常了,但是发现里面小圆圈开关滑动到右侧的时候就消失了,怎么调也调不出来,在这里卡住了很久,今天终于完美解决,问题现象如下:

 移植自定义View过程中遇到的问题及解决方法滑动小圆圈开关-->移植自定义View过程中遇到的问题及解决方法  继续滑动-->移植自定义View过程中遇到的问题及解决方法

再滑动-->移植自定义View过程中遇到的问题及解决方法  再往右滑就变成-->移植自定义View过程中遇到的问题及解决方法  小圆圈开关消失

期间加了很多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方法在控件的父元素正要放置它的子控件时调用。它会问一个问题,你想要用多大地方啊?,然后传入两个参数——widthMeasureSpecheightMeasureSpec  

它们指明控件可获得的空间以及关于这个空间描述的元数据。  

  

 比返回一个结果要好的方法是你传递View的高度和宽度到setMeasuredDimension方法里。  

接下来的代码片段给出了如何重写onMeasure。注意,调用的本地空方法是来计算高度和宽度的。它们会译解widthHeightSpecheightMeasureSpec值,并计算出合适的高度和宽度值。  

查看后明白:要解决此问题,必须要重写这个方法:

   @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;

         }

至此,这个问题终于解决完成了~