APP页面实现


根据原型图,我们可以看出,UI分为两部分,底部Tab导航+上方列表显示。 所以此处,我们通过 FragmentTabHost+Fragment,来实现底部的导航页面,通过RecyclerView来实现列表页面。 
因为篇幅原因,关于FragmentTabHost和RecyclerView的使用,不多做介绍,可以建议参考: FragmentTabHost使用方法及RecycleView_PullToRefresh_LoadMore两篇文章,其中后者关于Recyclerview的项目是我之前封装的一个支持下拉刷新,加载更多,添加Header和Footer等功能的RecyclerView,便于使用。

此处,再多说一点,因为是我们做自己来实现该ui,没美工给我设计图,切图标, 所以我们需要自己去找图标,此处推荐Iconfont-阿里巴巴矢量图标库, 在这里,我们可以找到很多的图标,选择适用的几个即可。

篇幅原因,具体的页面布局、实现代码,我这里就不多贴,有兴趣的,可以直接看源码,此处,只贴出列表list_item的页面布局代码。 
从原型图中,我们可以看出,列表的显示分为纯文显示和图片显示,所以我们的item布局,应该要兼容这两种显示方式。

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"xmlns:card_view="http://schemas.android.com/apk/res-auto"android:id="@+id/card_view"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="4dp"android:layout_marginRight="4dp"android:foreground="?android:attr/selectableItemBackground"card_view:cardBackgroundColor="#FFFFFF"card_view:cardCornerRadius="8dp"card_view:cardElevation="2dp"card_view:cardUseCompatPadding="true"><LinearLayout
        android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><RelativeLayout
            android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="6dp"android:gravity="center_vertical"><com.lnyp.joke.widget.CircleImageView
                android:id="@+id/imgUser"android:layout_width="50dp"android:layout_height="50dp"android:src="@mipmap/ic_launcher" /><LinearLayout
                android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_marginLeft="14dp"android:layout_toRightOf="@id/imgUser"android:orientation="vertical"><TextView
                    android:id="@+id/textUserName"android:layout_width="wrap_content"android:layout_height="wrap_content"android:singleLine="true"android:text="textUserNametextUserNametextUserNametextUserNametextUserNametextUserNametextUserNametextUserNametextUserName"android:textColor="#333333"android:textSize="14sp" /><TextView
                    android:id="@+id/textLastTime"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="6dp"android:layout_toRightOf="@id/imgUser"android:gravity="right"android:singleLine="true"android:text="textLastTime"android:textColor="#555555"android:textSize="12sp" /></LinearLayout></RelativeLayout><TextView
            android:id="@+id/textContent"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginBottom="4dp"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="4dp"android:gravity="left"android:lineSpacingExtra="4dp"android:text="描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述描述"android:textColor="#333333"android:textSize="15sp"android:visibility="gone" /><com.lnyp.joke.widget.ShowMaxImageView
            android:id="@+id/imgJoke"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="10dp"android:src="@mipmap/ic_launcher" /><TextView
            android:id="@+id/textTitle"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="4dp"android:singleLine="true"android:text="title title title tiltle title"android:textColor="#333333"android:textSize="16sp" /><LinearLayout
            android:id="@+id/layoutTags"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginBottom="2dp"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="4dp"android:gravity="right"android:orientation="horizontal"><TextView
                android:id="@+id/textTag1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginBottom="4dp"android:layout_marginLeft="4dp"android:background="@drawable/house_tag_text_bg"android:gravity="left"android:paddingBottom="2dp"android:paddingLeft="4dp"android:paddingRight="4dp"android:paddingTop="2dp"android:singleLine="true"android:text="标签"android:textColor="#333333"android:textSize="10sp" /><TextView
                android:id="@+id/textTag2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginBottom="4dp"android:layout_marginLeft="4dp"android:background="@drawable/house_tag_text_bg"android:gravity="left"android:paddingBottom="2dp"android:paddingLeft="4dp"android:paddingRight="4dp"android:paddingTop="2dp"android:singleLine="true"android:text="标签"android:textColor="#333333"android:textSize="10sp" /><TextView
                android:id="@+id/textTag3"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginBottom="4dp"android:layout_marginLeft="4dp"android:background="@drawable/house_tag_text_bg"android:gravity="left"android:paddingBottom="2dp"android:paddingLeft="4dp"android:paddingRight="4dp"android:paddingTop="2dp"android:singleLine="true"android:text="标签"android:textColor="#333333"android:textSize="10sp" /><TextView
                android:id="@+id/textTag4"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginBottom="4dp"android:layout_marginLeft="4dp"android:background="@drawable/house_tag_text_bg"android:gravity="left"android:paddingBottom="2dp"android:paddingLeft="4dp"android:paddingRight="4dp"android:paddingTop="2dp"android:singleLine="true"android:text="标签"android:textColor="#333333"android:textSize="10sp" /></LinearLayout></LinearLayout></android.support.v7.widget.CardView>
  • 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官方介绍上看到,下面,我直接贴出使用代码。


import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.text.TextUtils;
import android.view.View;
import android.widget.ImageView;import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;import butterknife.BindView;
import butterknife.ButterKnife;
import uk.co.senab.photoview.PhotoViewAttacher;/*** 图片浏览*/
public class PhotoActivity extends FragmentActivity {@BindView(R.id.imgJoke)public ImageView imgJoke;private String showImg;private String gifSrcImg;private PhotoViewAttacher mAttacher;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_photo);ButterKnife.bind(this);mAttacher = new PhotoViewAttacher(imgJoke);showImg = getIntent().getStringExtra("showImg");gifSrcImg = getIntent().getStringExtra("gifSrcImg");System.out.println(showImg + "   " + gifSrcImg);if (TextUtils.isEmpty(gifSrcImg)) {Glide.with(this).load(showImg).asBitmap().diskCacheStrategy(DiskCacheStrategy.SOURCE).into(imgJoke);} else {Glide.with(this).load(gifSrcImg).asGif().diskCacheStrategy(DiskCacheStrategy.SOURCE).into(imgJoke);}mAttacher.update();mAttacher.setOnPhotoTapListener(new PhotoViewAttacher.OnPhotoTapListener() {@Overridepublic void onPhotoTap(View view, float x, float y) {PhotoActivity.this.finish();}@Overridepublic void onOutsidePhotoTap() {PhotoActivity.this.finish();}});}
}
  • 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实现,逻辑实现相关推荐

  1. Android实战:手把手实现“捧腹网”APP(二)-----捧腹APP原型设计、实现框架选取...

    Android实战:手把手实现"捧腹网"APP(一)-–捧腹网网页分析.数据获取 Android实战:手把手实现"捧腹网"APP(二)-–捧腹APP原型设计.实 ...

  2. Android实战:手把手实现“捧腹网”APP(二)-----捧腹APP原型设计、实现框架选取

    APP原型设计 在APP的开发过程中,原型设计是必不可少的.用户界面原型必须在先启阶段的初期或在精化阶段一开始建立.整个系统(包括它的"实际"用户界面)的分析.设计和实施必须在原型 ...

  3. Android实战:手把手实现“捧腹网”APP(一)-----捧腹网网页分析、数据获取

    "捧腹网"页面结构分析 捧腹网M站地址: http://m.pengfu.com/ 捧腹网M站部分截图:      从截图中(可以直接去网站看下),我们可以看出,该网站相对简单,一 ...

  4. go 实战并发爬虫(捧腹网)

    package mainimport ("fmt""strconv""net/http""regexp""st ...

  5. 安卓外包公司—捧腹网Android与iPhone客户端(最新上线案例分享)

         捧腹网是中国领先的幽默笑话分享网站,致力于提供一个分享各类幽默笑话,搞笑图片,动态图,搞笑视频,经典段子,冷笑话,冏人冏事等幽默内容的互动平台,为大家带去欢乐和笑声.让我们一起分享快乐,捧腹 ...

  6. java爬取捧腹网段子

    先上效果图: 准备工作: /*** 建立http连接*/ public static String Connect(String address) {HttpURLConnection conn = ...

  7. python爬取捧腹网gif图片

    #_*_coding:utf-8_*_ #爬取捧腹网GIF图片 import urllib,re import urllib.request import chardet #需要导入这个模块,检测编码 ...

  8. Go语言段子爬虫--捧腹网

    最后我们来进行一次网络段子的爬虫,爬取捧腹网的段子数据 1.爬取网页的段子链接: 程序代码: package mainimport ("fmt""net/http&quo ...

  9. golang实现捧腹网爬取笑话

    爬虫的步骤见:here 以下golang代码实现对捧腹网笑话的爬取,并保存到本地的joy文件夹(程序会自行创建)内 package mainimport ("fmt""n ...

最新文章

  1. 前序遍历与中序遍历确定后序遍历
  2. 马云携阿里17位创始人及合伙人捐赠浙大一院5.6亿,杭州渐成中国硅谷
  3. Windows 快速删除 大量文件
  4. MySQL事务autocommit自动提交
  5. Python练习题:批量删除多个文件夹内的相同文件
  6. html图片离边框有距离,CSS边框:距离对象边缘?
  7. 记事本linux命令换行符,Windows 10版记事本应用终于支持Linux/Mac换行符 排版不再辣眼睛...
  8. centos7赋予全部权限_终结CentOS 7+Snort2.9+BASE 安装
  9. 大数据分析如何应用在驾驶世界
  10. Mac怎么读写NTFS格式?Mac读写NTFS格式硬盘教程
  11. HDLBITS笔记32:有限状态机二(Fsm3comb、Fsm3onehot、Fsm3、Fsm3s)
  12. java excel 取消科学计数法_基于Java将Excel科学计数法解析成数字
  13. (病毒安全)服务器被中了木马,如何清除
  14. Oracle数据库表的字段添加注释和向现有表添加字段
  15. (最新整理)国内网页设计网站网址大全(转)
  16. 【Unity3D】协同程序
  17. wqewqewqewq
  18. IOS 安卓双平台视频APP推荐-VIP
  19. 论文投稿指南——中文核心期刊推荐(计算机技术2)
  20. 模电-基本放大电路-共射放大

热门文章

  1. 搭建基于域名的虚拟web主机
  2. petshop4.0 详解之五(PetShop之业务逻辑层设计)[转]
  3. 如何修改 asp.net core 5 程序的默认端口号?
  4. WPF实现数据拾取器
  5. .NET 6新特性试用 | 可空引用类型
  6. 使用 Directory.Build 来消除项目文件中的重复配置
  7. .NET Core HttpClient请求异常思考
  8. 记一次 .NET WPF布草管理系统 挂死分析
  9. 浅析 EF Core 5 中的 DbContextFactory
  10. 再被补刀!Flash又遭抛弃,你会怀念它吗?