Android实战:手把手实现“捧腹网”APP(三)-----UI实现,逻辑实现
APP頁面實現
根據原型圖,我們可以看出,UI分為兩部分,底部Tab導航+上方列表顯示。 所以此處,我們通過 FragmentTabHost+Fragment,來實現底部的導航頁面,通過RecyclerView來實現列表頁面。?
因為篇幅原因,關于FragmentTabHost和RecyclerView的使用,不多做介紹,可以建議參考:?FragmentTabHost使用方法及RecycleView_PullToRefresh_LoadMore兩篇文章,其中后者關于Recyclerview的項目是我之前封裝的一個支持下拉刷新,加載更多,添加Header和Footer等功能的RecyclerView,便于使用。
此處,再多說一點,因為是我們做自己來實現該ui,沒美工給我設計圖,切圖標, 所以我們需要自己去找圖標,此處推薦Iconfont-阿里巴巴矢量圖標庫, 在這里,我們可以找到很多的圖標,選擇適用的幾個即可。
篇幅原因,具體的頁面布局、實現代碼,我這里就不多貼,有興趣的,可以直接看源碼,此處,只貼出列表list_item的頁面布局代碼。?
從原型圖中,我們可以看出,列表的顯示分為純文顯示和圖片顯示,所以我們的item布局,應該要兼容這兩種顯示方式。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
效果圖:?
我們只需要在實現的邏輯上,控制文字、圖片的顯隱就好了。
APP邏輯功能實現
1.數據獲取,實現列表適配器
在第一章捧腹網網頁分析、數據獲取中,我已經講過了如何去解析網頁中的數據為我們所用,拿到數據后,我們需要用這些數據填充RecyclerView,此處,使用的是我已經封裝好的RecyclerView,支持翻頁加載數據。
import android.support.v4.app.Fragment; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.util.DisplayMetrics; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView;import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.lnyp.joke.R; import com.lnyp.joke.pengfu.JokeBean; import com.lnyp.joke.widget.CircleImageView; import com.lnyp.joke.widget.ShowMaxImageView;import java.util.List;import butterknife.BindView; import butterknife.ButterKnife;/***笑話列表*/ public class JokeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {private LayoutInflater mInflater;private Fragment mContext;private List<JokeBean> mDatas;private View.OnClickListener onItemClick;private int screenWidth;public JokeListAdapter(Fragment context, List<JokeBean> datas, View.OnClickListener onItemClick) {this.mContext = context;this.mDatas = datas;this.onItemClick = onItemClick;mInflater = LayoutInflater.from(context.getActivity());DisplayMetrics metric = new DisplayMetrics();context.getActivity().getWindowManager().getDefaultDisplay().getMetrics(metric);screenWidth = metric.widthPixels;}@Overridepublic RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {View view = mInflater.inflate(R.layout.list_item_joke, parent, false);return new ViewHolder(view);}@Overridepublic void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {ViewHolder viewHolder = (ViewHolder) holder;JokeBean jokeBean = mDatas.get(position);if (jokeBean != null) {Glide.with(mContext).load(jokeBean.getUserAvatar()).asBitmap().centerCrop().into(viewHolder.imgUser);viewHolder.textUserName.setText(jokeBean.getUserName());viewHolder.textLastTime.setText(jokeBean.getLastTime());viewHolder.textTitle.setText(jokeBean.getTitle());JokeBean.DataBean dataBean = jokeBean.getDataBean();if (dataBean != null) {if (TextUtils.isEmpty(dataBean.getContent())) {viewHolder.textContent.setVisibility(View.GONE);viewHolder.imgJoke.setVisibility(View.VISIBLE);viewHolder.textTitle.setVisibility(View.VISIBLE);// System.out.println(dataBean.getShowImg() + " " + dataBean.getGifsrcImg());double width = Double.parseDouble(dataBean.getWidth());double height = Double.parseDouble(dataBean.getHeight());ViewGroup.LayoutParams lp = viewHolder.imgJoke.getLayoutParams();lp.width = (int) (screenWidth * 0.8);lp.height = (int) (screenWidth * 0.8 * height / width);viewHolder.imgJoke.setLayoutParams(lp);String url = dataBean.getShowImg();String gifUrl = dataBean.getGifsrcImg();System.out.println("url : " + url + " gifUrl : " + gifUrl);if (TextUtils.isEmpty(gifUrl)) {Glide.with(mContext).load(url).asBitmap().diskCacheStrategy(DiskCacheStrategy.SOURCE).into(viewHolder.imgJoke);} else {Glide.with(mContext).load(gifUrl).asGif().diskCacheStrategy(DiskCacheStrategy.SOURCE).into(viewHolder.imgJoke);}} else {viewHolder.textContent.setVisibility(View.VISIBLE);viewHolder.imgJoke.setVisibility(View.GONE);viewHolder.textTitle.setVisibility(View.GONE);viewHolder.textContent.setText(dataBean.getContent());}}List<String> tags = jokeBean.getTags();if (tags != null) {int size = tags.size();if (size == 0) {updateTags(viewHolder, View.GONE, View.GONE, View.GONE, View.GONE);} else if (size == 1) {viewHolder.textTag1.setText(tags.get(0));updateTags(viewHolder, View.VISIBLE, View.GONE, View.GONE, View.GONE);} else if (size == 2) {viewHolder.textTag1.setText(tags.get(0));viewHolder.textTag2.setText(tags.get(1));updateTags(viewHolder, View.VISIBLE, View.VISIBLE, View.GONE, View.GONE);} else if (size == 3) {viewHolder.textTag1.setText(tags.get(0));viewHolder.textTag2.setText(tags.get(1));viewHolder.textTag3.setText(tags.get(2));updateTags(viewHolder, View.VISIBLE, View.VISIBLE, View.VISIBLE, View.GONE);} else {viewHolder.textTag1.setText(tags.get(0));viewHolder.textTag2.setText(tags.get(1));viewHolder.textTag3.setText(tags.get(2));viewHolder.textTag4.setText(tags.get(3));updateTags(viewHolder, View.VISIBLE, View.VISIBLE, View.VISIBLE, View.VISIBLE);}viewHolder.layoutTags.setVisibility(View.VISIBLE);} else {updateTags(viewHolder, View.GONE, View.GONE, View.GONE, View.GONE);viewHolder.layoutTags.setVisibility(View.GONE);}viewHolder.imgJoke.setTag(R.string.app_name, position);viewHolder.imgJoke.setOnClickListener(onItemClick);}}private void updateTags(ViewHolder viewHolder, int v1, int v2, int v3, int v4) {viewHolder.textTag1.setVisibility(v1);viewHolder.textTag2.setVisibility(v2);viewHolder.textTag3.setVisibility(v3);viewHolder.textTag4.setVisibility(v4);}@Overridepublic int getItemCount() {return mDatas != null ? mDatas.size() : 0;}class ViewHolder extends RecyclerView.ViewHolder {@BindView(R.id.imgJoke)public ShowMaxImageView imgJoke;@BindView(R.id.textContent)public TextView textContent;@BindView(R.id.layoutTags)public LinearLayout layoutTags;@BindView(R.id.textTitle)public TextView textTitle;@BindView(R.id.textTag1)public TextView textTag1;@BindView(R.id.textTag2)public TextView textTag2;@BindView(R.id.textTag3)public TextView textTag3;@BindView(R.id.textTag4)public TextView textTag4;@BindView(R.id.imgUser)public CircleImageView imgUser;@BindView(R.id.textUserName)public TextView textUserName;@BindView(R.id.textLastTime)public TextView textLastTime;public ViewHolder(View itemView) {super(itemView);ButterKnife.bind(this, itemView);}} }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
對于RecyclerView的適配器RecyclerView.Adapter的使用方式,相信玩過它的人都很熟悉,里面的方法不多介紹,主要講下圖片處理這塊的實現:
String url = dataBean.getShowImg();String gifUrl = dataBean.getGifsrcImg();System.out.println("url : " + url + " gifUrl : " + gifUrl);if (TextUtils.isEmpty(gifUrl)) {Glide.with(mContext).load(url).asBitmap().diskCacheStrategy(DiskCacheStrategy.SOURCE).into(viewHolder.imgJoke);} else {Glide.with(mContext).load(gifUrl).asGif().diskCacheStrategy(DiskCacheStrategy.SOURCE).into(viewHolder.imgJoke);}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
app中要展示的圖片,分為靜態圖片和動態圖片,glide可以很好的處理gif動態圖的加載,但是,如果像下面這樣直接使用glide加載動態圖,效率可是比較慢的。
Glide.with(mContext).load(gifUrl)into(viewHolder.imgJoke);- 1
所以,在加載gif動態圖的時候,我們通常使用下面這樣的緩存策略
Glide.with(mContext).load(gifUrl).asGif().diskCacheStrategy(DiskCacheStrategy.SOURCE).into(viewHolder.imgJoke);- 1
除了圖片加載,還有一點需要講解下,就是下面這段代碼:
double width = Double.parseDouble(dataBean.getWidth());double height = Double.parseDouble(dataBean.getHeight());ViewGroup.LayoutParams lp = viewHolder.imgJoke.getLayoutParams();lp.width = (int) (screenWidth * 0.8);lp.height = (int) (screenWidth * 0.8 * height / width);viewHolder.imgJoke.setLayoutParams(lp);- 1
- 2
- 3
- 4
- 5
- 6
這段代碼的意思是,在加載圖片之前,先設置了ImageView的寬高。這樣做的目的,是為了在圖片加載顯示之前就固定ImageView的大小,避免了列表因為圖片高度不一致而出現“晃動”。
好,到這里,我們基本完成了列表顯示功能了,接下來,在Fragment中實現功能邏輯。
2.實現列表邏輯功能
package com.lnyp.joke.fragment;import android.graphics.Color; import android.os.Bundle; import android.os.Handler; import android.support.v4.app.Fragment; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup;import com.baoyz.widget.PullRefreshLayout; import com.lnyp.flexibledivider.HorizontalDividerItemDecoration; import com.lnyp.joke.R; import com.lnyp.joke.adapter.JokeListAdapter; import com.lnyp.joke.http.HttpUtils; import com.lnyp.joke.pengfu.JokeApi; import com.lnyp.joke.pengfu.JokeBean; import com.lnyp.joke.pengfu.JokeUtil; import com.lnyp.joke.widget.SmartisanDrawable; import com.lnyp.recyclerview.EndlessRecyclerOnScrollListener; import com.lnyp.recyclerview.HeaderAndFooterRecyclerViewAdapter; import com.lnyp.recyclerview.RecyclerViewLoadingFooter; import com.lnyp.recyclerview.RecyclerViewStateUtils; import com.victor.loading.rotate.RotateLoading;import org.jsoup.Jsoup; import org.jsoup.nodes.Document;import java.util.ArrayList; import java.util.List;import butterknife.BindView; import butterknife.ButterKnife; import butterknife.Unbinder;public class MainFragment extends Fragment {private Unbinder unbinder;@BindView(R.id.rotateloading)public RotateLoading rotateloading;@BindView(R.id.swipeRefreshLayout)public PullRefreshLayout swipeRefreshLayout;@BindView(R.id.listInspirations)public RecyclerView listInspirations;private HeaderAndFooterRecyclerViewAdapter mAdapter;private List<JokeBean> mDatas;private int page = 1;private boolean mHasMore = false;private boolean isRefresh = true;// 處理請求返回信息private MyHandler mHandler = new MyHandler();private class MyHandler extends Handler {public void handleMessage(android.os.Message msg) {switch (msg.what) {case 0:RecyclerViewStateUtils.setFooterViewState(listInspirations, RecyclerViewLoadingFooter.State.Normal);swipeRefreshLayout.setRefreshing(false);rotateloading.stop();mAdapter.notifyDataSetChanged();break;}}}public MainFragment() {}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {// Inflate the layout for this fragmentView view = inflater.inflate(R.layout.fragment_main, container, false);unbinder = ButterKnife.bind(this, view);initView();rotateloading.start();refreshReq();return view;}private void initView() {mDatas = new ArrayList<>();JokeListAdapter jokeListAdapter = new JokeListAdapter(this, mDatas, onClickListener);mAdapter = new HeaderAndFooterRecyclerViewAdapter(jokeListAdapter);listInspirations.setAdapter(mAdapter);listInspirations.setLayoutManager(new LinearLayoutManager(getActivity()));listInspirations.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity()).colorResId(R.color.divider_color).build());listInspirations.addOnScrollListener(mOnScrollListener);swipeRefreshLayout.setOnRefreshListener(onRefreshListener);swipeRefreshLayout.setRefreshDrawable(new SmartisanDrawable(getActivity(), swipeRefreshLayout));swipeRefreshLayout.setBackgroundColor(Color.parseColor("#EFEFEF"));swipeRefreshLayout.setColor(Color.parseColor("#8F8F81"));}private PullRefreshLayout.OnRefreshListener onRefreshListener = new PullRefreshLayout.OnRefreshListener() {@Overridepublic void onRefresh() {refreshReq();}};private void refreshReq() {isRefresh = true;page = 1;qryJokes();}private void qryJokes() {final String url = JokeApi.PENGFU_NEW_JOKES + page + JokeApi.URL_SUFFIX;System.out.println(url);HttpUtils.doGetAsyn(url, new HttpUtils.CallBack() {@Overridepublic void onRequestComplete(String result) {if (result == null) {return;}System.out.println(result);Document doc = Jsoup.parse(result);if (doc != null) {JokeUtil jokeUtil = new JokeUtil();List<JokeBean> jokeBeens = jokeUtil.getNewJokelist(doc);if (jokeBeens != null) {page++;mHasMore = true;if (isRefresh) {mDatas.clear();isRefresh = false;}mDatas.addAll(jokeBeens);mHandler.sendEmptyMessage(0);}}}});}private EndlessRecyclerOnScrollListener mOnScrollListener = new EndlessRecyclerOnScrollListener() {@Overridepublic void onLoadNextPage(View view) {super.onLoadNextPage(view);RecyclerViewLoadingFooter.State state = RecyclerViewStateUtils.getFooterViewState(listInspirations);if (state == RecyclerViewLoadingFooter.State.Loading) {return;}if (mHasMore) {RecyclerViewStateUtils.setFooterViewState(getActivity(), listInspirations, mHasMore, RecyclerViewLoadingFooter.State.Loading, null);qryJokes();} else {RecyclerViewStateUtils.setFooterViewState(getActivity(), listInspirations, mHasMore, RecyclerViewLoadingFooter.State.TheEnd, null);}}};private View.OnClickListener onClickListener = new View.OnClickListener() {@Overridepublic void onClick(View view) {try {int pos = (int) view.getTag(R.string.app_name);JokeBean jokeBean = mDatas.get(pos);String showImg = jokeBean.getDataBean().getShowImg();String gifSrcImg = jokeBean.getDataBean().getGifsrcImg(); //System.out.println(showImg + " " + gifSrcImg);} catch (Exception e) {e.printStackTrace();}}};@Overridepublic void onDestroyView() {super.onDestroyView();unbinder.unbind();} }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
功能邏輯比較簡單,不多做解釋。 到這里,我們的“捧腹”APP已經完成了80%了。下面,在做些擴展性的功能,使得它更像一個完整的APP。
3. 圖片的大圖瀏覽功能
上篇博文,我們就提到了,我們要使用PhotoView實現大圖的瀏覽功能。?
PhotoView的使用,可以直接在它的github官方介紹上看到,下面,我直接貼出使用代碼。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
程序中,我們添加了一個事件監聽,主要是為了在用戶單擊圖片顯示或者不顯示部分時,可以退出瀏覽。
4.為APP加入Bughd 實現崩潰分析、版本更新功能
功能做到這里,基本上完成了90%的APP,接下來,我們為其加入崩潰分析、版本更新功能。?
關于如何配置,大家直接到http://bughd.com/doc/android官網看,看官方文檔,為app添加功能,是開發的基本能力,而且,這個功能集成并不困難,建議大家自己添加,有疑問,可參考我最后放出的源碼。
APP打包發布
截止此處,我們的“捧腹”APP基本上就已經實現了,在說打包發布之前,我要提到一個很重要的問題,那就是數據版權。 我們知道,這個app的數據,是分析“捧腹網”的網頁,拿到的,我們應當尊重其版權所有。 因為我們是學習使用,所以大家應在app明顯的位置,加上數據來源。這里,我選擇在啟動頁面上添加。?
接下來,就是打包發布了。關于如何打包app,限于篇幅,請參考我之前寫的?Android Studio(十二):打包多個發布渠道的apk文件?,打包apk成功后,我們將其發布在fir.im免費托管分發服務的平臺上,方便大家下載測試。(如果沒問題,可以上傳到應用市場)。?
最后,讓我們看下APP最終效果。?
項目小結:?
如果你能耐下心來,看完這三篇實戰博文,相信你也可以做一個簡單的app了。這個app實現并不難,博文講解的也算是詳盡,很容易理解。?
這系列的博文,主要是針對初中級開發者,幫大家在研發過程中,理清思路,一步步完成一個完整的app。希望看完這篇博文的朋友,也能夠舉一反三, 做出一個自己所屬的app。
源碼地址:https://github.com/zuiwuyuan/Joke?
apk下載地址:?http://fir.im/xiaohane
歡迎有問題的朋友,留言討論,也歡迎進QQ群來討論交流:487786925( Android研發村 ),謝謝大家的支持。
版權聲明:本文為博主原創文章,未經博主允許不得轉載。 http://blog.csdn.net/zuiwuyuan/article/details/52554939總結
以上是生活随笔為你收集整理的Android实战:手把手实现“捧腹网”APP(三)-----UI实现,逻辑实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android实战:手把手实现“捧腹网”
- 下一篇: Android OkHttp3简介和使用