Android View 体系(1):View和ViewGroup体系结构
1 View和ViewGroup体系结构
1.1 View体系概要
Android的UI界面由View和ViewGroup及其子类组合而成。
View是所有UI组件的父类,其子类称为组件(Widget)。
ViewGroup是布局管理器,本身继承自View类,其子类称为布局(Layout)。
View的子类体系结构如下图:
1.2 View子类介绍
1.2.1 ViewGroup
ViewGroup的直接子类有:FrameLayout,LinearLayout,RelativeLayout,AbsoluteLayout,AdapterView,FragmentBreadCrumbs,SlidingDrawer
ViewGroup派生出的间接子类有:AbsListView, AbsSpinner, AdapterViewAnimator, AdapterViewFlipper, AppWidgetHostView, CalendarView, DatePicker, DialerFilter, ExpandableListView, Gallery, GestureOverlayView,GridView,HorizontalScrollView, ImageSwitcher,ListView,
1.2.2 TextView
为文本框设置多种颜色 :
TextView tv =(TextView)findViewById(R.id.tv_show);
SpannableStringBuilder style = new SpannableStringBuilder("蓝色:默认(红色)");
style.setSpan(new ForegroundColorSpan(Color.BLUE), 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
style.setSpan(new ForegroundColorSpan(Color.RED), 6, 8, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(style);
一行文字多种颜色:
String str = "<font color='red'>红色</font>" + "<font color= 'green'>绿色</font>";
TextView tv = new TextView(this);
tv.setText(Html.fromHtml(str));
1.2.3 ImageView
scaltype
CENTER 按原尺寸居中显示,图片长/宽超过View时截取图片居中部分
CENTER_CROP (当长或宽小于View时)按比例扩大尺寸居中显示,使图片长/宽不小于View的长/宽(可超出View)
CENTER_INSIDE (当长或宽大于View时)按比例缩小完整居中显示,使得图片长/宽不大于View长/宽
FIT_CENTER / FIT_CENTER (不管长或宽是大于或小于View)把图片按比例扩大/缩小到View的宽或高居中显示。
FIT_END / fitEnd 把图片按比例扩大/缩小到View的宽度,显示在View的下部分位置
FIT_START / fitStart 把图片按比例扩大/缩小到View的宽度,显示在View的上部分位置
FIT_XY / fitXY 把图片不按比例扩大/缩小到View的大小显示
MATRIX / matrix 用矩阵来绘制,动态缩小放大图片来显示。
1.2.4 SurfaceView
SurfaceView就是在窗口上挖一个洞,它就是显示在这个洞里,其他的View是显示在窗口上。SurfaceView属于View的子类 它是专门为制作游戏而产生的,支持OpenGL ES库,2D和3D的效果都可以实现。
SurfaceView允许其他线程更新视图对象(执行绘制方法),而其他的View不允许这么做,它只允许UI线程更新视图对象。
适用于被动更新,例如频繁地刷新。
适用于子线程来主动刷新界面,比如一个小人一直跑动的效果,需要子线程不停的重绘人的状态,避免阻塞UI线程。
使用surfaceView,实现SurfaceHolder.Callback接口(SurfaceView的改变 、SurfaceView的创建 、SurfaceView 销毁):
//Surface的大小发生改变时调用。
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height);
//Surface创建时触发,一般在这里调用画面的线程
public void surfaceCreated(SurfaceHolder holder);
//销毁时触发,一般在这里将画面的线程停止、释放。
public void surfaceDestroyed(SurfaceHolder holder);
例:频繁拍照功能
<SurfaceView android:id="@+id/surfaceView" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1"/>
CameraMgr cameraMgr = new CameraMgr(this, R.id.surfaceView, true);
cameraMgr.SetEventListener(this);
cameraMgr.initCamera();
CameraMgr类代码清单:
public class CameraMgr {
private String TAG = "CameraMgr";
private Activity mContext;
private Camera mCamera;
private SurfaceView mPreView;
private SurfaceHolder mHolder;
private int cameraPosition = 1;//0代表前置摄像头,1代表后置摄像头
Camera.PictureCallback pictureCallback;
public CameraMgr(Activity context, @IdRes int surfaceViewId, boolean isFacingBack) {
this.mContext = context;
mPreView = (SurfaceView) mContext.findViewById(surfaceViewId);
this.cameraPosition = isFacingBack ? 0 : 1;
}
public void SetEventListener(Camera.PictureCallback listener) {
this.pictureCallback = listener;
}
private boolean checkCamera(Context context) {
// 可修改参数来判断设备是否支持Camera等功能
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
return true; // 支持Camera功能
} else {
return false;
}
}
private void getCamera() {
int cameraCount = Camera.getNumberOfCameras();//得到摄像头的个数
cameraInfo = new Camera.CameraInfo();
for (int i = 0; i < cameraCount; i++) {
Camera.getCameraInfo(i, cameraInfo);//得到每一个摄像头的信息
if (cameraPosition == 0) {
//前置
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
mCamera = Camera.open(i);
Log.e("mCamera", mCamera == null ? "失败" : "成功");
break;
}
} else {
//后置
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
mCamera = Camera.open(i);
break;
}
}
}
}
Camera.CameraInfo cameraInfo;
public boolean initCamera() {
if (checkCamera(mContext)) {
getCamera();
takePreview();
return true;
} else {
return false;
}
}
public void resetCamera() {
takePreview();
}
private void takePreview() {
mHolder = mPreView.getHolder();
mHolder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (mCamera != null && mHolder != null) {
setStartPreview(mCamera, mHolder);
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mCamera != null) {
mCamera.stopPreview();
if (mHolder != null) {
setStartPreview(mCamera, mHolder);
}
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
releaseCamera();
}
}); // 实现SurfaceHolder.Callback接口
mCamera.autoFocus(null);
setStartPreview(mCamera, mHolder);//启动预览
}
private void setStartPreview(Camera camera, SurfaceHolder holder) {
try {
// 设置显示取景画面到surfaceview
camera.setPreviewDisplay(holder);
// 设置相机参数
Camera.Parameters parameters = camera.getParameters();
parameters.setPictureFormat(ImageFormat.JPEG); // 相片保存的格式
parameters.setPictureSize(540, 960); // 相片保存的尺寸,因为是横屏所以长>高
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); // 自动对焦
if(mContext.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
parameters.set("orientation", "portrait");
camera.setDisplayOrientation(90);
} else {
parameters.set("orientation", "landscape");
camera.setDisplayOrientation(0);
}
// 启动预览
camera.startPreview();
} catch (IOException e) {
Log.e(TAG, "setStartPreview: setPreviewDisplay error");
}
}
public void releaseCamera() {
if (mCamera != null) {
mCamera.setPreviewCallback(null);
mCamera.stopPreview();//停掉原来摄像头的预览
mCamera.release();//释放资源
mCamera = null;//取消原来摄像头
}
}
public void takePicture() {
if (mCamera == null) {
return;
}
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPictureFormat(ImageFormat.JPEG); // 相片保存的格式
parameters.setPictureSize(540, 960); // 相片保存的尺寸,因为是横屏所以长>高
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); // 自动对焦
parameters.set("orientation", "portrait");
mCamera.setDisplayOrientation(90);//拍照旋转无效
try {
mCamera.takePicture(null, null, pictureCallback);// 拍照
} catch (Exception e) {
Log.e("takePicture", e.getMessage());
}
}
}
1.2.5 ProgressBar
style属性:
· Widget.ProgressBar.Horizontal //水平ProgressBar样式
· Widget.ProgressBar.Small //小环形进度条
· Widget.ProgressBar.Large //大环形进度条
· Widget.ProgressBar.Inverse
· Widget.ProgressBar.Small.Inverse
· Widget.ProgressBar.Large.Inverse
indeterminate 属性:
android:indeterminate 就是关于设置不精确的属性,设置为true的话,滚动条的当前值会自动在最小到最大值之间来回移动,形成这样一个动画效果
进度属性:
ProgressBar有两个进度,一个是android:progress(第一显示进度),另一个是android:secondaryProgress(第二显示进度),如在看网络视频时候都会有一个缓存的进度以及一个播放的进度。
常用方法:
· setProgress(int) 设置第一进度
· setSecondaryProgress(int) 设置第二进度
· getProgress() 获取第一进度
· getSecondaryProgress() 获取第二进度
· incrementProgress(int) 增加或减少第一进度
· incrementSecondaryProgress(int) 增加或减少第二进度
· getMax() 获取最大进度
1.2.6 AnalogClock
仪表盘时钟
1.2.7 KeyboardView
键盘控件,用于编写键盘。为了安全而APP自带键盘,比如手机银行。
1.2.8 ViewStub
轻量级的View,没有尺寸,不绘制任何东西,绘制或者移除时省时。
实现View的延迟加载,在需要的时候才加载View,起到节约内存提高性能的作用。
为ViewStub指定一个布局,在Inflate布局的时候,只有ViewStub会被初始化,被设置为可见的时候,或是调用了ViewStub.inflate()的时候,ViewStub所向的布局才会被Inflate实例化。
用法:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">
<Button
android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="点击加载ViewStub" />
<ViewStub
android:id="@+id/view_stub" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout="@layout/view_toload" />
</LinearLayout>
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
View view = ((ViewStub)findViewById(R.id.view_stub)).inflate();
TextView tv = (TextView) view.findViewById(R.id.tv_test);
tv.setText("view_toload中的TextView");
}
});
1.3 Android坐标系
1.3.1 View获取自身宽高
getHeight():获取View自身高度
getWidth():获取View自身宽度
View自身坐标
通过如下方法可以获得View到其父控件(ViewGroup)的距离:
getTop():获取View自身顶边到其父布局顶边的距离
getLeft():获取View自身左边到其父布局左边的距离
getRight():获取View自身右边到其父布局左边的距离
getBottom():获取View自身底边到其父布局顶边的距离
MotionEvent提供的方法
MotionEvent提供了各种获取焦点坐标的方法:
getX():获取点击事件距离控件左边的距离
getY():获取点击事件距离控件顶边的距离
getRawX():获取点击事件距离整个屏幕左边距离,即绝对坐标
getRawY():获取点击事件距离整个屏幕顶边的的距离,即绝对坐标