【Android实验】UI设计-Android计算器
实验目的
自主完成一个简单APP的设计工作,综合应用已经学到的Android UI设计技巧,重点注意合理使用布局
实验要求
- 完成一个计算器的设计,可以以手机自带的计算器为参考。设计过程中,注意考虑界面的美观性,不同机型的适应性,以及功能的完备性。
- 注意结合Activity的生命周期,考虑不同情况下计算器的界面状态。
- 如有余力,可以考虑实现一个高精度科学计算型的计算器。
实验过程
1. 界面设计
界面仿照自己手机中计算器界面进行了设计,采用的布局是线性布局,其中比较特殊的布局是最后两行的布局,由于“=”键占用两个位置,所以采用vertical和horizontal相互配合的方式进行。
界面的展示如下:
界面代码(activity_caculator.xml):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:background="@drawable/a5"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:orientation="vertical"
android:focusableInTouchMode="true">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Calculator"
android:textStyle="italic"
android:textAlignment="center"
android:textSize="20sp" />
<EditText
android:id="@+id/et_input"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="0"
android:enabled="true"
android:textAlignment="textEnd"
android:textSize="30sp"
android:background="@null"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal"
android:weightSum="4">
<Button style="?android:attr/buttonStyle"
android:id="@+id/btn_clear"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#FFE4C4"
android:text="C"
android:textAlignment="center"
android:textSize="20sp"/>
<Button style="?android:attr/buttonStyle"
android:id="@+id/btn_divide"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#FFE4C4"
android:text="/"
android:textAlignment="center"
android:textSize="20sp"/>
<Button style="?android:attr/buttonStyle"
android:id="@+id/btn_times"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#FFE4C4"
android:text="*"
android:textAlignment="center"
android:textSize="20sp"/>
<Button
android:id="@+id/btn_delete"
style="?android:attr/buttonStyle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#FFE4C4"
android:text="DEL"
android:textAlignment="center"
android:textSize="20sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="horizontal"
android:layout_weight="1"
android:weightSum="4">
<Button style="?android:attr/buttonStyle"
android:id="@+id/btn_7"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#FDF5E6"
android:text="7"
android:textAlignment="center"
android:textSize="20sp"/>
<Button
android:id="@+id/btn_8"
style="?android:attr/buttonStyle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#FDF5E6"
android:text="8"
android:textAlignment="center"
android:textSize="20sp" />
<Button style="?android:attr/buttonStyle"
android:id="@+id/btn_9"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#FDF5E6"
android:text="9"
android:textAlignment="center"
android:textSize="20sp"/>
<Button style="?android:attr/buttonStyle"
android:id="@+id/btn_sub"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="#FFC0CB"
android:layout_weight="1"
android:text="-"
android:textAlignment="center"
android:textSize="20sp"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="horizontal"
android:layout_weight="1"
android:weightSum="4">
<Button style="?android:attr/buttonStyle"
android:id="@+id/btn_4"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#FDF5E6"
android:text="4"
android:textAlignment="center"
android:textSize="20sp"/>
<Button
android:id="@+id/btn_5"
style="?android:attr/buttonStyle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#FDF5E6"
android:text="5"
android:textAlignment="center"
android:textSize="20sp" />
<Button
android:id="@+id/btn_6"
style="?android:attr/buttonStyle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#FDF5E6"
android:text="6"
android:textAlignment="center"
android:textSize="20sp" />
<Button
android:id="@+id/btn_add"
style="?android:attr/buttonStyle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#FFC0CB"
android:text="+"
android:textAlignment="center"
android:textSize="20sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="horizontal"
android:layout_weight="2"
android:weightSum="4">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_weight="1">
<Button style="?android:attr/buttonStyle"
android:id="@+id/btn_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="#FDF5E6"
android:text="1"
android:textAlignment="center"
android:textSize="20sp"/>
<Button style="?android:attr/buttonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="%"
android:textAlignment="center"
android:background="#FDF5E6"
android:layout_weight="1"
android:id="@+id/btn_remainder"
android:textSize="20sp"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_weight="1">
<Button style="?android:attr/buttonStyle"
android:id="@+id/btn_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="#FDF5E6"
android:text="2"
android:textAlignment="center"
android:textSize="20sp"/>
<Button style="?android:attr/buttonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="0"
android:textAlignment="center"
android:background="#FDF5E6"
android:layout_weight="1"
android:id="@+id/btn_0"
android:textSize="20sp"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_weight="1">
<Button style="?android:attr/buttonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="3"
android:textAlignment="center"
android:background="#FDF5E6"
android:layout_weight="1"
android:id="@+id/btn_3"
android:textSize="20sp"/>
<Button
android:id="@+id/btn_point"
style="?android:attr/buttonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="#FDF5E6"
android:text="."
android:textAlignment="center"
android:textSize="20sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_weight="1">
<Button style="?android:attr/buttonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="="
android:textAlignment="center"
android:background="#FFC0CB"
android:layout_weight="1"
android:id="@+id/btn_equal"
android:textSize="20sp"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
在界面设计的过程中,感觉android:layout_weight
是一个比较重要的属性,整个界面的按比例排布都需要这个属性来决定,如果用绝对位置会导致翻转以后,计算器按钮无法按比例进行填充。
另外界面的一个特点就是没有了ActionBar,这个通过设置Style.xml
中的parent
属性,从而可以改变。
Style.xml文件如下:
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
另外的app命令以及图标替换在AndroidManifest.xml文件中更改:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.administrator.calculator">
<application
android:allowBackup="true"
android:icon="@drawable/pjthis"
android:label="PjCalc"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<activity android:name=".Caculator">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
修改APP名称在android:label属性中修改,APP图标在android:icon中修改,其中android:theme改为NoActionBar可以将头部的标题去掉,增大空间。在LinearLayout中修改android:backgroud可以对背景进行修改,这里换成了一个自定义背景。
2. 功能设计
进行事件响应的主体为:Calculator.java
对界面事件的获取以及处理主要由该文件处理:
代码如下:
package com.example.administrator.calculator;
import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
public class Caculator extends AppCompatActivity implements View.OnClickListener {
Button bt_0, bt_1, bt_2, bt_3, bt_4, bt_5, bt_6, bt_7, bt_8, bt_9;
Button bt_clear, bt_divide, bt_times, bt_delete, bt_add, bt_sub, bt_equal, bt_remainder, bt_point;
private EditText et_input;
private StringBuilder fomula = new StringBuilder();
private void initP() {
bt_0 = (Button) findViewById(R.id.btn_0);
bt_1 = (Button) findViewById(R.id.btn_1);
bt_2 = (Button) findViewById(R.id.btn_2);
bt_3 = (Button) findViewById(R.id.btn_3);
bt_4 = (Button) findViewById(R.id.btn_4);
bt_5 = (Button) findViewById(R.id.btn_5);
bt_6 = (Button) findViewById(R.id.btn_6);
bt_7 = (Button) findViewById(R.id.btn_7);
bt_8 = (Button) findViewById(R.id.btn_8);
bt_9 = (Button) findViewById(R.id.btn_9);
bt_clear = (Button) findViewById(R.id.btn_clear);
bt_divide = (Button) findViewById(R.id.btn_divide);
bt_times = (Button) findViewById(R.id.btn_times);
bt_delete = (Button) findViewById(R.id.btn_delete);
bt_add = (Button) findViewById(R.id.btn_add);
bt_sub = (Button) findViewById(R.id.btn_sub);
bt_equal = (Button) findViewById(R.id.btn_equal);
bt_point = (Button) findViewById(R.id.btn_point);
bt_remainder = (Button) findViewById(R.id.btn_remainder);
et_input = (EditText) findViewById(R.id.et_input);
et_input.setKeyListener(null);
bt_0.setOnClickListener(this);
bt_1.setOnClickListener(this);
bt_2.setOnClickListener(this);
bt_3.setOnClickListener(this);
bt_4.setOnClickListener(this);
bt_5.setOnClickListener(this);
bt_6.setOnClickListener(this);
bt_7.setOnClickListener(this);
bt_8.setOnClickListener(this);
bt_9.setOnClickListener(this);
bt_add.setOnClickListener(this);
bt_clear.setOnClickListener(this);
bt_divide.setOnClickListener(this);
bt_times.setOnClickListener(this);
bt_delete.setOnClickListener(this);
bt_sub.setOnClickListener(this);
bt_remainder.setOnClickListener(this);
bt_point.setOnClickListener(this);
bt_equal.setOnClickListener(this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_caculator);
initP();
}
@Override
public void onClick(View v) {
int latest = 0;
if (fomula.length() != 0) {
latest = fomula.codePointAt(fomula.length() - 1);
}
else
latest = '.';
switch (v.getId()) {
case R.id.btn_0:
fomula = fomula.append("0");
et_input.setText(fomula);
break;
case R.id.btn_1:
fomula = fomula.append("1");
et_input.setText(fomula);
break;
case R.id.btn_2:
fomula = fomula.append("2");
et_input.setText(fomula);
break;
case R.id.btn_3:
fomula = fomula.append("3");
et_input.setText(fomula);
break;
case R.id.btn_4:
fomula = fomula.append("4");
et_input.setText(fomula);
break;
case R.id.btn_5:
fomula = fomula.append("5");
et_input.setText(fomula);
break;
case R.id.btn_6:
fomula = fomula.append("6");
et_input.setText(fomula);
break;
case R.id.btn_7:
fomula = fomula.append("7");
et_input.setText(fomula);
break;
case R.id.btn_8:
fomula = fomula.append("8");
et_input.setText(fomula);
break;
case R.id.btn_9:
fomula = fomula.append("9");
et_input.setText(fomula);
break;
case R.id.btn_sub:
if (latest >= '0' && latest <= '9')
fomula = fomula.append("-");
else {
if(latest != '.')
fomula.delete(fomula.length()-1, fomula.length());
fomula = fomula.append("-");
}
et_input.setText(fomula);
break;
case R.id.btn_add:
if (latest >= '0' && latest <= '9')
fomula = fomula.append("+");
else {
if(latest != '.')
fomula.delete(fomula.length()-1, fomula.length());
fomula = fomula.append("+");
}
et_input.setText(fomula);
break;
case R.id.btn_times:
if (latest >= '0' && latest <= '9')
fomula = fomula.append("*");
else {
if(latest != '.')
fomula = fomula.delete(fomula.length()-1,fomula.length());
fomula = fomula.append("*");
}
et_input.setText(fomula);
break;
case R.id.btn_divide:
if (latest >= '0' && latest <= '9')
fomula = fomula.append("/");
else {
if(latest != '.')
fomula.delete(fomula.length()-1, fomula.length());
fomula = fomula.append("/");
}
et_input.setText(fomula);
break;
case R.id.btn_delete:
if (fomula.length() > 0)
fomula = fomula.delete(fomula.length() - 1, fomula.length());
et_input.setText(fomula);
break;
case R.id.btn_clear:
fomula = fomula.delete(0, fomula.length());
et_input.setText(fomula);
break;
case R.id.btn_equal:
String ans="0";
if(fomula.length()>1){
InfixInToDuffix inf = new InfixInToDuffix();
try{
String a = inf.toSuffix(fomula);
System.out.println("out:");
System.out.println(a);
ans = inf.dealEquation(a);
fomula = fomula.delete(0,fomula.length());
fomula = fomula.append(ans);
}catch (Exception ex){
ans = "error";
fomula = fomula.delete(0,fomula.length());
}
}
et_input.setText(ans);
break;
case R.id.btn_point:
fomula = fomula.append(".");
et_input.setText(fomula);
break;
case R.id.btn_remainder:
if(latest >= '0' && latest <= '9'){
fomula.append("%");
}
else
{
if(latest != '.')
fomula.delete(fomula.length()-1,fomula.length());
fomula.append("%");
}
et_input.setText(fomula);
break;
}
}
}
声明各个按钮及部件,然后通过findViewById得到对应的对象,然后进行处理相应的处理。
其中有几个细节需要处理,否则会导致程序崩溃:
- 符号处理。
- 符号前边不能有符号。
- 小数点处理。
- 如果结果是整数,不要加小数点。
- 小数点的连续使用,如
1.2.3.5.1。
- 运算符号如果出现在数字之前,需要特殊判断。
- 多个符号连续出现问题。
- 处理方式为将上一个符号顶替下来,换成最新的运算符。
- 减号如果作为-负号的情况出现。
3. 运算处理
主要是通过两个栈,将中缀转化为后缀,然后进行求解。其中“*/”
运算符的优先级应该与“%”
优先级一致,但是这里让“%”
优先级低于"*/"
,然后进行的处理。
package com.example.administrator.calculator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.lang.*;
import java.util.ArrayList;
import java.util.*;
/**
* Created by pprp on 2018/9/22.
*/
class InfixInToDuffix {
//使用集合定义好符号的运算优先级别
private static final Map<Character,Integer>basic =new HashMap<Character, Integer>();
static {
basic.put('-',1);
basic.put('+', 1);
basic.put('*', 3);
basic.put('/', 3);
basic.put('(', 0);
basic.put('%',2);
}
//将中缀表达式转换为后缀表达式
public String toSuffix(StringBuilder infix){
List<String> queue = new ArrayList<String>();
List<Character> stack = new ArrayList<Character>();
char[] charArr = infix.substring(0,infix.length()).trim().toCharArray();
String standard = "*/+-()%";
char ch = '&';
int len = 0;
for (int i = 0; i < charArr.length; i++) {
ch = charArr[i];
if(Character.isDigit(ch)) {
len++;
}else if(ch == '.'){
len++;
}else if(standard.indexOf(ch) != -1) {
if(len > 0) {
queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len, i)));
len = 0;
}
if(ch == '(') {
stack.add(ch);
continue;
}
if (!stack.isEmpty()) {
int size = stack.size() - 1;
boolean flag = false;
while (size >= 0 && ch == ')' && stack.get(size) != '(') {
queue.add(String.valueOf(stack.remove(size)));
size--;
flag = true;
}
if(ch==')'&&stack.get(size) == '('){
flag = true;
}
while (size >= 0 && !flag && basic.get(stack.get(size)) >= basic.get(ch)) {
queue.add(String.valueOf(stack.remove(size)));
size--;
}
}
if(ch != ')') {
stack.add(ch);
} else {
stack.remove(stack.size() - 1);
}
}
if(i == charArr.length - 1) {
if(len > 0) {
queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len+1, i+1)));
}
int size = stack.size() - 1;
while (size >= 0) {
queue.add(String.valueOf(stack.remove(size)));
size--;
}
}
}
String a = queue.toString();
return a.substring(1,a.length()-1);
}
public String dealEquation(String equation){
String [] arr = equation.split(", ");
List<String> list = new ArrayList<String>();
for (int i = 0; i < arr.length; i++) {
int size = list.size();
switch (arr[i]) {
case "+": double a = Double.parseDouble(list.remove(size-2))+ Double.parseDouble(list.remove(size-2)); list.add(String.valueOf(a)); break;
case "-": double b = Double.parseDouble(list.remove(size-2))- Double.parseDouble(list.remove(size-2)); list.add(String.valueOf(b)); break;
case "*": double c = Double.parseDouble(list.remove(size-2))* Double.parseDouble(list.remove(size-2)); list.add(String.valueOf(c)); break;
case "/": double d = Double.parseDouble(list.remove(size-2))/ Double.parseDouble(list.remove(size-2)); list.add(String.valueOf(d)); break;
case "%": double e = Double.parseDouble(list.remove(size-2)) % Double.parseDouble(list.remove(size-2)); list.add(String.valueOf(e)); break;
default: list.add(arr[i]); break; //如果是数字 直接放进list中
}
}
return list.size() == 1 ? list.get(0) : "Fail" ;
}
}
【Android实验】UI设计-Android计算器的更多相关文章
- Android 高级UI设计笔记07:RecyclerView 的详解
1. 使用RecyclerView 在 Android 应用程序中列表是一个非常重要的控件,适用场合非常多,如新闻列表.应用列表.消息列表等等,但是从Android 一出生到现在并没有非常 ...
- Android应用UI设计流程
Android应用UI设计流程 设计原理 1.在移动设计中,使用环境是最关键的因素.原型设计方法必须考虑尺寸因素 2.用户测试必须涵盖运动.声音和多点触控等方面: 进行移动设计和测试时,请将你知道的有 ...
- Android中UI设计的一些技巧!!!
出处:http://blog.csdn.net/android_tutor/article/details/5995759 大家好,今天给大家分享的是Android中UI设计的一些技巧,本节内容主要有 ...
- Android 高级UI设计笔记06:仿微信图片选择器(转载)
仿微信图片选择器: 一.项目整体分析: 1. Android加载图片的3个目标: (1)尽可能的去避免内存溢出. a. 根据图片的显示大小去压缩图片 b. 使用缓存对我们图片进行管理(LruCache ...
- 【Android开发经验】Android举UI设计经验
转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 1.Android眼下的主流设备分辨率为480×800.720×1280.1080×1920,单位是像素.在 ...
- Android 高级UI设计笔记21:Android SegmentView(分段选择控件)
1. 分段控制(SegmentView) 首先我们先看看什么是SegmentView的效果,如下: 分段控制这个View控件是ios7的分段控制,和QQ消息页面顶部的效果一样,android没有这个控 ...
- Android 高级UI设计笔记19:PopupWindow使用详解
1. PopupWindow使用 PopupWindow这个类用来实现一个弹出框,可以使用任意布局的View作为其内容,这个弹出框是悬浮在当前activity之上的. 2. PopupWindow使用 ...
- Android 高级UI设计笔记22:Android 指示引导页(带圆点)
1. 引导页: 我们在安装某个软件首次运行时,大部分都会有一个引导页的提示,介绍软件新功能的加入或者使用说明等,支持滑动且下面会有几个圆点,显示共有多少页和当前图片的位置,类似如下效果: 2. 引导页 ...
- Android 高级UI设计笔记20:RecyclerView 的详解之RecyclerView添加Item点击事件
1. 引言: RecyclerView侧重的是布局的灵活性,虽说可以替代ListView但是连基本的点击事件都没有,这篇文章就来详细讲解如何为RecyclerView的item添加点击事件,顺便复习一 ...
随机推荐
- [vue]vue v-on事件绑定(原生修饰符+vue自带事件修饰符)
preventDefault阻止默认行为和stopPropagation终止传递 event.preventDefault() 链接本来点了可以跳转, 如果注册preventDefault事件,则点了 ...
- logstash的各个场景应用(配置文件均已实践过)
场景: 1) datasource->logstash->elasticsearch->kibana 2) datasource->filebeat->logstash- ...
- tf.nn.embedding_lookup函数的用法
关于np.random.RandomState.np.random.rand.np.random.random.np.random_sample参考https://blog.csdn.net/lanc ...
- FireFox Plugin编程
9 jiaofeng601, +479 9人支持,来自 Meteor.猪爪.hanyuxinting更多 本文通过多图组合,详细引导初学者开发NPAPI的浏览器插件. 如需测试开发完成的插件请参考 ...
- 函数及while实例
输入1,输出:if 输入2,输出:elif 输入其他数值,输出:else 输入非数字,输出:except def greeting3(name3, lang3=1): if lang3 == 1: r ...
- 用Anaconda安装TensorFlow+keras
检测目前安装了哪些环境变量:conda info --envs 查看当前有哪些可以使用的tensorflow版本:conda search --full -name tensorflow 查看ten ...
- 7.11 Models -- Customizing Adapters
一.概述 1. 在Ember Data中,和后台数据存储通信的逻辑存在于Adapter中.Ember Data的有一些内置的假设,一个 REST API 应该怎么看.如果你的后台约定和这些假设不同,E ...
- Jason使用
Jason是一种数据传输时候的一种格式,类似XML. package liferay; import java.beans.IntrospectionException; import java.be ...
- Bootstrap学习笔记-响应式布局原理
响应式布局的原理就是利用css3中@media媒体来实现的 <html> <head> <meta charset="utf-8"> <t ...
- liferay中如何获取实例的id和portletId
在Portlet中request分为两种renderRequet和actionRequest而portlet需要取得实例Id的时候都在renderRequest的时候才可以取到,如下例子 Portle ...