本节内容
1.View的基本属性
2.view实现监听事件的几种方式
3.使用高阶函数接收回调
4.shape资源使用
5.触摸事件传递过程源码分析
6.判断触摸点是否在某个视图中
7.状态栏和标题栏的高度计算
8.触摸点坐标转化大小
9.onWindowsFocusChanged方法
一、View的基本属性
1.创建一个xml界面,添加一个View控件,点击它,右侧就会出现很多它的属性
image.png
底下还有很多属性,没有都截出来。简单介绍一些常用的属性。
-
2.View的background属性,背景可以是纯粹的颜色,也可以是一张背景图片。
-
3.alpha:透明度,0为完全透明,1为完全不透明。可以通过alpha实现渐变的动画。
-
4.clickable:如果为true,表示可以被点击。如果为false,表示不能被点击。
-
5.focusable:是否可以获得焦点,一般与clickable同步使用,且一般都是true或false,它们的状态值是一样的。
-
6.id:唯一表示控件在容器中的标识符。
-
7.tag:标签,字符串。功能:①记录数据 ②通过标签获取控件
8.当有id时,可以直接通过id访问这个控件。当id不明确时,可以通过tag访问控件。
val mView = container.findViewWithTag<View>("1")
mView.alpha=1f
mView.background = getDrawable(R.color.colorAccent)
9.可以通过onClick设置点击事件。先在xml的代码中添加一个onClick,并命名。然后在MainActivity中实现自己命名的这个方法。
android:onClick="changeBg"
fun changeBg(view: View) {
view.background=getDrawable(R.color.colorPrimary)
}
二、View实现监听事件的几种方式
1.通过实现对应的接口,实现监听事件(自己监听事件)
mView.setOnClickListener(this)
override fun onClick(v: View?) {
v?.background= getDrawable(R.color.colorPrimaryDark)
}
-
View有一个OnClickListener的接口,这个接口里面有一个onClick方法。一旦点击界面,系统会触发一个performClick方法,它会去view里面找有没有listener,如果有的话,那么它就会去调用listener对应的方法,就是onClick方法。
-
比较麻烦的是,如果是的监听者设为this,那么还需要另外去实现onClickListener接口
2.直接声明一个类,实现对应的接口和方法(别人监听)用的很少
mView.setOnClickListener(MyListener())
inner class MyListener:View.OnClickListener {
override fun onClick(v: View?) {
v?.background= getDrawable(R.color.colorPrimary)
}
}
3.匿名内部类(用的比较多)
mView.setOnClickListener(object :View.OnClickListener{
override fun onClick(v: View?) {
v?.background= getDrawable(R.color.colorPrimary)
}
})
4.如果实现的接口只有一个 可以使用lambda表达式
mView.setOnClickListener({v:View? ->
v?.background= getDrawable(R.color.colorPrimary)
})
5.如果这个方法的最后一个参数是lambda表达式,那么这个表达式可以放在括号外边
mView.setOnClickListener{v:View? ->
v?.background= getDrawable(R.color.colorPrimary)
}
6.如果这个方法只有一个参数,那么这个参数可以省略(用的比较多)
mView.setOnClickListener{
it?.background= getDrawable(R.color.colorPrimary)
}
三、使用高阶函数接收回调
1.它可以直接使用一个函数来作为返回值
2.高阶函数应用举例
-
创建一个类,在里面定义一个接收回调的函数,再定义一个触发事件。
class MyView {
//1.定义接收回调的函数/方法
var callBack:((String)->Unit)?= null
//2.事件触发
fun performClick(){
callBack?.let {
it("user:swl")
}
}
}
-
在MainActivity中创建一个对象,再接收回调。因为callBack只有一个参数,所以这个参数可以省略。callBack一般只关心参数。
//创建对象
val myView = MyView()
//接收回调
myView.callBack = {
Log.v("swl","主页接收到回调的数据了:$it")
}
mView.setOnClickListener{
myView.performClick()
}
四、shape资源的使用
1.让一个图片变成圆角。圆角的图片在生活中很常见,所以最好学会这个知识。
-
首先在drawable资源文件下new一个DrawableResourceFile,然后取一个名字。
-
打开之后呢,把<selector>改为<shape>,然后可以给它设置各种属性。形状设置为矩形。stroke是画笔的意思,里面设置的是画笔的颜色和宽度。solid是固定的意思,里面设置的是框框里面的颜色。
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="20dp"/>
<stroke android:color="@color/colorAccent"
android:width="2dp"/>
<solid android:color="@color/colorPrimary"/>
</shape>
-
<gradient>还可以设置渐变色。linear线性的,表示平铺过去的渐变。sweep,就是像扇形一样扫描过去的渐变。
<gradient android:type="linear" -->
android:startColor="@color/colorAccent"
android:centerColor="@color/colorPrimary"
android:endColor="@color/colorPrimaryDark"/>
2.前面说了,background可以是颜色,也可以是drawable里的资源文件,所以我们把xml中的背景换成我们刚刚新建的资源文件。
android:background="@drawable/shape_corner_radius"
五、触摸事件传递过程源码分析
1.触摸事件有几种事件类型,由MotionEvent类来管理
-
ACTION_DOWN 按下
-
ACTION_UP 离开屏幕
-
ACTION_MOVE 移动
-
ACTION_CANCEL 被其他应用打断
2.调用onTouchEvent方法来判断触摸事件的类型
override fun onTouchEvent(event: MotionEvent?): Boolean {
}
3.当触摸事件开始时,又会回调下面这个方法
override fun onUserInteraction() {
super.onUserInteraction()
Log.v("swl","触摸事件即将开启")
}
4.如果子控件需要接收触摸事件 就必须实现onTouchEvent,它的返回值类型为boolean, 当返回值为true时,表示这个事件已经被消费了,就不会继续传递。当返回值为false时,表示这个事件没有被消费,就继续传递。
六、判断触摸点是否在某个视图中
1.在onTouchEvent中判断是哪种点击事件,再做出相应的操作。这个方法可能被多次调用。
override fun onTouchEvent(event: MotionEvent?): Boolean {
when(event?.action){
MotionEvent.ACTION_DOWN -> {
Log.v("swl", "手指按下 x: ${event.x},y:${event.y}")
}
MotionEvent.ACTION_MOVE -> {
Log.v("swl","手指滑动")
}
MotionEvent.ACTION_UP ->{
Log.v("swl","手指离开屏幕")
}else -> Log.v("swl","被其他应用打断了")
}
return true
}
2.那么如何判断触摸点是否在某个视图中呢。有一个 Rect(l,t,r,b),其中 (rect是一个矩形区域)
* l:x,
* t:y,
* r:l + width ,
* b: t + height
还有一个point(x,y),可以获取当前点的坐标。
获取触摸点的x和y坐标
event.x 表示触摸点和屏幕的左边间距
event.y 表示触摸点和屏幕的上边间距
mView.x 相对于父容器的左边间距
mView.y 相对于父容器的顶部间距 没有bar和状态栏的高度
3.有一个requestRectangleOnScreen方法可以获取触摸点相对于屏幕的位置。rect是一个矩形区域。
val rect:Rect = Rect()
/获取这个控件在屏幕上的rect 相对于屏幕来说的尺寸
mView.requestRectangleOnScreen(rect)
rect.right = rect.left + mView.width
rect.bottom = rect.top + mView.height
4.判断某个rect是否包含某个点
rect.contains(event.x.toInt(),event.y.toInt()).also {
if(it){
mView.background= getDrawable(R.color.colorPrimary)
}else{
mView.background = getDrawable(R.color.colorAccent)
}
}
七、状态栏和标题栏的高度计算
image.png
-
红色框框起来的是绘制区域,绘制区域和屏幕顶部的距离为bar,也就是状态栏和标题栏。
1.每次获取触摸点到顶部的距离时,都会把bar给加上去,如果我们把这个高度计算出来,再用获取的top减去这部分距离,那么得到的就是相对于绘制区域顶部的高度。
将触摸点的y坐标减去顶部高度 ->获得相对于内容绘制区域的坐标
2.获取屏幕的尺寸
val display = DisplayMetrics()
windowManager.defaultDisplay.getMetrics(display)
Log.v("swl","屏幕尺寸 width:${display.widthPixels}, height : ${display.heightPixels}")
3.获取内容绘制区域的尺寸
val drawRect = Rect()
window.findViewById<ViewGroup>(Window.ID_ANDROID_CONTENT).getDrawingRect(drawRect)
4.计算顶部高度
val barHeight = display.heightPixels - drawRect.height()
八、触摸点坐标转化
1.将触摸点的y坐标 - 顶部高度 = 相对于内容绘制区域的坐标
viewRect.contains(event.x.toInt(),(event.y-barHeight).toInt()).also {
if(it){
mView.background= getDrawable(R.color.colorPrimary)
}else{
mView.background = getDrawable(R.color.colorAccent)
}
}
九、onWindowFocusChanged方法
1.前面计算状态栏和标题栏的代码,可以放在onWindowFocusChanged方法里面,因为这个方法被调用在onTouchEvent之前
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
//获取屏幕的尺寸
val display = DisplayMetrics()
windowManager.defaultDisplay.getMetrics(display)
Log.v("swl","屏幕尺寸 width:${display.widthPixels}, height : ${display.heightPixels}")
//获取内容绘制区域的尺寸
val drawRect = Rect()
//通过获取window上的content容器 ->容器的rect
window.findViewById<ViewGroup>(Window.ID_ANDROID_CONTENT).getDrawingRect(drawRect)
//顶部高度
val barHeight = display.heightPixels - drawRect.height()
}
网友评论