[转]TypeScript中文文档——基础类型 TypeScripts
转自:https://zhongsp.gitbooks.io/typescript-handbook/content/
介绍
为了让程序有价值,我们需要能够处理最简单的数据单元:数字,字符串,结构体,布尔值等。 TypeScript支持与JavaScript几乎相同的数据类型,此外还提供了实用的枚举类型方便我们使用。
布尔值
最基本的数据类型就是简单的true/false值,在JavaScript和TypeScript里叫做boolean(其它语言中也一样)。
let isDone: boolean = false;
数字
和JavaScript一样,TypeScript里的所有数字都是浮点数。 这些浮点数的类型是number。 除了支持十进制和十六进制字面量,Typescript还支持ECMAScript 2015中引入的二进制和八进制字面量。
let decLiteral: number = 6; let hexLiteral: number = 0xf00d; let binaryLiteral: number = 0b1010; let octalLiteral: number = 0o744;
字符串
JavaScript程序的另一项基本操作是处理网页或服务器端的文本数据。 像其它语言里一样,我们使用string表示文本数据类型。 和JavaScript一样,可以使用双引号(")或单引号(')表示字符串。
let name: string = "bob";
name = "smith";
你还可以使用模版字符串,它可以定义多行文本和内嵌表达式。 这种字符串是被反引号包围(` ),并且以${ expr }这种形式嵌入表达式
let name: string = `Gene`;
let age: number = 37;
let sentence: string = `Hello, my name is ${ name }.
I'll be ${ age + 1 } years old next month.`;
这与下面定义sentence的方式效果相同:
let sentence: string = "Hello, my name is " + name + ".\n\n" + "I'll be " + (age + 1) + " years old next month.";
数组
TypeScript像JavaScript一样可以操作数组元素。 有两种方式可以定义数组。 第一种,可以在元素类型后面接上[],表示由此类型元素组成的一个数组:
let list: number[] = [1, 2, 3];
第二种方式是使用数组泛型,Array<元素类型>:
let list: Array<number> = [1, 2, 3];
元组 Tuple
元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。 比如,你可以定义一对值分别为string和number类型的元组。
// Declare a tuple type let x: [string, number]; // Initialize it x = ['hello', 10]; // OK // Initialize it incorrectly x = [10, 'hello']; // Error
当访问一个已知索引的元素,会得到正确的类型:
console.log(x[0].substr(1)); // OK console.log(x[1].substr(1)); // Error, 'number' does not have 'substr'
当访问一个越界的元素,会使用联合类型替代:
x[3] = 'world'; // OK, 字符串可以赋值给(string | number)类型 console.log(x[5].toString()); // OK, 'string' 和 'number' 都有 toString x[6] = true; // Error, 布尔不是(string | number)类型
联合类型是高级主题,我们会在以后的章节里讨论它。
枚举
enum类型是对JavaScript标准数据类型的一个补充。 像C#等其它语言一样,使用枚举类型可以为一组数值赋予友好的名字。
enum Color {Red, Green, Blue}; let c: Color = Color.Green;
默认情况下,从0开始为元素编号。 你也可以手动的指定成员的数值。 例如,我们将上面的例子改成从1开始编号:
enum Color {Red = 1, Green, Blue}; let c: Color = Color.Green;
或者,全部都采用手动赋值:
enum Color {Red = 1, Green = 2, Blue = 4}; let c: Color = Color.Green;
枚举类型提供的一个便利是你可以由枚举的值得到它的名字。 例如,我们知道数值为2,但是不确定它映射到Color里的哪个名字,我们可以查找相应的名字:
enum Color {Red = 1, Green, Blue}; let colorName: string = Color[2];
alert(colorName);
任意值
有时候,我们会想要为那些在编程阶段还不清楚类型的变量指定一个类型。 这些值可能来自于动态的内容,比如来自用户输入或第三方代码库。 这种情况下,我们不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。 那么我们可以使用any类型来标记这些变量:
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean
在对现有代码进行改写的时候,any类型是十分有用的,它允许你在编译时可选择地包含或移除类型检查。 你可能认为Object有相似的作用,就像它在其它语言中那样。 但是Object类型的变量只是允许你给它赋任意值 - 但是却不能够在它上面调用任意的方法,即便它真的有这些方法:
let notSure: any = 4;
notSure.ifItExists(); // okay, ifItExists might exist at runtime notSure.toFixed(); // okay, toFixed exists (but the compiler doesn't check) let prettySure: Object = 4;
prettySure.toFixed(); // Error: Property 'toFixed' doesn't exist on type 'Object'.
当你只知道一部分数据的类型时,any类型也是有用的。 比如,你有一个数组,它包含了不同的类型的数据:
let list: any[] = [1, true, "free"];
list[1] = 100;
空值
某种程度上来说,void类型像是与any类型相反,它表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是void:
function warnUser(): void {
alert("This is my warning message");
}
声明一个void类型的变量没有什么大用,因为你只能为它赋予undefined和null:
let unusable: void = undefined;
Null 和 Undefined
TypeScript里,undefined和null两者各自有自己的类型分别叫做undefined和null。 和void相似,它们的本身的类型用处不是很大:
// Not much else we can assign to these variables! let u: undefined = undefined; let n: null = null;
默认情况下null和undefined是所有类型的子类型。 就是说你可以把null和undefined赋值给number类型的变量。
然而,当你指定了--strictNullChecks标记,null和undefined只能赋值给void和它们各自。 这能避免很多常见的问题。 也许在某处你想传入一个string或null或undefined,你可以使用联合类型string | null | undefined。 再次说明,稍后我们会介绍联合类型。
注意:我们鼓励尽可能地使用
--strictNullChecks,但在本手册里我们假设这个标记是关闭的。
Never
never类型表示的是那些永不存在的值的类型。 例如,never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型; 变量也可能是never类型,当它们被永不为真的类型保护所约束时。
never类型是任何类型的子类型,也可以赋值给任何类型;然而,没有类型是never的子类型或可以赋值给never类型(除了never本身之外)。 即使any也不可以赋值给never。
下面是一些返回never类型的函数:
// 返回never的函数必须存在无法达到的终点 function error(message: string): never { throw new Error(message);
} // 推断的返回值类型为never function fail() { return error("Something failed");
} // 返回never的函数必须存在无法达到的终点 function infiniteLoop(): never { while (true) {
}
}
类型断言
有时候你会遇到这样的情况,你会比TypeScript更了解某个值的详细信息。 通常这会发生在你清楚地知道一个实体具有比它现有类型更确切的类型。
通过类型断言这种方式可以告诉编译器,“相信我,我知道自己在干什么”。 类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。 它没有运行时的影响,只是在编译阶段起作用。 TypeScript会假设你,程序员,已经进行了必须的检查。
类型断言有两种形式。 其一是“尖括号”语法:
let someValue: any = "this is a string"; let strLength: number = (<string>someValue).length;
另一个为as语法:
let someValue: any = "this is a string"; let strLength: number = (someValue as string).length;
两种形式是等价的。 至于使用哪个大多数情况下是凭个人喜好;然而,当你在TypeScript里使用JSX时,只有as语法断言是被允许的。
关于let
你可能已经注意到了,我们使用let关键字来代替大家所熟悉的JavaScript关键字var。 let关键字是JavaScript的一个新概念,TypeScript实现了它。 我们会在以后详细介绍它,很多常见的问题都可以通过使用let来解决,所以尽可能地使用let来代替var吧。
char a[] 和char *a的区别 C笔记
char a[] 和char *a的区别
char a[100] = "locck2";//OK char *b = "locck2" ;//OK
a和b都是指向字符串“locck2”的第一个字符的指针。
a数组是存放在栈中的,是可以通过指针修改数组内容的的;如:
a[1] = 'a';
而b指向的字符串是存放于常量区的,通过指针只能访问字符串常量,不能修改的。
char a[100] = "locck2";//在运行时才确认
而char *b="loccck2";在编译时就确定了,因为是常量。
内存分配方式
内存分配有三种:静态存储区、堆区和栈区。他们的功能不同,对他们使用方式也就不同。
- 静态存储区:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。它主要存放静态数据、全局数据和常量。
- 栈区:在执行函数时,函数(包括main函数)内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。(任何变量都处于站区,例如int a[] = {1, 2},变量a处于栈区。数组的内容也存在于栈区。)
- 堆区:亦称动态内存分配。程序在运行的时候用malloc或new申请任意大小的内存,程序员自己负责在适当的时候用free或delete释放内存。动态内存的生存期可以由我们决定,如果我们不释放内存,程序将在最后才释放掉动态内存。 但是,良好的编程习惯是:如果某动态内存不再使用,需要将其释放掉,并立即将指针置位NULL,防止产生野指针。
KcrusKal、Prime最短路径算法 Unity游戏研究
克鲁斯卡尔算法,克鲁斯卡尔
给定一个带权的无向连通图,如何选取一棵生成树,使树上所有边上权的总和为最小,这叫最小生成树. 求最小生成树的算法
(1) 克鲁斯卡尔算法
图的存贮结构采用边集数组,且权值相等的边在数组中排列次序可以是任意的.该方法对于边相对比较多的不是很实用,浪费时间.
(2) 普里姆算法
图的存贮结构采用邻接矩阵.此方法是按各个顶点连通的步骤进行,需要用一个顶点集合,开始为空集,以后将以连通的顶点陆续加入到集合中,全部顶点加入集合后就得到所需的最小生成树 .
下面来具体讲下:
克鲁斯卡尔算法
方法:将图中边按其权值由小到大的次序顺序选取,若选边后不形成回路,则保留作为一条边,若形成回路则除去.依次选够(n-1)条边,即得最小生成树.(n为顶点数)

第一步:由边集数组选第一条边
![]()
第二步:选第二条边,即权值为2的边

第三步:选第三条边,即权值为3的边

第四步:选第四条边,即权值为4的边

第五步:选第五条边
普里姆算法
方法:从指定顶点开始将它加入集合中,然后将集合内的顶点与集合外的顶点所构成的所有边中选取权值最小的一条边作为生成树的边,并将集合外的那个顶点加入到集合中,表示该顶点已连通.再用集合内的顶点与集合外的顶点构成的边中找最小的边,并将相应的顶点加入集合中,如此下去直到全部顶点都加入到集合中,即得最小生成树.
例在下图中从1点出发求出此图的最小生成树,并按生成树的边的顺序将顶点与权值填入表中.

———————>先写出其邻接矩阵

第一步:从①开始,①进集合,用与集合外所有顶点能构成的边中找最小权值的一条边
①——②权6
①——③权1 -> 取①——③边
①——④权5 第二步:③进集合,①,③与②,④,⑤,⑥构成的最小边为
①——④权5
③——⑥权4 -> 取③——⑥边 第三步:⑥进集合,①,③,⑥与②,④,⑤构成的各最小边
①——②权6
③——②权5
⑥——④权2 -> 取⑥——④边 第四步:④进集合,①,③,⑥,④与②,⑤构成的各最小边
①——②权6
③——②权5 -> 取③——②边
⑥——⑤权6 第四步:②进集合,①,③,⑥,②,④与⑤构成的各最小边
②——⑤权3 -> 取②——⑤边
Lua中的table函数库 Lua笔记
一部分的table函数只对其数组部分产生影响, 而另一部分则对整个table均产生影响. 下面会分开说明.
table.concat(table, sep, start, end)
concat是concatenate(连锁, 连接)的缩写. table.concat()函数列出参数中指定table的数组部分从start位置到end位置的所有元素, 元素间以指定的分隔符(sep)隔开。除了table外, 其他的参数都不是必须的, 分隔符的默认值是空字符, start的默认值是1, end的默认值是数组部分的总长.
sep, start, end这三个参数是顺序读入的, 所以虽然它们都不是必须参数, 但如果要指定靠后的参数, 必须同时指定前面的参数.
> tbl = {"alpha", "beta", "gamma"}
> print(table.concat(tbl, ":"))
alpha:beta:gamma
> print(table.concat(tbl, nil, 1, 2))
alphabeta
> print(table.concat(tbl, "\n", 2, 3))
beta
gamma
table.insert(table, pos, value)
table.insert()函数在table的数组部分指定位置(pos)插入值为value的一个元素. pos参数可选, 默认为数组部分末尾.
> tbl = {"alpha", "beta", "gamma"}
> table.insert(tbl, "delta")
> table.insert(tbl, "epsilon")
> print(table.concat(tbl, ", ")
alpha, beta, gamma, delta, epsilon
> table.insert(tbl, 3, "zeta")
> print(table.concat(tbl, ", ")
alpha, beta, zeta, gamma, delta, epsilon
table.maxn(table)
table.maxn()函数返回指定table中所有正数key值中最大的key值. 如果不存在key值为正数的元素, 则返回0. 此函数不限于table的数组部分.
> tbl = {[1] = "a", [2] = "b", [3] = "c", [26] = "z"}
> print(#tbl)
3 -- 因为26和之前的数字不连续, 所以不算在数组部分内
> print(table.maxn(tbl))
26
> tbl[91.32] = true
> print(table.maxn(tbl))
91.32
table.remove(table, pos)
table.remove()函数删除并返回table数组部分位于pos位置的元素. 其后的元素会被前移. pos参数可选, 默认为table长度, 即从最后一个元素删起.
table.sort(table, comp)
table.sort()函数对给定的table进行升序排序.
> tbl = {"alpha", "beta", "gamma", "delta"}
> table.sort(tbl)
> print(table.concat(tbl, ", "))
alpha, beta, delta, gamma
comp是一个可选的参数, 此参数是一个外部函数, 可以用来自定义sort函数的排序标准.
此函数应满足以下条件: 接受两个参数(依次为a, b), 并返回一个布尔型的值, 当a应该排在b前面时, 返回true, 反之返回false.
例如, 当我们需要降序排序时, 可以这样写:
> sortFunc = function(a, b) return b < a end
> table.sort(tbl, sortFunc)
> print(table.concat(tbl, ", "))
gamma, delta, beta, alpha
用类似的原理还可以写出更加复杂的排序函数. 例如, 有一个table存有工会三名成员的姓名及等级信息:
guild = {}
table.insert(guild, {
name = "Cladhaire",
class = "Rogue",
level = 70,
})
table.insert(guild, {
name = "Sagart",
class = "Priest",
level = 70,
})
table.insert(guild, {
name = "Mallaithe",
class = "Warlock",
level = 40,
})
对这个table进行排序时, 应用以下的规则: 按等级升序排序, 在等级相同时, 按姓名升序排序.
可以写出这样的排序函数:
function sortLevelNameAsc(a, b)
if a.level == b.level then
return a.name < b.name
else
return a.level < b.level
end
end
测试功能如下:
> table.sort(guild, sortLevelNameAsc)
> for idx, value in ipairs(guild) do print(idx, value.name) end
1, Mallaithe
2, Cladhaire
3, Sagart
table.foreachi(table, function(i, v))
会期望一个从 1(数字 1)开始的连续整数范围,遍历table中的key和value逐对进行function(i, v)操作
t1 = {2, 4, 6, language="Lua", version="5", 8, 10, 12, web="hello lua"};
table.foreachi(t1, function(i, v) print (i, v) end) ; --等价于foreachi(t1, print)
输出结果:
1 2
2 4
3 6
4 8
5 10
6 12
table.foreach(table, function(i, v))
与foreachi不同的是,foreach会对整个表进行迭代
t1 = {2, 4, 6, language="Lua", version="5", 8, 10, 12, web="hello lua"};
table.foreach(t1, function(i, v) print (i, v) end) ;
输出结果:
1 2
2 4
3 6
4 8
5 10
6 12
web hello lua
language Lua
version 5
table.getn(table)
返回table中元素的个数
t1 = {1, 2, 3, 5};
print(getn(t1))
->4
table.setn(table, nSize)
设置table中的元素个数
Lua pairs ipairs区别 Lua笔记
ipairs (t)
Returns three values: an iterator function, the table t, and 0, so that the construction
for i,v in ipairs(t) do body end
will iterate over the pairs (1,t[1]), (2,t[2]), ···, up to the first integer key absent from the table.
pairs (t)
Returns three values: the next function, the table t, and nil, so that the construction
for k,v in pairs(t) do body end
will iterate over all key–value pairs of table t.
See function next for the caveats of modifying the table during its traversal.
pairs可以遍历表中所有的key,并且除了迭代器本身以及遍历表本身还可以返回nil;
ipairs则不能返回nil,只能返回数字0,如果遇到nil则退出。
ipairs适用于数组,pairs适用于键值表。
skynet研究001——skynet Skynet笔记
一个由国内大神云风开发的基于C+lua的开源服务器框架(https://github.com/cloudwu/skynet)。
底层核心用c编写,上层逻辑由lua实现。
入门文档 http://skynetdoc.com/book/index.html
源码下载
git clone https://github.com/cloudwu/skynet.git
安装编译
cd skynet
make macosx
运行服务器demo
./skynet ./examples/config
运行客户端demo
./3rd/lua/lua ./examples/client.lua
输入hello 返回world
Unity与Photon通信简单文档 游戏服务器
Unity与Photon通信简单文档
主要的常用相关术语
Application
Application指的是游戏逻辑应用,由C#语言书写同时由Photon引擎负责启动运行。所有的应用均从Application继承。
Deploy Folder
即发布目录,在服务端SDK中,deploy目录包含了Photon引擎运行的所有需要的文件:Photon核心文件和应用程序文件。
Peer
即连接到Photon引擎的客户端,另一方面Photon服务器端也是Peer,且只有一个。
Channel
在Photon引擎中channel主要用于分割通信用,在同一channel中所有的operation和event都是顺序执行的。
Disconnect (Connect连接)
即服务器和客户端断开操作。通常发生在客户端断开连接或连接超时时候;服务器也可以根据需要断开和客户端之间的连接。
Event
Event是异步发送给客户端的事件消息。可以由操作(operations,如
sideeffect)触发或引发(这是operation的主要目的)。事件由事件代码(Eventcode)标识,事件来源则是ActorNumber。
EvCode
即EventCode简称,标识事件的类型以及事件所附带的信息。
Operation
对在Photon服务器端上远程方法调用的另外一种叫法。客户端使用operation可以在服务器上做任何事情,甚至可以发送event给其他客户端。
OpCode
“Operation Code”的简称。byte类型,用于触发服务器端操作,客户端获取操作返回结果,用opCodes判断返回动作类型。
PhotonControl
Photon的管理工具,打开PhotonControl.exe文件即可开启一个托盘应用。
PhotonServer.config
Photon引擎的配置文件,主要用于IP、应用以及性能检测设置。以前叫PhotonSocketServer.xml,目前刚刚改为PhotonSocketServer.config。
Timeout
使用eNet方式,客户端和服务器端都监视对方消息是否可靠,如果检测到长时间没有回应,则会断开连接。
Unreliable
不可靠的命令则不需要对方回应,它顺序发送数据,可能会有数据丢失,数据序列有“漏洞”。
通信过程
服务器端
1.在VS2010环境下建立一个空项目
2.添加引用
ExitGames.dll;
Photon.SocketServer.dll;
PhotonHostRuntimeInterfaces.dll;
3.创建一个类命名为Program.cs,添加Using
4.Program继承于ApplicationBase类,并实现其抽象类方法
5.添加一个类GamePeer.cs,同上添加Using,该Peer继承PeerBase类,实现其抽象类方法
6.生成项目保存到SimpleDemo/bin文件夹下,把SimpleDemo文件夹放到Photon 的deploy文件夹内(具体路径:../你的Photon解压文件夹/deploy)
7.配置Photon,根据你的系统,win7 64位打开deploy/bin_Win64文件夹下的PhotonServer.config文件,用txt打开,找到节点<Applications></Applications>,在此之内添加配置
<Application
Name="SimpleDemo"
BaseDirectory="SimpleDemo"
Assembly="SimpleDemo"
Type="SimpleDemo.Program"
ForceAutoRestart="true"
WatchFiles="dll;config"
ExcludeFiles="log4net.config">
</Application>
保存。 其中Name是应用程序(ServerApp)名字,BaseDirectory是应用程序(SimpleDemo/bin)所在文件夹,Assembly是应用程序集名称(在VS项目属性可以看到),Type指应用程序主程序名(相当于C#中Main函数所在文件名,本例中指Program.cs)(即继承于ApplicationBase类的),后边的是配置文件信息。
8.配置好后,打开同级目录下PhotonControl.exe程序即开启Photon程序,然后在任务栏旁边的Photon图标上右键Default/Start as application启动服务器,如果没有问题,Photon图标由灰色变成蓝色,表示启动成功,也可以右键Open Logs打开Log界面,看到Log信息“Server is running”则服务器启动了。
客户端(unity3d)
1.首先导入Photon SDK(Photon3Unity3D.dll)到unity工程,
2.创建客户端Peer类(ClientPeer.cs),添加Using,并继承IPhotonPeerListener类,而且实现其抽象类方法
3.连接到服务器,设置好服务器地址(包括端口号,一般使用Udp是5055)和服务器名称;然后创建Peer进行连接;
本地可以写成(“localhost:5055”),ServerApp指SimpleDemo
在Start()方法里连接服务器
在Update()方法里保持连接
4.实现ClientPeer中public void OnStatusChanged(StatusCode statusCode)方法,获取连接状态。
运行Unity3d,如果连接畅通,则Debug(“Connected”)信息。
通信操作
1.客户端向服务器发送数据
ClientPeer使用OpCustom方法向服务器发送数据
带三个参数 opCode:操作数,Parameters:内容(字典类型),SendReliable:是否可靠传输;
如:按下B,向服务器发送代号为201的操作;
2.服务端处理客户端请求
客户端发出的所有服务器请求都会在GamePeer类中的OnOperationRequest方法里接收到(丢包除外),接收到的参数operationRequest包括OpCode和Parameters,通过Opcode判断操作类型;
接收到代号为201的操作后,服务器向客户端发送一个Response(代号为99,带一个字符串数据),该Response只有发送201的Peer才能接收到。服务端也可以向客户端发送一个事件:
该事件所有连接上的Peer都能收到代码为100的消息事件。
3.客户端处理服务端发来的消息
所有服务端发来的Response消息都会在OnOperationResponse里接收,
4.所有服务端发来的Events事件都会在OnEvent里接收到
写点什么 人生杂谈
有时候总感觉得写点什么,却又不知道该写什么,觉得没什么可写,然后就不了了之了。
曾有多次思如泉涌的瞬间,有很多想表达的东西,关于人生,关于感悟,关于梦想,以为众多的思绪可以变成华丽的诗文,以为可以信手拈来,提笔即是篇章,却奈何腹中只剩零零散散的几个词语,越漂越远。
写点什么无非缅怀过去要么想想未来又或者只是一时冲动,很多时候开始都是想写点什么,然后什么都应该写点,到最后也不知道写的什么。人生又何偿不如是呢?有人说人生这条长河里,左岸是无法忘怀的记忆,右岸是可以憧憬的美好未来,中间流淌着的是值得奋斗的青春和隐隐的伤感。已过弱冠之年,人生正处于急流中间,有很多孩童时的快乐想去找回,却发现面对快步入而立的人生时,只有无能为力和伤感。曾经我一直在想什么是人生,生不带来死不带去的,人生又有什么意义?
过去是美好的。人却总喜欢在失去了的时候才发现曾经的美好,才去怀念。其实,每个人都是第一次做人,没有彩排,每天都不知道会发生什么,每天都是未知,走过那么多的岁月,会发现有很多没有把握的青春,也留下了不少的遗憾,同时也经历风雨变得成熟果敢。后来才想明白,原来人生本没有任何意义,而我们要做的则给人生添加意义。过去的每一天都是积累,是以后丰富人生的度量,。。。
有人说二十五是人生的一个转折,在这个尴尬的年纪,年经又不年经,懂又不懂,一无所有的时候,总以为自己有足够的资本去拼搏,仔细算来却发现还有很多事情没有去尝试,很多儿时的梦想尚未开始,回想当初的踌躇满志,个性与张扬,终究还是年少轻狂。
使用Fragment实现底部Tab标签切换界面功能 安卓应用开发
使用Fragment实现底部Tab标签切换界面功能
主界面布局
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.loccy.loccy.MainActivity">
<RelativeLayout
android:id="@+id/rl_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--<RelativeLayout-->
<!--android:id="@+id/top_tab"-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="50dip"-->
<!--android:background="#948a8a">-->
<!--<ImageView-->
<!--android:id="@+id/logo"-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="match_parent"-->
<!--android:layout_centerInParent="true"-->
<!--android:background="#f00"/>-->
<!--</RelativeLayout>-->
<LinearLayout
android:id="@+id/ll_bottom_tab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center_vertical"
android:orientation="horizontal"
android:baselineAligned="true"
android:background="#dadada">
<RelativeLayout
android:id="@+id/rl_tab_homepage"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
<ImageView
android:id="@+id/iv_tab_homepage"
android:layout_width="26dp"
android:layout_height="26dp"
android:paddingTop="5dp"
android:layout_centerHorizontal="true"
android:src="@drawable/tab_homepage_checked"
android:contentDescription="@null"/>
<TextView
android:id="@+id/tv_tab_homepage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="3dp"
android:layout_below="@+id/iv_tab_homepage"
android:layout_centerHorizontal="true"
android:text="@string/tab_homepage"
android:textColor="@color/tab_item_checked"
android:textSize="14sp"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/rl_tab_activity"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
<ImageView
android:id="@+id/iv_tab_activity"
android:layout_width="26dp"
android:layout_height="26dp"
android:paddingTop="5dp"
android:layout_centerHorizontal="true"
android:src="@drawable/tab_me_normal"
android:contentDescription="@null"/>
<TextView
android:id="@+id/tv_tab_activity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="3dp"
android:layout_below="@+id/iv_tab_activity"
android:layout_centerHorizontal="true"
android:text="@string/tab_activity"
android:textColor="@color/tab_item_normal"
android:textSize="14sp"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/rl_tab_message"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
<ImageView
android:id="@+id/iv_tab_message"
android:layout_width="26dp"
android:layout_height="26dp"
android:paddingTop="5dp"
android:layout_centerHorizontal="true"
android:src="@drawable/tab_message_normal"
android:contentDescription="@null"/>
<TextView
android:id="@+id/tv_tab_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="3dp"
android:layout_below="@+id/iv_tab_message"
android:layout_centerHorizontal="true"
android:text="@string/tab_message"
android:textColor="@color/tab_item_normal"
android:textSize="14sp"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/rl_tab_me"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
<ImageView
android:id="@+id/iv_tab_me"
android:layout_width="26dp"
android:layout_height="26dp"
android:paddingTop="5dp"
android:layout_centerHorizontal="true"
android:src="@drawable/tab_me_normal"
android:contentDescription="@null"/>
<TextView
android:id="@+id/tv_tab_me"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="3dp"
android:layout_below="@+id/iv_tab_me"
android:layout_centerHorizontal="true"
android:text="@string/tab_me"
android:textColor="@color/tab_item_normal"
android:textSize="14sp"/>
</RelativeLayout>
</LinearLayout>
<View
android:id="@+id/line"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_above="@id/ll_bottom_tab"
android:background="#cfcece">
</View>
<LinearLayout
android:id="@+id/content_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/line"
android:orientation="vertical">
</LinearLayout>
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>
主Activity控制切换
package com.loccy.loccy;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private RelativeLayout tab_homepage_lt,tab_activity_lt,tab_message_lt,tab_me_lt;
private Fragment homepage_fm,activity_fm,message_fm,me_fm,curFragment;
private static final int TABCOUNT = 4;
private ImageView[] tab_item_imgs = new ImageView[TABCOUNT];
private TextView[] tab_item_txts = new TextView[TABCOUNT];
private int[] img_ids = new int[]{R.id.iv_tab_homepage,R.id.iv_tab_activity,R.id.iv_tab_message,R.id.iv_tab_me};
private int[] txt_ids = new int[]{R.id.tv_tab_homepage,R.id.tv_tab_activity,R.id.tv_tab_message,R.id.tv_tab_me};
private int[] img_nor_ids = new int[]{R.drawable.tab_homepage_normal,R.drawable.tab_me_normal,R.drawable.tab_message_normal,R.drawable.tab_me_normal};
private int[] img_chd_ids = new int[]{R.drawable.tab_homepage_checked,R.drawable.tab_me_checked,R.drawable.tab_message_checked,R.drawable.tab_me_checked};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InitUI();
InitTab();
}
void InitUI(){
tab_homepage_lt = (RelativeLayout)findViewById(R.id.rl_tab_homepage);
tab_activity_lt = (RelativeLayout)findViewById(R.id.rl_tab_activity);
tab_message_lt = (RelativeLayout)findViewById(R.id.rl_tab_message);
tab_me_lt = (RelativeLayout)findViewById(R.id.rl_tab_me);
tab_homepage_lt.setOnClickListener(this);
tab_activity_lt.setOnClickListener(this);
tab_message_lt.setOnClickListener(this);
tab_me_lt.setOnClickListener(this);
for(int i=0;i<TABCOUNT;i++){
tab_item_imgs[i] = (ImageView)findViewById(img_ids[i]);
tab_item_txts[i] = (TextView)findViewById(txt_ids[i]);
}
}
void InitTab() {
if (homepage_fm == null)
homepage_fm = new HomeFragment();
if(!homepage_fm.isAdded()){
getSupportFragmentManager().beginTransaction().add(R.id.content_layout,homepage_fm).commit();
curFragment = homepage_fm;
for(int i=0;i<TABCOUNT;i++){
if(i==0){
tab_item_imgs[i].setImageResource(img_chd_ids[i]);
tab_item_txts[i].setTextColor(getResources().getColor(R.color.tab_item_checked));
}
else {
tab_item_imgs[i].setImageResource(img_nor_ids[i]);
tab_item_txts[i].setTextColor(getResources().getColor(R.color.tab_item_normal));
}
}
}
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.rl_tab_homepage:onClickTab(0);break;
case R.id.rl_tab_activity:onClickTab(1);break;
case R.id.rl_tab_message:onClickTab(2);break;
case R.id.rl_tab_me:onClickTab(3);break;
}
}
void onClickTab(int index){
switch (index){
case 0:{
if (homepage_fm == null)
homepage_fm = new HomeFragment();
addOrShowFragment(homepage_fm);
}
break;
case 1:{
if (activity_fm == null)
activity_fm = new ActivityFragment();
addOrShowFragment(activity_fm);
}
break;
case 2:{
if (message_fm == null)
message_fm = new MessageFragment();
addOrShowFragment(message_fm);
}
break;
case 3:{
if (me_fm == null)
me_fm = new MeFragment();
addOrShowFragment(me_fm);
}
break;
default:break;
}
for(int i=0;i<TABCOUNT;i++){
if(i==index){
tab_item_imgs[i].setImageResource(img_chd_ids[i]);
tab_item_txts[i].setTextColor(getResources().getColor(R.color.tab_item_checked));
}
else {
tab_item_imgs[i].setImageResource(img_nor_ids[i]);
tab_item_txts[i].setTextColor(getResources().getColor(R.color.tab_item_normal));
}
}
}
private void addOrShowFragment(Fragment fragment){
if(curFragment==fragment)
return;
if(!fragment.isAdded()) {
getSupportFragmentManager().beginTransaction().hide(curFragment).add(R.id.content_layout, fragment).commit();
}
else {
getSupportFragmentManager().beginTransaction().hide(curFragment).show(fragment).commit();
}
curFragment = fragment;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
Fragment布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/top_tab"
android:layout_width="match_parent"
android:layout_height="50dip"
android:background="#948a8a"
android:layout_weight="1">
<ImageView
android:id="@+id/logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:background="#837a7a"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/tab_homepage"
android:textColor="@color/white"
android:textSize="24sp"/>
<Button
android:id="@+id/locate_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:background="#0000"
android:text="深圳"
android:textSize="24sp"/>
</RelativeLayout>
</LinearLayout>
Fragment代码
package com.loccy.loccy;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;
/**
* Created by Loccy on 16/3/17.
*/
public class HomeFragment extends Fragment{
private Button search_btn,locate_btn;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//return super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.fragment_homepage,container,false);
locate_btn = (Button)view.findViewById(R.id.locate_btn);
locate_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getContext(), "Locate", Toast.LENGTH_SHORT).show();
}
});
return view;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}

