Android 的数据绑定
BarneyMarcu
8年前
<h2>效果图</h2> <h2><img src="https://simg.open-open.com/show/895695bb2dd048f8a9bcf0be7419f1c3.gif"></h2> <p>完成这么多的UI操作,其实指需要很少的代码,现在附上全部关键代码。</p> <p>首先是布局文件:activity_main.xml</p> <pre> <code class="language-xml"><?xml version="1.0" encoding="utf-8"?> xmlns:ng="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:id="@+id/ll_container" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="10dp" android:tag="ng:user:name" android:text="Hello World!" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="userName" android:padding="10dp" android:tag="ng:user:name" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="10dp" android:tag="ng:user:age" /> <ProgressBar android:layout_width="match_parent" android:layout_height="wrap_content" style="@style/Base.Widget.AppCompat.ProgressBar.Horizontal" android:progress="10" android:tag="ng:user:age"/> <SeekBar android:layout_width="match_parent" android:layout_height="wrap_content" android:progress="0" android:tag="ng:user:age"/> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal"> <Switch android:layout_width="wrap_content" android:layout_height="match_parent" android:text="男" android:tag="ng:user:isMale" android:layout_margin="10dp"/> <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content" android:tag="ng:user:isMale" android:text="男" android:layout_margin="10dp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="10dp" android:tag="ng:user:isMale" android:text="Hello World!" /> </LinearLayout> <LinearLayout android:id="@+id/rv_list" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:tag="nglist:user:list"> <com.autonavi.jacklee.ngandroid.angular.view.NgItemView android:layout_width="match_parent" android:layout_height="wrap_content" android:tag="ng:student" ng:ngRecyclerViewItemList="@layout/item_student" /> <com.autonavi.jacklee.ngandroid.angular.view.NgItemView android:layout_width="match_parent" android:layout_height="wrap_content" android:tag="ng:title" ng:ngRecyclerViewItemList="@layout/item_tag" /> <com.autonavi.jacklee.ngandroid.angular.view.NgItemView android:layout_width="match_parent" android:layout_height="wrap_content" android:tag="ng:content" ng:ngRecyclerViewItemList="@layout/item_content" /> </LinearLayout> </LinearLayout></code></pre> <p>其中java代码部分如下:</p> <pre> <code class="language-java">public class MainActivity extends AppCompatActivity implements CommonAdapter.CommonAdapterInterface{ private NgGo ngGo; private NgModel ngUser; private List list; private LinearLayout ll_container; private Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); if((int)ngUser.getValue("age") >= 100){ ngUser.addParams("age", 0 ); }else{ ngUser.addParams("age", ((int)ngUser.getValue("age")) + 2 ); } NgModel user = ((List<NgModel>)ngUser.getValue("list")).get(0); user.addParams("name", "Jack" + ((int)ngUser.getValue("age"))); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ll_container = (LinearLayout) findViewById(R.id.ll_container); ngGo = new NgGo(ll_container); ngUser = new NgModel("user"); ngGo.addNgModel(ngUser); ngGo.start(); } @Override protected void onResume() { super.onResume(); initNgGo(); } private void initNgGo(){ ngUser.addParams("name", "Jhon"); ngUser.addParams("sex", "nan"); ngUser.addParams("age", 14); ngUser.addParams("isMale", false); list = new ArrayList<>(); for(int i = 0; i<10; i++){ if(i%3 == 0){ NgModel ngUser = new NgModel("student"); ngUser.addParams("name", "Jack" + i); list.add(ngUser); }else if(i%3 == 1){ NgModel ngUser = new NgModel("title"); ngUser.addParams("name", "title" + i); list.add(ngUser); }else{ NgModel ngUser = new NgModel("content"); ngUser.addParams("name", "Content" + i); list.add(ngUser); } } ngUser.addParams("list", list); Message msg = Message.obtain(); handler.sendMessageDelayed(msg, 1000); CommonAdapter adapter = ngGo.getRecyclerAdapter(R.id.rv_list); adapter.setCommonAdapterInterface(this); } @Override public void handleItem(int id, CommonAdapter.CommonHolder holder, final int position) { switch (id){ case R.id.rv_list: if(list.get(position).getTag().equals("student")){ holder.getView(R.id.iv_head).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { } }); } holder.getItemView().setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(getApplicationContext(), position + "_item", Toast.LENGTH_SHORT).show(); } }); break; } }</code></pre> <p>}</p> <p>以上就是所有代码,是不是感觉代码很少?哈哈哈</p> <p>现在开始介绍AngularAndroid</p> <h2>一 需要记住的几个对象</h2> <ol> <li>NgGo:这个是AngularAndroid渲染的具体执行者</li> <li>NgModel:这个是数据绑定中的绑定对象,只要它的属性值产生了变化,那么只要绑定在它身上的View就会做出相应的改变</li> <li>CommonAdapter:这个是RecyclerView的通用适配器</li> <li>NgItemView:这个是RecyclerView的Item,NgGo在监测到LinearLayout的tag中以nglist开头,会自动将LinearLayout转为RecyclerView,LinearLayout有多少个NgItemView,RecyclerView就有多少种item类型。</li> </ol> <h2>二 使用步骤</h2> <p>1.初始化NgGo对象 NgGo ngg = new NgGo(View parent);</p> <p>parent这个view对象,类似与angularjs中的控制域,可能一个页面中有不同的逻辑部分,这个时候,需要多个逻辑对象,这样的话,每个逻辑操作对象都对应一个控制域。一般这样的情况比较少。</p> <p>2.初始化NgModel对象 NgModel user = new NgModel("user");</p> <p>其中“user”这个参数,对应xml中"ng:user:name"的user,也就是NgModel需要指定对象名字。</p> <p>3.将NgModel添加到NgGo中,交给NgGo去控制 ngg.addNgModel(user);</p> <p>4.NgGo开始渲染 ngg.start();</p> <p>至此,数据绑定完成,现在尝试改变user的属性值:user.addParams("name", "Jhon");</p> <p>然后运行程序,是不是发现只要xml中tag为"ng:user:name"的view都显示"Jhon"?</p> <p>因为是双向绑定,所以,当view的文本发生改变时,对应的NgModel的相应属性也会发生变化。倘若Editext和TextView的tag都设置为"ng:user:name"时,会发现,TextView的值是跟着EditText的值动态改变的。</p> <p>有人会问这有什么用?现在举例一个最简单的场景:</p> <p>现在要做一个登录页面:</p> <p>原始做法:</p> <p>1.实例化帐号和密码两个EditText</p> <p>3.点击登录时,判断EditText的输入值是否符合规定。</p> <p>现在的做法:</p> <p>1.点击登录时,判断user对象的帐号(account)和密码(password)是否符合规定</p> <p>有木有发现,全程不用关注View对象,只需要关注具体的逻辑对象User,思维不用来回切</p>