在需求,设计稿和接口都已准备好的情况下你如何复现设计,对上接口。怎样去实现这个页面?
假设这个页面是一个基础页面(没有很复杂的功能或者特别酷炫的效果),那么它可能是这样的一个流程
第5个步骤根据状态不同可能有多种不同选项,我们暂且不表。先继续看下去
假设设计稿是这样的(有点挫,大家将就一下)
假设接口返回的数据是这样的
{
"data": {
"id": 1,
"age": 20,
"avatar": "http://img0.imgtn.bdimg.com/it/u=1593523098,2479335990&fm=23&gp=0.jpg",
"name": "sgfb",
"signature": "这个人很懒,没有留下任何签名"
},
"status": {
"message": "获取个人信息成功",
"code": "001",
"success": true
}
}
我们根据上面讲的流程走一遍
1.写出实体类
public class Status{ public boolean success; public String code; public String message; }
public class DataWithStatus<T>{ public T data; public Status status; }
public class Person{ public int id; public int age; public String name; public String avatar; public String signature; }2.画出布局
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:gravity="center_horizontal" android:layout_marginTop="50dp"> <ImageView android:id="@+id/avatar" android:layout_width="80dp" android:layout_height="80dp" android:src="@mipmap/ic_launcher"/> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:textSize="16sp" android:text="sgfb"/> <TextView android:id="@+id/age" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:text="年龄:22"/> <TextView android:id="@+id/signature" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:text="我的签名"/> </LinearLayout> </FrameLayout>4.在使用的界面上声明并绑定上事件.一般这个步骤我们会使用一些例如butterknife之类的第三方。但是这里我们暂不使用
ImageView mAvatar; TextView mName; TextView mSignature; TextView mAge; private void initView(){ mAvatar= (ImageView) findViewById(R.id.avatar); mName=(TextView)findViewById(R.id.name); mSignature=(TextView)findViewById(R.id.signature); mAge=(TextView)findViewById(R.id.age); mAvatar.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { showAvatar(); } }); }5.请求接口数据,数据返回后绑定到视图上。在这里我使用了fastlib库的网络功能,因为这篇博客不是重点讲网络功能的所以有兴趣的可以自行到这个链接中了解 fastLib网络功能使用
Request request=new Request("http://192.168.8.3:8084/FastProject/Test"); request.setListener(new Listener<DataWithStatus<Person>>(){ @Override public void onResponseListener(Request r, DataWithStatus<Person> result) { if(result.status.success){ Person p=result.data; mName.setText(p.name); mAge.setText("年龄:"+Integer.toString(p.age)); mSignature.setText(p.signature); Glide.with(MainActivity.this).load(p.avatar).into(mAvatar); //使用Glide加载服务器中的图像 } else N.showShort(MainActivity.this,result.status.message); } @Override public void onErrorListener(Request r, String error) { Log.d("MainActivity","网络异常:"+error); } }); request.start(true,this);上面的例子可以说是比较正常向的流程。但是仅仅满足于“正常“就可以了吗?如果页面非常的多,或者页面内的组件非常的多而复杂的话我们可能会耗在一些基础(我用基础而不是用冗余这个词是因为我还并不是很确定这些代码是否是冗余的)的地方比较多的时间。比如一个有20个视图的页面,假如没有使用butterknife,你可能会看到
View view1; View view2; View view3; View view4; View view5; View view6; View view7; View view8; View view9; View view10; View view11; View view12; View view13; View view14; View view15; View view16; View view17; View view18; View view19; View view20; private void initViews(){ view1=findViewById(R.id.view1); view2=findViewById(R.id.view2); view3=findViewById(R.id.view3); view4=findViewById(R.id.view4); view5=findViewById(R.id.view5); view6=findViewById(R.id.view6); view7=findViewById(R.id.view7); view8=findViewById(R.id.view8); view9=findViewById(R.id.view9); view10=findViewById(R.id.view10); view11=findViewById(R.id.view11); view12=findViewById(R.id.view12); view13=findViewById(R.id.view13); view14=findViewById(R.id.view14); view15=findViewById(R.id.view15); view16=findViewById(R.id.view16); view17=findViewById(R.id.view17); view18=findViewById(R.id.view18); view19=findViewById(R.id.view19); view20=findViewById(R.id.view20); view1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //do something } }); view2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //do something } }); view3.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //do something } }); view4.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //do something } }); view5.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //do something } }); }这其中还是中还只是假定只有5个视图有事件且事件具体代码还没加入。
也许,我们需要一些“不正常”的方案来尝试写出这些页面
json数据填充到视图中一些共同点的启发
在重复的写了一些相似的代码后我突然认识到,json数据填充的位置
大部分是相同的,请看下面的图示
可以看出来,除了avatar是通过第三方加载到src之外,其它显示数据都是加载到TextView的text中。同理可得如果视图组件是CheckBox那么json给予的数据可能就是checked的标志。既然如此我们可以想象一下,如果有预先写好的填充方式(比如TextView组件就填充数据text)而且有某种办法确定填充组件的相对应数据。那么我们是不是可以不用在写重复代码了呢。
一个简单的解决方案。以id为确定填充组件标识,写好一部分的桥连接代码。当接口返回数据后自动填充。我已根据此想法写了一套封装,使用这一套封装来写同样的页面,流程应该是
对比两个流程,后一方的是明显会省略了一些代码
根据这个流程我们走一遍试试
1.画出布局与上一个流程的布局是一摸一样的,所以参照上一个流程布局即可
2.准备桥接类。因为TextView和CheckBox是明显指定text和checked属性的,所以封装内部已经写好了这两个的桥接。但是还没有ImageView的,所以写一个ImageView的桥接,并且在以后也可以使用
public class ViewResolveFactory{ /** * 添加ImageView桥接 * @param binder * @param context */ public static void putImageViewResulve(JsonViewBinder binder,final Context context){ binder.putResolve(new JsonViewBinder.ViewResolve() { @Override public void resolve(View view,Object reader) { Glide.with(context).load(reader.toString()).into((ImageView)view); } },ImageView.class, AppCompatImageView.class); } }
3.请求接口并在返回后调用自动绑定
private void requestInterface(){ Request request=new Request("http://192.168.8.3:8084/FastProject/Test"); request.setListener(new Listener<String>(){ @Override public void onResponseListener(Request r, String result) { try { JsonObject jo= FastJson.fromJson(result); mJsonViewBinder.bindDataToView(jo); } catch (IOException e) { e.printStackTrace(); } } @Override public void onErrorListener(Request r, String error) { Log.d("MainActivity","网络异常:"+error); } }); request.start(true,this); }
4.对特殊视图进行处理
/** * json数据填充后调用 */ private void jsonInflaterAfter(){ TextView age= (TextView) findViewById(R.id.age); String ageStr=age.getText().toString(); age.setText("年龄:"+(TextUtils.isEmpty(ageStr)?"":ageStr)); }最终效果图
这还只是一个雏形的想法,如果有什么不对或者可以加强的地方,恳请指教