UI - 用户界面
<p>[TOC]</p>
<h1>用户界面: UI</h1>
<p>ui模块提供了编写用户界面的支持。</p>
<pre><code>给Android开发者或者高阶用户的提醒,Auto.js的UI系统来自于Android,所有属性和方法都能在Android源码中找到。如果某些代码或属性没有出现在Auto.js的文档中,可以参考Android的文档。
View: https://developer.android.google.cn/reference/android/view/View?hl=cn
Widget: https://developer.android.google.cn/reference/android/widget/package-summary?hl=cn</code></pre>
<p>带有ui的脚本的的最前面必须使用<code>"ui";</code>指定ui模式,否则脚本将不会以ui模式运行。正确示范:</p>
<pre><code>"ui";
//脚本的其他代码</code></pre>
<p>字符串"ui"的前面可以有注释、空行和空格<strong>[v4.1.0新增]</strong>,但是不能有其他代码。</p>
<p>界面是由视图(View)组成的。View分成两种,控件(Widget)和布局(Layout)。控件(Widget)用来具体显示文字、图片、网页等,比如文本控件(text)用来显示文字,按钮控件(button)则可以显示一个按钮并提供点击效果,图片控件(img)则用来显示来自网络或者文件的图片,除此之外还有输入框控件(input)、进度条控件(progressbar)、单选复选框控件(checkbox)等;布局(Layout)则是装着一个或多个控件的"容器",用于控制在他里面的控件的位置,比如垂直布局(vertical)会把他里面的控件从上往下依次显示(即纵向排列),水平布局(horizontal)则会把他里面的控件从左往右依次显示(即横向排列),以及帧布局(frame),他会把他里面的控件直接在左上角显示,如果有多个控件,后面的控件会重叠在前面的控件上。</p>
<p>我们使用xml来编写界面,并通过<code>ui.layout()</code>函数指定界面的布局xml。举个例子:</p>
<pre><code>"ui";
$ui.layout(
<vertical>
<button text="第一个按钮"/>
<button text="第二个按钮"/>
</vertical>
);</code></pre>
<p>在这个例子中,第3~6行的部分就是xml,指定了界面的具体内容。代码的第3行的标签<code><vertical> ... </vertical></code>表示垂直布局,布局的标签通常以<code><...></code>开始,以<code></...></code>结束,两个标签之间的内容就是布局里面的内容,例如<code><frame> ... </frame></code>。在这个例子中第4, 5行的内容就是垂直布局(vertical)里面的内容。代码的第4行是一个按钮控件(button),控件的标签通常以<code><...</code>开始,以<code>/></code>结束,他们之间是控件的具体属性,例如<code><text ... /></code>。在这个例子中<code>text="第一个按钮"</code>的部分就是按钮控件(button)的属性,这个属性指定了这个按钮控件的文本内容(text)为"第一个按钮"。</p>
<p>代码的第5行和第4行一样,也是一个按钮控件,只不过他的文本内容为"第二个按钮"。这两个控件在垂直布局中,因此会纵向排列,效果如图:</p>
<p><img src="images/ex1.png" alt="ex1" /></p>
<p>如果我们把这个例子的垂直布局(vertical)改成水平布局(horizontal),也即:</p>
<pre><code>"ui";
ui.layout(
<horizontal>
<button text="第一个按钮"/>
<button text="第二个按钮"/>
</horizontal>
);</code></pre>
<p>则这两个按钮会横向排列,效果如图:</p>
<p><img src="images/ex1-horizontal.png" alt="ex1-horizontal" /></p>
<p>一个控件可以指定多个属性(甚至可以不指定任何属性),用空格隔开即可;布局同样也可以指定属性,例如:</p>
<pre><code>"ui";
ui.layout(
<vertical bg="#ff0000">
<button text="第一个按钮" textSize="20sp"/>
<button text="第二个按钮"/>
</vertical>
);</code></pre>
<p>第三行<code>bg="#ff0000"</code>指定了垂直布局的背景色(bg)为"#ff0000",这是一个RGB颜色,表示红色(有关RGB的相关知识参见<a href="http://tool.oschina.net/commons?type=3">RGB颜色对照表</a>)。第四行的<code>textSize="20sp"</code>则指定了按钮控件的字体大小(textSize)为"20sp",sp是一个字体单位,暂时不用深入理会。上述代码的效果如图:</p>
<p><img src="images/ex1-properties.png" alt="ex-properties" /></p>
<p>一个界面便由一些布局和控件组成。为了便于文档阅读,我们再说明一下以下术语:</p>
<ul>
<li>子视图, 子控件: 布局里面的控件是这个布局的子控件/子视图。实际上布局里面不仅仅只能有控件,还可以是嵌套的布局。因此用子视图(Child View)更准确一些。在上面的例子中,按钮便是垂直布局的子控件。</li>
<li>父视图,父布局:直接包含一个控件的布局是这个控件的父布局/父视图(Parent View)。在上面的例子中,垂直布局便是按钮的父布局。</li>
</ul>
<h1>视图: View</h1>
<p>控件和布局都属于视图(View)。在这个章节中将介绍所有控件和布局的共有的属性和函数。例如属性背景,宽高等(所有控件和布局都能设置背景和宽高),函数<code>click()</code>设置视图(View)被点击时执行的动作。</p>
<h2>attr(name, value)</h2>
<ul>
<li><code>name</code> {string} 属性名称</li>
<li><code>value</code> {string} 属性的值</li>
</ul>
<p>设置属性的值。属性指定是View在xml中的属性。例如可以通过语句<code>attr("text", "文本")</code>来设置文本控件的文本值。</p>
<pre><code class="language-javascript">"ui";
$ui.layout(
<frame>
<text id="example" text="Hello"/>
</frame>
);
// 5秒后执行
$ui.post(() => {
// 修改文本
$ui.example.attr("text", "Hello, Auto.js UI");
// 修改背景
$ui.example.attr("bg", "#ff00ff");
// 修改高度
$ui.example.attr("h", "500dp");
}, 5000);</code></pre>
<p><strong>注意:</strong>并不是所有属性都能在js代码设置,有一些属性只能在布局创建时设置,例如style属性;还有一些属性虽然能在代码中设置,但是还没支持;对于这些情况,在Auto.js Pro 8.1.0+会抛出异常,其他版本则不会抛出异常。</p>
<h2>attr(name)</h2>
<ul>
<li><code>name</code> {string} 属性名称</li>
<li>返回 {string}</li>
</ul>
<p>获取属性的值。</p>
<pre><code class="language-javascript">"ui";
$ui.layout(
<frame>
<text id="example" text="1"/>
</frame>
);
plusOne();
function plusOne() {
// 获取文本
let text = $ui.example.attr("text");
// 解析为数字
let num = parseInt(text);
// 数字加1
num++;
// 设置文本
$ui.example.attr("text", String(num));
// 1秒后继续
$ui.post(plusOne, 1000);
}
</code></pre>
<h2>w</h2>
<p>View的宽度,是属性<code>width</code>的缩写形式。可以设置的值为<code>*</code>, <code>auto</code>和具体数值。其中<code>*</code>表示宽度<strong>尽量</strong>填满父布局,而<code>auto</code>表示宽度将根据View的内容自动调整(自适应宽度)。例如:</p>
<pre><code>"ui";
ui.layout(
<horizontal>
<button w="auto" text="自适应宽度"/>
<button w="*" text="填满父布局"/>
</horizontal>
);</code></pre>
<p>在这个例子中,第一个按钮为自适应宽度,第二个按钮为填满父布局,显示效果为:</p>
<p><img src="images/ex-w.png" alt="ex-w" /></p>
<p>如果不设置该属性,则不同的控件和布局有不同的默认宽度,大多数为<code>auto</code>。</p>
<p>宽度属性也可以指定一个具体数值。例如<code>w="20"</code>,<code>w="20px"</code>等。不加单位的情况下默认单位为dp,其他单位包括px(像素), mm(毫米), in(英寸)。有关尺寸单位的更多内容,参见<a href="#ui_尺寸的单位_Dimension">尺寸的单位: Dimension</a>。</p>
<pre><code>"ui";
ui.layout(
<horizontal>
<button w="200" text="宽度200dp"/>
<button w="100" text="宽度100dp"/>
</horizontal>
);</code></pre>
<h2>h</h2>
<p>View的高度,是属性<code>height</code>的缩写形式。可以设置的值为<code>*</code>, <code>auto</code>和具体数值。其中<code>*</code>表示宽度<strong>尽量</strong>填满父布局,而<code>auto</code>表示宽度将根据View的内容自动调整(自适应宽度)。</p>
<p>如果不设置该属性,则不同的控件和布局有不同的默认高度,大多数为<code>auto</code>。</p>
<p>宽度属性也可以指定一个具体数值。例如<code>h="20"</code>,<code>h="20px"</code>等。不加单位的情况下默认单位为dp,其他单位包括px(像素), mm(毫米), in(英寸)。有关尺寸单位的更多内容,参见<a href="#ui_尺寸的单位_Dimension">尺寸的单位: Dimension</a>。</p>
<h2>id</h2>
<p>View的id,用来区分一个界面下的不同控件和布局,一个界面的id在同一个界面下通常是唯一的,也就是一般不存在两个View有相同的id。id属性也是连接xml布局和JavaScript代码的桥梁,在代码中可以通过一个View的id来获取到这个View,并对他进行操作(设置点击动作、设置属性、获取属性等)。例如:</p>
<pre><code>"ui";
ui.layout(
<frame>
<button id="ok" text="确定"/>
</frame>
);
//通过ui.ok获取到按钮控件
toast(ui.ok.getText());</code></pre>
<p>这个例子中有一个按钮控件"确定",id属性为"ok",那么我们可以在代码中使用<code>ui.ok</code>来获取他,再通过<code>getText()</code>函数获取到这个按钮控件的文本内容。
另外这个例子中使用帧布局(frame)是因为,我们只有一个控件,因此用于最简单的布局帧布局。</p>
<h2>gravity</h2>
<p>View的"重力"。用于决定View的内容相对于View的位置,可以设置的值为:</p>
<ul>
<li><code>left</code> 靠左</li>
<li><code>right</code> 靠右</li>
<li><code>top</code> 靠顶部</li>
<li><code>bottom</code> 靠底部</li>
<li><code>center</code> 居中</li>
<li><code>center_vertical</code> 垂直居中</li>
<li><code>center_horizontal</code> 水平居中</li>
</ul>
<p>例如对于一个按钮控件,<code>gravity="right"</code>会使其中的文本内容靠右显示。例如:</p>
<pre><code>"ui";
ui.layout(
<frame>
<button gravity="right" w="*" h="auto" text="靠右的文字"/>
</frame>
);</code></pre>
<p>显示效果为:</p>
<p><img src="images/ex-gravity.png" alt="ex-gravity" /></p>
<p>这些属性是可以组合的,例如<code>gravity="right|bottom"</code>的View他的内容会在右下角。</p>
<h2>layout_gravity</h2>
<p>View在布局中的"重力",用于决定View本身在他的<strong>父布局</strong>的位置,可以设置的值和gravity属性相同。注意把这个属性和gravity属性区分开来。</p>
<pre><code>"ui";
ui.layout(
<frame w="*" h="*">
<button layout_gravity="center" w="auto" h="auto" text="居中的按钮"/>
<button layout_gravity="right|bottom" w="auto" h="auto" text="右下角的按钮"/>
</frame>
);</code></pre>
<p>在这个例子中,我们让帧布局(frame)的大小占满整个屏幕,通过给第一个按钮设置属性<code>layout_gravity="center"</code>来使得按钮在帧布局中居中,通过给第二个按钮设置属性<code>layout_gravity="right|bottom"</code>使得他在帧布局中位于右下角。效果如图:</p>
<p><img src="images/ex-layout-gravity.png" alt="ex-layout-gravity" /></p>
<p>要注意的是,layout_gravity的属性不一定总是生效的,具体取决于布局的类别。例如不能让水平布局中的第一个子控件靠底部显示(否则和水平布局本身相违背)。</p>
<h2>margin</h2>
<p>margin为View和其他View的间距,即外边距。margin属性包括四个值:</p>
<ul>
<li><code>marginLeft</code> 左外边距</li>
<li><code>marginRight</code> 右外边距</li>
<li><code>marginTop</code> 上外边距</li>
<li><code>marginBottom</code> 下外边距</li>
</ul>
<p>而margin属性本身的值可以有三种格式:</p>
<ul>
<li><code>margin="marginAll"</code> 指定各个外边距都是该值。例如<code>margin="10"</code>表示左右上下边距都是10dp。</li>
<li><code>margin="marginLeft marginTop marginRight marginBottom"</code> 分别指定各个外边距。例如<code>margin="10 20 30 40"</code>表示左边距为10dp, 上边距为20dp, 右边距为30dp, 下边距为40dp</li>
<li><code>margin="marginHorizontal marginVertical"</code> 指定水平外边距和垂直外边距。例如<code>margin="10 20"</code>表示左右边距为10dp, 上下边距为20dp。</li>
</ul>
<p>用一个例子来具体理解外边距的含义:</p>
<pre><code>"ui";
ui.layout(
<horizontal>
<button margin="30" text="距离四周30"/>
<button text="普通的按钮"/>
</horizontal>
);</code></pre>
<p>第一个按钮的margin属性指定了他的边距为30dp, 也就是他与水平布局以及第二个按钮的间距都是30dp, 其显示效果如图:</p>
<p><img src="images/ex1-margin.png" alt="ex1-margin" /></p>
<p>如果把<code>margin="30"</code>改成<code>margin="10 40"</code>那么第一个按钮的左右间距为10dp, 上下间距为40dp, 效果如图:</p>
<p><img src="images/ex2-margin.png" alt="ex2-margin" /></p>
<p>有关margin属性的单位,参见<a href="#ui_尺寸的单位_Dimension">尺寸的单位: Dimension</a>。</p>
<h2>marginLeft</h2>
<p>View的左外边距。如果该属性和margin属性指定的值冲突,则在后面的属性生效,前面的属性无效,例如<code>margin="20" marginLeft="10"</code>的左外边距为10dp,其他外边距为20dp。</p>
<pre><code>"ui";
ui.layout(
<horizontal>
<button marginLeft="50" text="距离左边50"/>
<button text="普通的按钮"/>
</horizontal>
);</code></pre>
<p>第一个按钮指定了左外边距为50dp,则他和他的父布局水平布局(horizontal)的左边的间距为50dp, 效果如图:</p>
<p><img src="images/ex-marginLeft.png" alt="ex-marginLeft" /></p>
<h2>marginRight</h2>
<p>View的右外边距。如果该属性和margin属性指定的值冲突,则在后面的属性生效,前面的属性无效。</p>
<h2>marginTop</h2>
<p>View的上外边距。如果该属性和margin属性指定的值冲突,则在后面的属性生效,前面的属性无效。</p>
<h2>marginBottom</h2>
<p>View的下外边距。如果该属性和margin属性指定的值冲突,则在后面的属性生效,前面的属性无效。</p>
<h2>padding</h2>
<p>View和他的自身内容的间距,也就是内边距。注意和margin属性区分开来,margin属性是View之间的间距,而padding是View和他自身内容的间距。举个例子,一个文本控件的padding也即文本控件的边缘和他的文本内容的间距,paddingLeft即文本控件的左边和他的文本内容的间距。</p>
<p>paddding属性的值同样有三种格式:</p>
<ul>
<li><code>padding="paddingAll"</code> 指定各个内边距都是该值。例如<code>padding="10"</code>表示左右上下内边距都是10dp。</li>
<li><code>padding="paddingLeft paddingTop paddingRight paddingBottom"</code> 分别指定各个内边距。例如<code>padding="10 20 30 40"</code>表示左内边距为10dp, 上内边距为20dp, 右内边距为30dp, 下内边距为40dp</li>
<li><code>padding="paddingHorizontal paddingVertical"</code> 指定水平内边距和垂直内边距。例如<code>padding="10 20"</code>表示左右内边距为10dp, 上下内边距为20dp。</li>
</ul>
<p>用一个例子来具体理解内边距的含义:</p>
<pre><code>"ui";
ui.layout(
<frame w="*" h="*" gravity="center">
<text padding="10 20 30 40" bg="#ff0000" w="auto" h="auto" text="HelloWorld"/>
</frame>
);</code></pre>
<p>这个例子是一个居中的按钮(通过父布局的<code>gravity="center"</code>属性设置),背景色为红色(<code>bg="#ff0000"</code>),文本内容为"HelloWorld",左边距为10dp,上边距为20dp,下边距为30dp,右边距为40dp,其显示效果如图:</p>
<p><img src="images/ex-padding.png" alt="ex-padding" /></p>
<h2>paddingLeft</h2>
<p>View的左内边距。如果该属性和padding属性指定的值冲突,则在后面的属性生效,前面的属性无效。</p>
<h2>paddingRight</h2>
<p>View的右内边距。如果该属性和padding属性指定的值冲突,则在后面的属性生效,前面的属性无效。</p>
<h2>paddingTop</h2>
<p>View的上内边距。如果该属性和padding属性指定的值冲突,则在后面的属性生效,前面的属性无效。</p>
<h2>paddingBottom</h2>
<p>View的下内边距。如果该属性和padding属性指定的值冲突,则在后面的属性生效,前面的属性无效。</p>
<h2>bg</h2>
<p>View的背景。其值可以是一个链接或路径指向的图片,或者RGB格式的颜色,或者其他背景。具体参见<a href="#draw">Drawables</a>。</p>
<p>例如,<code>bg="#00ff00"</code>设置背景为绿色,<code>bg="file:///sdcard/1.png"</code>设置背景为图片"1.png",<code>bg="?attr/selectableItemBackground"</code>设置背景为点击时出现的波纹效果(可能需要同时设置<code>clickable="true"</code>才生效)。</p>
<h2>alpha</h2>
<p>View的透明度,其值是一个0~1之间的小数,0表示完全透明,1表示完全不透明。例如<code>alpha="0.5"</code>表示半透明。</p>
<h2>foreground</h2>
<p>View的前景。前景即在一个View的内容上显示的内容,可能会覆盖掉View本身的内容。其值和属性bg的值类似。</p>
<h2>minHeight</h2>
<p>View的最小高度。该值不总是生效的,取决于其父布局是否有足够的空间容纳。</p>
<p>例:<code><text height="auto" minHeight="50"/></code></p>
<p>有关该属性的单位,参见<a href="#ui_尺寸的单位_Dimension">尺寸的单位: Dimension</a>。</p>
<h2>minWidth</h2>
<p>View的最小宽度。该值不总是生效的,取决于其父布局是否有足够的空间容纳。</p>
<p>例:<code><input width="auto" minWidth="50"/></code></p>
<p>有关该属性的单位,参见<a href="#ui_尺寸的单位_Dimension">尺寸的单位: Dimension</a>。</p>
<h2>visibility</h2>
<p>View的可见性,该属性可以决定View是否显示出来。其值可以为:</p>
<ul>
<li><code>gone</code> 不可见。</li>
<li><code>visible</code> 可见。默认情况下View都是可见的。</li>
<li><code>invisible</code> 不可见,但仍然占用位置。</li>
</ul>
<h2>rotation</h2>
<p>View的旋转角度。通过该属性可以让这个View顺时针旋转一定的角度。例如<code>rotation="90"</code>可以让他顺时针旋转90度。</p>
<p>如果要设置旋转中心,可以通过<code>transformPivotX</code>, <code>transformPivotY</code>属性设置。默认的旋转中心为View的中心。</p>
<h2>transformPivotX</h2>
<p>View的变换中心坐标x。用于View的旋转、放缩等变换的中心坐标。例如<code>transformPivotX="10"</code>。</p>
<p>该坐标的坐标系以View的左上角为原点。也就是x值为变换中心到View的左边的距离。</p>
<p>有关该属性的单位,参见<a href="#ui_尺寸的单位_Dimension">尺寸的单位: Dimension</a>。</p>
<h2>transformPivotY</h2>
<p>View的变换中心坐标y。用于View的旋转、放缩等变换的中心坐标。例如<code>transformPivotY="10"</code>。</p>
<p>该坐标的坐标系以View的左上角为原点。也就是y值为变换中心到View的上边的距离。</p>
<p>有关该属性的单位,参见<a href="#ui_尺寸的单位_Dimension">尺寸的单位: Dimension</a>。</p>
<h2>style</h2>
<p>设置View的样式。不同控件有不同的可选的内置样式。具体参见各个控件的说明。</p>
<p>需要注意的是,style属性只支持安卓5.1及其以上。</p>
<h1>文本控件: text</h1>
<p>文本控件用于显示文本,可以控制文本的字体大小,字体颜色,字体等。</p>
<p>以下介绍该控件的主要属性和方法,如果要查看他的所有属性和方法,请阅读<a href="http://www.zhdoc.net/android/reference/android/widget/TextView.html">TextView</a>。</p>
<h2>text</h2>
<p>设置文本的内容。例如<code>text="一段文本"</code>。</p>
<h2>textColor</h2>
<p>设置字体的颜色,可以是RGB格式的颜色(例如#ff00ff),或者颜色名称(例如red, green等),具体参见<a href="#ui_颜色">颜色</a>。</p>
<p>示例, 红色字体:<code><text text="红色字体" textColor="red"/></code></p>
<h2>textSize</h2>
<p>设置字体的大小,单位一般是sp。按照Material Design的规范,正文字体大小为14sp,标题字体大小为18sp,次标题为16sp。</p>
<p>示例,超大字体: <code><text text="超大字体" textSize="40sp"/></code></p>
<h2>textStyle</h2>
<p>设置字体的样式,比如斜体、粗体等。可选的值为:</p>
<ul>
<li>bold 加粗字体</li>
<li>italic 斜体 </li>
<li>normal 正常字体</li>
</ul>
<p>可以用或("|")把他们组合起来,比如粗斜体为"bold|italic"。</p>
<p>例如,粗体:`<text textStyle="bold" textSize="18sp" text="这是粗体"/></p>
<h2>lines</h2>
<p>设置文本控件的行数。即使文本内容没有达到设置的行数,控件也会留出相应的宽度来显示空白行;如果文本内容超出了设置的行数,则超出的部分不会显示。</p>
<p>另外在xml中是不能设置多行文本的,要在代码中设置。例如:</p>
<pre><code>"ui";
ui.layout(
<vertical>
<text id="myText" line="3">
</vertical>
)
//通过\n换行
ui.myText.setText("第一行\n第二行\n第三行\n第四行");</code></pre>
<h2>maxLines</h2>
<p>设置文本控件的最大行数。</p>
<h2>typeface</h2>
<p>设置字体。可选的值为:</p>
<ul>
<li><code>normal</code> 正常字体</li>
<li><code>sans</code> 衬线字体</li>
<li><code>serif</code> 非衬线字体</li>
<li><code>monospace</code> 等宽字体</li>
</ul>
<p>示例,等宽字体: <code><text text="等宽字体" typeface="monospace"/></code></p>
<h2>ellipsize</h2>
<p>设置文本的省略号位置。文本的省略号会在文本内容超出文本控件时显示。可选的值为:</p>
<ul>
<li><code>end</code> 在文本末尾显示省略号</li>
<li><code>marquee</code> 跑马灯效果,文本将滚动显示</li>
<li><code>middle</code> 在文本中间显示省略号</li>
<li><code>none</code> 不显示省略号</li>
<li><code>start</code> 在文本开头显示省略号</li>
</ul>
<h2>ems</h2>
<p>当设置该属性后,TextView显示的字符长度(单位是em),超出的部分将不显示,或者根据ellipsize属性的设置显示省略号。</p>
<p>例如,限制文本最长为5em: `<text ems="5" ellipsize="end" text="很长很长很长很长很长很长很长的文本"/></p>
<h2>autoLink</h2>
<p>控制是否自动找到url和电子邮件地址等链接,并转换为可点击的链接。默认值为“none”。</p>
<p>设置该值可以让文本中的链接、电话等变成可点击状态。</p>
<p>可选的值为以下的值以其通过或("|")的组合:</p>
<ul>
<li><code>all</code> 匹配所有连接、邮件、地址、电话</li>
<li><code>email</code> 匹配电子邮件地址</li>
<li><code>map</code> 匹配地图地址</li>
<li><code>none</code> 不匹配 (默认)</li>
<li><code>phone</code> 匹配电话号码</li>
<li><code>web</code> 匹配URL地址</li>
</ul>
<p>示例:<code><text autoLink="web|phone" text="百度: http://www.baidu.com 电信电话: 10000"/></code></p>
<h1>按钮控件: button</h1>
<p>按钮控件是一个特殊的文本控件,因此所有文本控件的函数的属性都适用于按钮控件。</p>
<p>除此之外,按钮控件有一些内置的样式,通过<code>style</code>属性设置,包括:</p>
<ul>
<li>Widget.AppCompat.Button.Colored 带颜色的按钮</li>
<li>Widget.AppCompat.Button.Borderless 无边框按钮</li>
<li>Widget.AppCompat.Button.Borderless.Colored 带颜色的无边框按钮</li>
</ul>
<p>这些样式的具体效果参见"示例/界面控件/按钮控件.js"。</p>
<p>例如:<code><button style="Widget.AppCompat.Button.Colored" text="漂亮的按钮"/></code></p>
<h1>输入框控件: input</h1>
<p>输入框控件也是一个特殊的文本控件,因此所有文本控件的函数的属性和函数都适用于按钮控件。输入框控件有自己的属性和函数,要查看所有这些内容,阅读<a href="http://www.zhdoc.net/android/reference/android/widget/EditText.html">EditText</a>。</p>
<p>对于一个输入框控件,我们可以通过text属性设置他的内容,通过lines属性指定输入框的行数;在代码中通过<code>getText()</code>函数获取输入的内容。例如:</p>
<pre><code>"ui";
ui.layout(
<vertical padding="16">
<text textSize="16sp" textColor="black" text="请输入姓名"/>
<input id="name" text="小明"/>
<button id="ok" text="确定"/>
</vertical>
);
//指定确定按钮点击时要执行的动作
ui.ok.click(function(){
//通过getText()获取输入的内容
var name = ui.name.getText();
toast(name + "您好!");
});</code></pre>
<p>效果如图:</p>
<p><img src="ex-input.png" alt="ex-input" /></p>
<p>除此之外,输入框控件有另外一些主要属性(虽然这些属性对于文本控件也是可用的但一般只用于输入框控件):</p>
<h2>hint</h2>
<p>输入提示。这个提示会在输入框为空的时候显示出来。如图所示:</p>
<p><img src="images/ex-hint.png" alt="ex-hint" /></p>
<p>上面图片效果的代码为:</p>
<pre><code>"ui";
ui.layout(
<vertical>
<input hint="请输入姓名"/>
</vertical>
)</code></pre>
<h2>textColorHint</h2>
<p>指定输入提示的字体颜色。</p>
<h2>textSizeHint</h2>
<p>指定输入提示的字体大小。</p>
<h2>inputType</h2>
<p>指定输入框可以输入的文本类型。可选的值为以下值及其用"|"的组合:</p>
<ul>
<li><code>date</code> 用于输入日期。</li>
<li><code>datetime</code> 用于输入日期和时间。</li>
<li><code>none</code> 没有内容类型。此输入框不可编辑。</li>
<li><code>number</code> 仅可输入数字。</li>
<li><code>numberDecimal</code> 可以与number和它的其他选项组合,以允许输入十进制数(包括小数)。</li>
<li><code>numberPassword</code> 仅可输入数字密码。</li>
<li><code>numberSigned</code> 可以与number和它的其他选项组合,以允许输入有符号的数。</li>
<li><code>phone</code> 用于输入一个电话号码。</li>
<li><code>text</code> 只是普通文本。</li>
<li><code>textAutoComplete</code> 可以与text和它的其他选项结合, 以指定此字段将做自己的自动完成, 并适当地与输入法交互。</li>
<li><code>textAutoCorrect</code> 可以与text和它的其他选项结合, 以请求自动文本输入纠错。</li>
<li><code>textCapCharacters</code> 可以与text和它的其他选项结合, 以请求大写所有字符。</li>
<li><code>textCapSentences</code> 可以与text和它的其他选项结合, 以请求大写每个句子里面的第一个字符。</li>
<li><code>textCapWords</code> 可以与text和它的其他选项结合, 以请求大写每个单词里面的第一个字符。</li>
<li><code>textEmailAddress</code> 用于输入一个电子邮件地址。</li>
<li><code>textEmailSubject</code> 用于输入电子邮件的主题。</li>
<li><code>textImeMultiLine</code> 可以与text和它的其他选项结合,以指示虽然常规文本视图不应为多行, 但如果可以, 则IME应提供多行支持。</li>
<li><code>textLongMessage</code> 用于输入长消息的内容。</li>
<li><code>textMultiLine</code> 可以与text和它的其他选项结合, 以便在该字段中允许多行文本。如果未设置此标志, 则文本字段将被限制为单行。</li>
<li><code>textNoSuggestions</code> 可以与text及它的其他选项结合, 以指示输入法不应显示任何基于字典的单词建议。</li>
<li><code>textPassword</code> 用于输入密码。</li>
<li><code>textPersonName</code> 用于输入人名。</li>
<li><code>textPhonetic</code> 用于输入拼音发音的文本, 如联系人条目中的拼音名称字段。</li>
<li><code>textPostalAddress</code> 用于输入邮寄地址。</li>
<li><code>textShortMessage</code> 用于输入短的消息内容。</li>
<li><code>textUri</code> 用于输入一个URI。</li>
<li><code>textVisiblePassword</code> 用于输入可见的密码。</li>
<li><code>textWebEditText</code> 用于输入在web表单中的文本。</li>
<li><code>textWebEmailAddress</code> 用于在web表单里输入一个电子邮件地址。</li>
<li><code>textWebPassword</code> 用于在web表单里输入一个密码。</li>
<li><code>time</code> 用于输入时间。</li>
</ul>
<p>例如,想指定一个输入框的输入类型为小数数字,为: <code><input inputType="number|numberDecimal"/></code></p>
<h2>password</h2>
<p>指定输入框输入框是否为密码输入框。默认为<code>false</code>。</p>
<p>例如:<code><input password="true"/></code></p>
<h2>numeric</h2>
<p>指定输入框输入框是否为数字输入框。默认为<code>false</code>。</p>
<p>例如:<code><input numeric="true"/></code></p>
<h2>phoneNumber</h2>
<p>指定输入框输入框是否为电话号码输入框。默认为<code>false</code>。</p>
<p>例如:<code><input phoneNumber="true"/></code></p>
<h2>digits</h2>
<p>指定输入框可以输入的字符。例如,要指定输入框只能输入"1234567890+-",为<code><input digits="1234567890+-"/></code>。</p>
<h2>singleLine</h2>
<p>指定输入框是否为单行输入框。默认为<code>false</code>。您也可以通过<code>lines="1"</code>来指定单行输入框。</p>
<p>例如:<code><input singleLine="true"/></code></p>
<h1>图片控件: img</h1>
<p>图片控件用于显示来自网络、本地或者内嵌数据的图片,并可以指定图片以圆角矩形、圆形等显示。但是不能用于显示gif动态图。</p>
<p>这里只介绍他的主要方法和属性,如果要查看他的所有方法和属性,阅读<a href="http://www.zhdoc.net/android/reference/android/widget/ImageView.html">ImageView</a>。</p>
<h2>src</h2>
<p>使用一个Uri指定图片的来源。可以是图片的地址(<a href="http://....),本地路径(file://....)或者base64数据("data:image/png;base64">http://....),本地路径(file://....)或者base64数据("data:image/png;base64</a>,...")。</p>
<p>如果使用图片地址或本地路径,Auto.js会自动使用适当的缓存来储存这些图片,减少下次加载的时间。</p>
<p>例如,显示百度的logo:</p>
<pre><code>"ui";
ui.layout(
<frame>
<img src="https://www.baidu.com/img/bd_logo1.png"/>
</frame>
);</code></pre>
<p>再例如,显示文件/sdcard/1.png的图片为 <code><img src="file:///sdcard/1.png"/></code>。
再例如,使base64显示一张钱包小图片为:</p>
<pre><code>"ui";
ui.layout(
<frame>
<img w="40" h="40" src="data:image/png;base64,..."/>
</frame>
);</code></pre>
<h2>tint</h2>
<p>图片着色,其值是一个颜色名称或RGB颜色值。使用该属性会将图片中的非透明区域都涂上同一颜色。可以用于改变图片的颜色。</p>
<p>例如,对于上面的base64的图片: <code><img w="40" h="40" tint="red" src="data:image/png;base64,..."/></code>,则钱包图标颜色会变成红色。</p>
<h2>scaleType</h2>
<p>控制图片根据图片控件的宽高放缩时的模式。可选的值为:</p>
<ul>
<li><code>center</code> 在控件中居中显示图像, 但不执行缩放。</li>
<li><code>centerCrop</code> 保持图像的长宽比缩放图片, 使图像的尺寸 (宽度和高度) 等于或大于控件的相应尺寸 (不包括内边距padding)并且使图像在控件中居中显示。</li>
<li><code>centerInside</code> 保持图像的长宽比缩放图片, 使图像的尺寸 (宽度和高度) 小于视图的相应尺寸 (不包括内边距padding)并且图像在控件中居中显示。</li>
<li><code>fitCenter</code> 保持图像的长宽比缩放图片, 使图片的宽<strong>或</strong>高和控件的宽高相同并使图片在控件中居中显示</li>
<li><code>fitEnd</code> 保持图像的长宽比缩放图片, 使图片的宽<strong>或</strong>高和控件的宽高相同并使图片在控件中靠右下角显示</li>
<li><code>fitStart</code> 保持图像的长宽比缩放图片, 使图片的宽<strong>或</strong>高和控件的宽高相同并使图片在控件靠左上角显示</li>
<li><code>fitXY</code> 使图片和宽高和控件的宽高完全匹配,但图片的长宽比可能不能保持一致</li>
<li><code>matrix</code> 绘制时使用图像矩阵进行缩放。需要在代码中使用<code>setImageMatrix(Matrix)</code>函数才能生效。</li>
</ul>
<p>默认的scaleType为<code>fitCenter</code>;除此之外最常用的是<code>fitXY</code>, 他能使图片放缩到控件一样的大小,但图片可能会变形。</p>
<h2>radius</h2>
<p>图片控件的半径。如果设置为控件宽高的一半并且控件的宽高相同则图片将剪切为圆形显示;否则图片为圆角矩形显示,半径即为四个圆角的半径,也可以通过<code>radiusTopLeft</code>, <code>radiusTopRight</code>, <code>radiusBottomLeft</code>, <code>radiusBottomRight</code>等属性分别设置四个圆角的半径。</p>
<p>例如,圆角矩形的Auto.js图标:<code><img w="100" h="100" radius="20" bg="white" src="http://www.autojs.org/assets/uploads/profile/3-profileavatar.png" /></code></p>
<p>有关该属性的单位,参见<a href="#ui_尺寸的单位_Dimension">尺寸的单位: Dimension</a>。</p>
<h2>radiusTopLeft</h2>
<p>图片控件的左上角圆角的半径。有关该属性的单位,参见<a href="#ui_尺寸的单位_Dimension">尺寸的单位: Dimension</a>。</p>
<h2>radiusTopRight</h2>
<p>图片控件的右上角圆角的半径。有关该属性的单位,参见<a href="#ui_尺寸的单位_Dimension">尺寸的单位: Dimension</a>。</p>
<h2>radiusBottomLeft</h2>
<p>图片控件的左下角圆角的半径。有关该属性的单位,参见<a href="#ui_尺寸的单位_Dimension">尺寸的单位: Dimension</a>。</p>
<h2>radiusBottomRight</h2>
<p>图片控件的右下角圆角的半径。有关该属性的单位,参见<a href="#ui_尺寸的单位_Dimension">尺寸的单位: Dimension</a>。</p>
<h2>borderWidth</h2>
<p>图片控件的边框宽度。用于在图片外面显示一个边框,边框会随着图片控件的外形(圆角等)改变而相应变化。
例如, 圆角矩形带灰色边框的Auto.js图标:<code><img w="100" h="100" radius="20" borderWidth="5" borderColor="gray" bg="white" src="http://www.autojs.org/assets/uploads/profile/3-profileavatar.png" /></code></p>
<h2>borderColor</h2>
<p>图片控件的边框颜色。</p>
<h2>circle</h2>
<p>指定该图片控件的图片是否剪切为圆形显示。如果为<code>true</code>,则图片控件会使其宽高保持一致(如果宽高不一致,则保持高度等于宽度)并使圆形的半径为宽度的一半。</p>
<p>例如,圆形的Auto.js图标:<code><img w="100" h="100" circle="true" bg="white" src="http://www.autojs.org/assets/uploads/profile/3-profileavatar.png" /></code></p>
<h1>垂直布局: vertical</h1>
<p>垂直布局是一种比较简单的布局,会把在它里面的控件按照垂直方向依次摆放,如下图所示:</p>
<p>垂直布局:</p>
<p>—————</p>
<p>| 控件1 |</p>
<p>| 控件2 |</p>
<p>| 控件3 |</p>
<p>| ............ |</p>
<p>——————</p>
<h2>layout_weight</h2>
<p>垂直布局中的控件可以通过<code>layout_weight</code>属性来控制控件高度占垂直布局高度的比例。如果为一个控件指定<code>layout_weight</code>, 则这个控件的高度=垂直布局剩余高度 * layout_weight / weightSum;如果不指定weightSum, 则weightSum为所有子控件的layout_weight之和。所谓"剩余高度",指的是垂直布局中减去没有指定layout_weight的控件的剩余高度。
例如:</p>
<pre><code>"ui";
ui.layout(
<vertical h="100dp">
<text layout_weight="1" text="控件1" bg="#ff0000"/>
<text layout_weight="1" text="控件2" bg="#00ff00"/>
<text layout_weight="1" text="控件3" bg="#0000ff"/>
</vertical>
);</code></pre>
<p>在这个布局中,三个控件的layout_weight都是1,也就是他们的高度都会占垂直布局高度的1/3,都是33.3dp.
再例如:</p>
<pre><code>"ui";
ui.layout(
<vertical h="100dp">
<text layout_weight="1" text="控件1" bg="#ff0000"/>
<text layout_weight="2" text="控件2" bg="#00ff00"/>
<text layout_weight="1" text="控件3" bg="#0000ff"/>
</vertical>
);</code></pre>
<p>在这个布局中,第一个控件高度为1/4, 第二个控件为2/4, 第三个控件为1/4.
再例如:</p>
<pre><code>"ui";
ui.layout(
<vertical h="100dp" weightSum="5">
<text layout_weight="1" text="控件1" bg="#ff0000"/>
<text layout_weight="2" text="控件2" bg="#00ff00"/>
<text layout_weight="1" text="控件3" bg="#0000ff"/>
</vertical>
);</code></pre>
<p>在这个布局中,因为指定了weightSum为5, 因此第一个控件高度为1/5, 第二个控件为2/5, 第三个控件为1/5.
再例如:</p>
<pre><code>"ui";
ui.layout(
<vertical h="100dp">
<text h="40dp" text="控件1" bg="#ff0000"/>
<text layout_weight="2" text="控件2" bg="#00ff00"/>
<text layout_weight="1" text="控件3" bg="#0000ff"/>
</vertical>
);</code></pre>
<p>在这个布局中,第一个控件并没有指定layout_weight, 而是指定高度为40dp, 因此不加入比例计算,此时布局剩余高度为60dp。第二个控件高度为剩余高度的2/3,也就是40dp,第三个控件高度为剩余高度的1/3,也就是20dp。</p>
<p>垂直布局的layout_weight属性还可以用于控制他的子控件高度占满剩余空间,例如:</p>
<pre><code>"ui";
ui.layout(
<vertical h="100dp">
<text h="40dp" text="控件1" bg="#ff0000"/>
<text h="40dp" text="控件2" bg="#00ff00"/>
<text layout_weight="1" text="控件3" bg="#0000ff"/>
</vertical>
);</code></pre>
<p>在这个布局中,第三个控件的高度会占满除去控件1和控件2的剩余空间。</p>
<h1>水平布局: horizontal</h1>
<p>水平布局是一种比较简单的布局,会把在它里面的控件按照水平方向依次摆放,如下图所示:
水平布局:
————————————————————————————</p>
<p>| 控件1 | 控件2 | 控件3 | ... |</p>
<p>————————————————————————————</p>
<h2>layout_weight</h2>
<p>水平布局中也可以使用layout_weight属性来控制子控件的<strong>宽度</strong>占父布局的比例。和垂直布局中类似,不再赘述。</p>
<h1>线性布局: linear</h1>
<p>实际上,垂直布局和水平布局都属于线性布局。线性布局有一个orientation的属性,用于指定布局的方向,可选的值为<code>vertical</code>和<code>horizontal</code>。</p>
<p>例如<code><linear orientation="vertical"></linear></code>相当于<code><vertical></vertical></code>。</p>
<p>线性布局的默认方向是横向的,因此,一个没有指定orientation属性的线性布局就是横向布局。</p>
<h1>帧布局: frame</h1>
<p>帧布局</p>
<h1>相对布局: relative</h1>
<h1>勾选框控件: checkbox</h1>
<h1>选择框控件: radio</h1>
<h1>选择框布局: radiogroup</h1>
<h1>开关控件: Switch</h1>
<p>开关控件用于表示一个选项是否被选中。</p>
<h2>checked</h2>
<p>表示开关是否被选中。可选的值为:</p>
<ul>
<li><code>true</code> 打开开关</li>
<li><code>false</code> 关闭开关</li>
</ul>
<h2>text</h2>
<p>对开关进行描述的文字。</p>
<h1>进度条控件: progressbar</h1>
<h1>拖动条控件: seekbar</h1>
<h1>下来菜单控件: spinner</h1>
<h1>时间选择控件: timepicker</h1>
<h1>日期选择控件: datepicker</h1>
<h1>浮动按钮控件: fab</h1>
<h1>标题栏控件: toolbar</h1>
<h1>卡片: card</h1>
<p>卡片控件是一个拥有圆角、阴影的控件。</p>
<h2>cardBackgroundColor</h2>
<p>卡片的背景颜色。</p>
<h2>cardCornerRadius</h2>
<p>卡片的圆角半径。</p>
<h2>cardElevation</h2>
<p>设置卡片在z轴上的高度,来控制阴影的大小。</p>
<h2>contentPadding</h2>
<p>设置卡片的内边距。该属性包括四个值:</p>
<ul>
<li><code>contentPaddingLeft</code> 左内边距</li>
<li><code>contentPaddingRight</code> 右内边距</li>
<li><code>contentPaddingTop</code> 上内边距</li>
<li><code>contentPaddingBottom</code> 下内边距</li>
</ul>
<h2>foreground</h2>
<p>使用<code>foreground="?selectableItemBackground"</code>属性可以为卡片添加点击效果。</p>
<h1>抽屉布局: drawer</h1>
<h1>列表: list</h1>
<h1>Tab: tab</h1>
<h1>ui</h1>
<h2>ui.layout(xml)</h2>
<ul>
<li><code>xml</code> {XML} | {string} 布局XML或者XML字符串</li>
</ul>
<p>将布局XML渲染为视图(View)对象, 并设置为当前视图。</p>
<h2>ui.layoutFile(xmlFile)</h2>
<ul>
<li><code>xml</code> {string} 布局XML文件的路径</li>
</ul>
<p>此函数和<code>ui.layout</code>相似,只不过允许传入一个xml文件路径来渲染布局。</p>
<h2>ui.inflate(xml[, parent = null, attachToParent = false])</h2>
<ul>
<li><code>xml</code> {string} | {XML} 布局XML或者XML字符串</li>
<li><code>parent</code> {View} 父视图</li>
<li><code>attachToParent</code> {boolean} 是否渲染的View加到父视图中,默认为false</li>
<li>返回 {View}</li>
</ul>
<p>将布局XML渲染为视图(View)对象。如果该View将作为某个View的子View,我们建议传入<code>parent</code>参数,这样在渲染时依赖于父视图的一些布局属性能够正确应用。</p>
<p>此函数用于动态创建、显示View。</p>
<pre><code class="language-javascript">"ui";
$ui.layout(
<linear id="container">
</linear>
);
// 动态创建3个文本控件,并加到container容器中
// 这里仅为实例,实际上并不推荐这种做法,如果要展示列表,
// 使用list组件;动态创建十几个、几十个View会让界面卡顿
for (let i = 0; i < 3; i++) {
let textView = $ui.inflate(
<text textColor="#000000" textSize="14sp"/>
, $ui.container);
textView.attr("text", "文本控件" + i);
$ui.container.addView(textView);
}</code></pre>
<h1>ui.registerWidget(name, widget)</h1>
<ul>
<li><code>name</code> {string} 组件名称</li>
<li><code>widget</code> {Function} 组件</li>
</ul>
<p>注册一个自定义组件。参考示例->界面控件->自定义控件。</p>
<h1>ui.isUiThread()</h1>
<ul>
<li>返回 {boolean}</li>
</ul>
<p>返回当前线程是否是UI线程。</p>
<pre><code class="language-javascript">"ui";
log($ui.isUiThread()); // => true
$threads.start(function () {
log($ui.isUiThread()); // => false
});
</code></pre>
<h2>ui.findView(id)</h2>
<ul>
<li><code>id</code> {string} View的ID</li>
<li>返回 {View}</li>
</ul>
<p>在当前视图中根据ID查找相应的视图对象并返回。如果当前未设置视图或找不到此ID的视图时返回<code>null</code>。</p>
<p>一般我们都是通过<code>ui.xxx</code>来获取id为xxx的控件,如果xxx是一个ui已经有的属性,就可以通过<code>$ui.findView()</code>来获取这个控件。</p>
<h2>ui.finish()</h2>
<p>结束当前活动并销毁界面。</p>
<h2>ui.setContentView(view)</h2>
<ul>
<li><code>view</code> {View} </li>
</ul>
<p>将视图对象设置为当前视图。</p>
<h2>ui.post(callback[, delay = 0])</h2>
<ul>
<li><code>callback</code> {Function} 回调函数</li>
<li><code>delay</code> {number} 延迟,单位毫秒</li>
</ul>
<p>将<code>callback</code>加到UI线程的消息循环中,并延迟delay毫秒后执行(不能准确保证一定在delay毫秒后执行)。</p>
<p>此函数可以用于UI线程中延时执行动作(sleep不能在UI线程中使用),也可以用于子线程中更新UI。</p>
<pre><code class="language-javascript">"ui";
ui.layout(
<frame>
<text id="result"/>
</frame>
);
ui.result.attr("text", "计算中");
// 在子线程中计算1+ ... + 10000000
threads.start({
let sum = 0;
for (let i = 0; i < 1000000; i++) {
sum += i;
}
// 由于不能在子线程操作UI,所以要抛到UI线程执行
ui.post(() => {
ui.result.attr("text", String(sum));
});
});</code></pre>
<h2>ui.run(callback)</h2>
<ul>
<li><code>callback</code> {Function} 回调函数</li>
<li>返回 callback的执行结果</li>
</ul>
<p>将<code>callback</code>在UI线程中执行。如果当前已经在UI线程中,则直接执行<code>callback</code>;否则将<code>callback</code>抛到UI线程中执行(加到UI线程的消息循环的末尾),<strong>并等待callback执行结束(阻塞当前线程)</strong>。</p>
<h2>ui.statusBarColor(color)</h2>
<ul>
<li>color {string} | {number} 颜色</li>
</ul>
<p>设置当前界面的状态栏颜色。</p>
<pre><code class="language-javascript">"ui";
ui.statusBarColor("#000000");</code></pre>
<h2>ui.useAndroidResources()</h2>
<p>启用使用Android的布局(layout)、绘图(drawable)、动画(anim)、样式(style)等资源的特性。启用该特性后,在project.json中进行以下配置,就可以像写Android原生一样写界面:</p>
<pre><code class="language-json">{
// ...
androidResources: {
"resDir": "res", // 资源文件夹
"manifest": "AndroidManifest.xml" // AndroidManifest文件路径
}
}</code></pre>
<p>res文件夹通常为以下结构:</p>
<pre><code>- res
- layout // 布局资源
- drawable // 图片、形状等资源
- menu // 菜单资源
- values // 样式、字符串等资源
// ...</code></pre>
<p>可参考示例->复杂界面->Android原生界面。</p>
<h1>尺寸的单位: Dimension</h1>
<h1>Drawables</h1>
<h1>颜色</h1>
<p><strong>(完善中...)</strong></p>