Kotlin——2. 类的结构与分类
类的结构
类可以包括:
- 初始化块
- 初始化代码块(init)中可以使用主构造的参数;
- 构造函数
- 属性
- 函数
- 嵌套类和内部类
- 对象表达式
- 对象声明
类的模拟结构如下:
1 |
|
类的分类
数据类(data)- 特色:解构声明 & copy()
包含保存的数据和数据机械推导而来的函数的类,使用data
修饰.
构造
data class ClazzName(var param1:Int,val param2:String,...)
- 参数要求
val/var
修饰- 构造必须有参数,除非参数均设置默认值
- 修饰符要求:不能用抽象(
abstract
),开放(open
),密封,内部的; - 继承要求 - 只能实现接口
构造自动导出以下函数(除非 自行定义以下函数造成覆盖
):
equals()
hashCode()
toString()
格式为ClazzName(var param1=1,val param2="String",...)
- 根据参数(属性)声明顺序生成解构声明
component1(),component2()....componentN()
copy()
用于改变某个对象的某个属性,其他不变的情况val jack = User(name = "Jack", age = 1) val olderJack = jack.copy(age = 2)
解构声明 - 将一个对象属性同时赋值给一组的多个变量
val jane = User("Jane", 35)
val (name, age) = jane
//name与age为从对象jane获取值并同时声明的成员变量
val (name, age) = jane
相当于:
val name = jane.component1()
val age = jane.component2()
`componentN()` 函数需要用 **`operator`** 关键字标记,以允许在解构声明中使用它们。
注意:
可以用在
for-
循环中,经常用于a,b属性对于集合(可提供将映射表示为一个值的序列的iterator() 函数)中对象的属性的判断for ((a, b) in collection) { …… }
解构声明作为函数返回值存在的情况 (
val (param1,param2) = function(....)
),function()
函数返回对应数据类对象或标准类Pair<type1,type2>
解构声明对应数据类对象的参数的个数,不需要某个参数,可以使用
下划线"_"
代替
密封类 - 文件限制和When分支覆盖
是一个值为有限集中的类型、而不能有任何其他类型,可以有包含状态的多个实例的子类,并且 子类必须和基类位于同一个文件,孙类不做限制(在 Kotlin 1.1 之前, 子类必须嵌套在密封类声明的内部),使用sealed
关键字的类.
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
//when分支情况
fun eval(expr: Expr): Double = when(expr) {
is Const -> expr.number
is Sum -> eval(expr.e1) + eval(expr.e2)
NotANumber -> Double.NaN
// 不再需要 `else` 子句,因为我们已经覆盖了所有的情况
}
使用密封类的关键好处在于使用 when 表达式 的时候,如果能够 验证语句覆盖了所有情况,就不需要为该语句再添加一个 else 子句了。
嵌套类,内部类,匿名内部类
- 嵌套类是指嵌套于其他类中的类;
- 内部类有 inner 关键字,内部类可以访问外部类成员属性,持有外部类引用;
匿名内部类用于函数参数传入,与java相同,可以使用带接口类型前缀的lambda表达式创建它;
val listener = ActionListener { println("clicked") }
枚举类
枚举类的声明
- 使用enum关键字;
- 每一个枚举分别是一个当前类的对象,可以有初始化的值使用”()”包围;
当类需要定义其他成员属性或函数,要使用”;”将成员与其他分开;
enum class Direction { NORTH, SOUTH, WEST, EAST } //构造有参数,枚举有初始值 enum class Color(val rgb: Int) { RED(0xFF0000),GREEN(0x00FF00),BLUE(0x0000FF) } //自定义成员抽象函数,枚举对象实现函数 enum class ProtocolState { WAITING { override fun signal() = TALKING }, TALKING { override fun signal() = WAITING }; abstract fun signal(): ProtocolState }
枚举常量使用
枚举常量可以获得在类声明中名称和属性.
val name: String val ordinal: Int
枚举常量实现
Comparable
接口,自然排序顺序是定义顺序.枚举类有成方法允许列出定义的枚举常量以及通过名称获取枚举常量。
EnumClass.valueOf(value: String): EnumClass EnumClass.values(): Array<EnumClass>
使用
enumValues<T>()
和enumValueOf<T>()
函数以泛型的方式访问枚举类中的常量enum class RGB { RED, GREEN, BLUE } inline fun <reified T : Enum<T>> printAllValues() { print(enumValues<T>().joinToString { it.name }) } printAllValues<RGB>() // 输出 RED, GREEN, BLUE
本文参考自 Kotlin语言中心站
Kotlin——1. 包,数据类型,普通类,接口
包 - 当前包和导包
当前包
例如:
package demo
导包
当导入的类名相同时可以使用 as
指定某个类的新名称并不创建新的类.
例如:
import foo.Bar // Bar 可访问
import bar.Bar as bBar // bBar 代表“bar.Bar”
数据类型
基本数据类型 Byte,Short,Int,Long,Float,Double
- 字节比(单位bit位-> 字节):
Byte:Short:Int:Long:Float:Double = 8:16:32:64:32:64 = 1:2:4:8:4:8
; - Long类型后跟”L”,Float类型后跟”f” or “F”;
- 16进制表示:0x3FA;2进制表示:0b00000011;
- 可以使用下划线使易读;
较小的类型不能隐式转换为较大的类型,只能显式转换;
- toByte(): Byte - toShort(): Short - toInt(): Int - toLong(): Long - toFloat(): Float - toDouble(): Double - toChar(): Char
数据比较判断,涉及装箱.
需要可空引用时,数字、字符会被装箱。如下:
val a: Int = 10000 val boxedA: Int? = a val anotherBoxedA: Int? = a print(boxedA === anotherBoxedA) //false,装箱不同一性 print(boxedA == anotherBoxedA) //true,相等性
位运算符
- shl(bits) – 有符号左移 (Java 的 <<) - shr(bits) – 有符号右移 (Java 的 >>) - ushr(bits) – 无符号右移 (Java 的 >>>) - and(bits) – 位与 - or(bits) – 位或 - xor(bits) – 位异或 - inv() – 位非 例如: val x = (1 shl 2) and 0x000FF000 类似于x = (1 << 2) & 0x000FF000
Char
字符,可以使用.toInt()
显式转为Int
- 字符字面值用单引号括起来: '1'。 特殊字符可以用反斜杠转义。
- 支持这几个转义序列:\t、 \b、\n、\r、\'、\"、\\ 和 \$。
- 编码其他字符要用 Unicode 转义序列语法:'\uFF00'。
Array数组 - 创建和赋值(不形变)
库函数
arrayOf()
来创建一个数组并传递元素值给它val asc = arrayOf(1,2,3,4,5);//[1,2,3,4,5]
库函数
arrayOfNulls()
可以用于创建一个指定大小、元素都为空的数组。Array构造
// 创建一个 Array<String> 初始化为 ["0", "1", "4", "9", "16"] val asc = Array(5, { i -> (i * i).toString() }) // - 接受数组大小 // - 工厂函数,用作参数的函数能够返回,给定索引的每个元素初始值
- 其他未装箱的数组:ByteArray、 ShortArray、IntArray 等等。
字符串
原生字符串: 使用三引号包裹,没有转义字符序列的字符串
val text = """ | 这是什么 | 这是原生字符串 | 好像挺有意思的,前面这个是什么? | 边界前缀 """.trimMargin() // | 用作默认边界前缀,但你可以选择其他字符并作为参数传入 //比如 trimMargin(">")。
转义字符串: 可以有转义序列的字符串.\t、 \b、\n、\r、\’、\”、\ 和 \$。
字符串中使用 ‘ $ ‘ 引用要添加入字符串的值或 调用值和表达式(使用 “{“ 和 “}” ).原生字符串中需要${‘$’}.
val s = "abc" val str = "$s.length is ${s.length}" // str = "abc.length is 3"
普通类和接口
简单类和接口的定义
class ClazzName{}
class ClazzName //没有类体
interface Foo{
fun a()
fun b(){...}
}
class A:Foo{...}
- 类可以相互嵌套,可以继承或实现接口,使用
:
操作符; - 接口默认使用
open
关键字; - 接口函数可以有函数体.
本文参考自 Kotlin语言中心站
Android自定义控件之坐标与参数/对应函数
View之坐标与参数/对应函数
目录:
1. 坐标与坐标系
- mLeft: 以父容器左上为坐标原点,左上角X值
- mRight: 以父容器左上为坐标原点,右下角X值
- mTop: 以父容器左上为坐标原点,左上角Y值
- mBottom: 以父容器左上为坐标原点,右下角Y值
注意: offsetLeftAndRight(int offset)与offsetTopAndBottom(int offset)
用于View的平移.直接改变以上四个值
- translationX: 以父容器左上为坐标原点,X偏移量
- translationY: 以父容器左上为坐标原点,Y偏移量
注意: 偏移量使用setTranslationX/Y(float),原相对于父容器的坐标不会发生变化,
View通过坐标与偏移量的叠加进行绘制.
- MotionEvent#getX(): 以当前View左上为坐标原点,触摸点X值
- MotionEvent#getY(): 以当前View左上为坐标原点,触摸点Y值
- MotionEvent#getRawX():以屏幕左上为坐标原点,触摸点X值
- MotionEvent#getRawY():以屏幕左上为坐标原点,触摸点Y值
注意: 与触摸事件相关.
- mScrollX: 与View位置无关,View内容相对于原状态X方向的滚动量
- mScrollY: 与View位置无关,View内容相对于原状态Y方向的滚动量
注意: 向上/左,滚动量为正;反之为负.
- mPaddingLeft
- mPaddingRight
- mPaddingTop
- mPaddingBottom
2. 参数与函数
- width: getRight() - getLeft()
- height: getBottom() - getTop()
- measureWidth: mMeasuredWidth & MEASURED_SIZE_MASK
- measureHeight: mMeasuredHeight & MEASURED_SIZE_MASK
注: >>> width/height 与 measureWidth/measureHeight 区别在于赋值时机不同,
>>> measureWidth/measureHeight 形成于 measure 过程;
>>> width/height 形成于 layout 过程;
- getLocalVisibleRect(Rect)
- getGlobalVisibleRect(Rect,Point)
- getLocationOnScreen(int[2])
- getLocationInWindow(int[2])
Android自定义控件之事件分发机制表现与实现原理
事件分发机制表现与实现原理
http://blog.csdn.net/qq_23547831/article/details/51530671
表现图片来源: http://blog.csdn.net/chunqiuwei/article/details/41084921
Android自定义控件之 MotionEvent
MotionEvent
1. 不常用事件;
2. 多点触控事件;
3. 历史数据(事件批处理);
4. 获取事件发生的时间;
5. 获取压力(接触面积大小);
6. 鼠标事件;
参考自: http://www.gcssloop.com/customview/motionevent
Android自定义控件之测量,布局,绘制过程
控件的测量,布局,绘制过程
目录:
- 测量
1. 测量之MeasureSpec与LayoutParams
2. View # onMeasure(int,int)
3. ViewGroup # measureChildren()
4. 测量某个View的宽高的方式
- 布局
1. View # layout(int,int,int,int)
2. View # onLayout()
1. LinearLayout
2. RelativeLayout
3. FrameLayout
- 绘制
View # draw(Canvas)
1. Draw the background 绘制背景
2. If necessary, save the canvas' layers to prepare for fading
3. Draw view's content 绘制内容
4. Draw children 绘制子控件
5. If necessary, draw the fading edges and restore layers
6. Draw decorations (scrollbars for instance) 绘制附加内容
参考自:
1. 《 Android 开发艺术探索 》 : Page 174
2. Android开发之自定义控件(二)---onLayout详解 : http://blog.csdn.net/dmk877/article/details/49632959