├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── misc.xml ├── modules.xml └── runConfigurations.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── byl │ │ └── mvpdemo │ │ ├── MyApplication.java │ │ ├── adapter │ │ ├── BaseAdapter.java │ │ ├── ImagesAdapter.java │ │ └── NewsAdapter.java │ │ ├── api │ │ ├── ApiService.java │ │ └── ApiUtil.java │ │ ├── model │ │ ├── modelbean │ │ │ ├── BaseBean.java │ │ │ ├── ImageModel.java │ │ │ ├── LoginBean.java │ │ │ ├── LoginModel.java │ │ │ ├── News.java │ │ │ ├── NewsBean.java │ │ │ └── NewsModel.java │ │ └── mvpview │ │ │ ├── ImagesMvpView.java │ │ │ ├── LoginMvpView.java │ │ │ ├── NewsMvpView.java │ │ │ └── base │ │ │ └── MvpView.java │ │ ├── presenter │ │ ├── ImagesPresenter.java │ │ ├── LoginPresenter.java │ │ ├── NewsPresenter.java │ │ └── base │ │ │ ├── BasePresenter.java │ │ │ └── Presenter.java │ │ ├── ui │ │ ├── base │ │ │ ├── BaseActivity.java │ │ │ └── BaseFragment.java │ │ ├── images │ │ │ ├── FragmentImageTab1.java │ │ │ └── FragmentImageTab2.java │ │ ├── login │ │ │ └── LoginActivity.java │ │ └── main │ │ │ ├── FragmentTab1.java │ │ │ ├── FragmentTab2.java │ │ │ ├── FragmentTab3.java │ │ │ ├── MainActivity.java │ │ │ └── adapter │ │ │ ├── FragmentMainTabAdapter.java │ │ │ └── FragmentVedioAdapter.java │ │ ├── util │ │ ├── LogUtil.java │ │ └── SysUtil.java │ │ └── view │ │ ├── MyLinearLayoutManager.java │ │ ├── MyProgressDialog.java │ │ └── pullrecyclerview │ │ ├── PullBaseView.java │ │ ├── PullRecyclerView.java │ │ ├── RefreshAnimView.java │ │ └── RefreshLoadingView.java │ └── res │ ├── anim │ └── alpha_in.xml │ ├── color │ └── main_tab_text_selector.xml │ ├── drawable │ ├── anim_refresh.xml │ ├── common_back_arrow_selector.xml │ ├── common_btn_selector.xml │ ├── common_image_selector.xml │ ├── common_text_selector.xml │ ├── shape_bg_common.xml │ ├── shape_bg_common_button.xml │ ├── shape_bg_common_button_press.xml │ ├── shape_bg_common_transparent.xml │ ├── shape_bg_common_white.xml │ ├── tab1_selector.xml │ ├── tab2_selector.xml │ ├── tab3_selector.xml │ └── tab_text_selector.xml │ ├── layout │ ├── activity_login.xml │ ├── activity_main.xml │ ├── common_title_bar.xml │ ├── fragment_1.xml │ ├── fragment_2.xml │ ├── fragment_3.xml │ ├── fragment_images_tab1.xml │ ├── fragment_images_tab2.xml │ ├── item_girls.xml │ ├── item_home_head.xml │ ├── item_img.xml │ ├── item_main_tab.xml │ ├── item_news.xml │ ├── loading_dialog.xml │ ├── refresh_footer.xml │ └── refresh_header.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ ├── banner.png │ ├── fop.png │ ├── head_default.png │ ├── home_icon_cg_glfriends.png │ ├── home_icon_cg_glhouse.png │ ├── home_icon_cg_gllaw.png │ ├── home_icon_cg_gllife.png │ ├── ic_common_back_arrow_normal.png │ ├── ic_common_back_arrow_pressed.png │ ├── ic_launcher.png │ ├── ic_loading_dialog.png │ ├── ic_pulltorefresh_arrow.png │ ├── ic_pulltorefresh_arrow_up.png │ ├── ic_search.png │ ├── icon_tabbar_favorites.png │ ├── icon_tabbar_favorites_selected.png │ ├── icon_tabbar_library.png │ ├── icon_tabbar_library_selected.png │ ├── icon_tabbar_settings.png │ ├── icon_tabbar_settings_selected.png │ ├── iv_qr.png │ ├── takeout_img_list_loading_pic1.png │ └── takeout_img_list_loading_pic2.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-v21 │ └── styles.xml │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── appdemo.apk ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | MVPDemo -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MVP-Retrofit-RxJava(项目年久失修,不再建议使用) 2 | Android MVP+Retrofit+RxJava项目实践 3 | 4 | 1.登录 2.首页 3.图片 5 | 6 |  7 | 8 | 整个项目使用MVP架构,导航栏使用TabLayout+ViewPager+Fragment,网络请求部分则使用目前流行的Retrofit+RxJava! 9 | 10 | 下拉刷新: PullRecylerView:https://github.com/baiyuliang/PullRecyclerView 11 | CSDN:http://blog.csdn.net/baiyuliang2013/article/details/51516727 12 | 13 | 部分代码: 14 | 15 | LoginActivity: 16 | 17 | ``` 18 | /** 19 | * 登录 20 | */ 21 | void doLogin() { 22 | String account = et_account.getText().toString(); 23 | if (TextUtils.isEmpty(account)) { 24 | Toast.makeText(LoginActivity.this, "请输入您的手机号", Toast.LENGTH_SHORT).show(); 25 | return; 26 | } 27 | String pwd = et_pwd.getText().toString(); 28 | if (TextUtils.isEmpty(pwd)) { 29 | Toast.makeText(LoginActivity.this, "请输入您的密码", Toast.LENGTH_SHORT).show(); 30 | return; 31 | } 32 | loginPresenter.login(account); 33 | } 34 | 35 | @Override 36 | public void loginSuccess(LoginBean loginBean) { 37 | startActivity(MainActivity.class); 38 | finish(); 39 | Toast.makeText(LoginActivity.this, "登录成功", Toast.LENGTH_SHORT).show(); 40 | } 41 | 42 | @Override 43 | public void loginFail(String message) { 44 | Toast.makeText(LoginActivity.this, message, Toast.LENGTH_SHORT).show(); 45 | } 46 | ``` 47 | 48 | 网络请求核心代码: 49 | ApiUtil: 50 | 51 | ``` 52 | public class ApiUtil { 53 | 54 | public static ApiService createApiService() { 55 | OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder(); 56 | okHttpClientBuilder.connectTimeout(10 * 1000, TimeUnit.MILLISECONDS);//设置请求超时时间10s 57 | OkHttpClient client = okHttpClientBuilder 58 | .addInterceptor((chain) -> {//添加统一参数 59 | Request request = chain.request(); 60 | HttpUrl url = request.url() 61 | .newBuilder() 62 | .addQueryParameter("showapi_appid", "20676") 63 | .addQueryParameter("showapi_sign", "f730cd8c4cf8498895f83d43ddaba8c2") 64 | .build(); 65 | request = request.newBuilder().url(url).build(); 66 | return chain.proceed(request); 67 | }) 68 | .addInterceptor((chain) -> {//log拦截器 69 | Request request = chain.request(); 70 | LogUtil.v("request>>" + request.toString()); 71 | Response response = chain.proceed(chain.request()); 72 | MediaType mediaType = response.body().contentType(); 73 | String content = response.body().string(); 74 | LogUtil.i("response>>" + content); 75 | return response.newBuilder().body(ResponseBody.create(mediaType, content)).build(); 76 | }) 77 | .hostnameVerifier((hostname, session) -> true) 78 | .build(); 79 | 80 | Retrofit retrofit = new Retrofit.Builder() 81 | .baseUrl(ApiService.API_ROOT) 82 | .client(client) 83 | .addConverterFactory(GsonConverterFactory.create(new Gson())) 84 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 85 | .build(); 86 | return retrofit.create(ApiService.class); 87 | } 88 | 89 | } 90 | ``` 91 | 92 | #### 已知bug: 93 | 94 | 首页使用RecyclerView+Header的模式,整体为一个RecyclerView,因RecycleView没有类似ScrollView的滑动监听,因此测量RecycleView滑动距离时,在item数量变化情况下会影响测量结果,导致首页标题栏跟随手指滑动透明效果出现问题,此案例只作为学习使用,实际项目中可以使用阿里的vlayout,强大易用! 95 | 96 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'me.tatarka.retrolambda' 3 | 4 | android { 5 | compileSdkVersion 23 6 | buildToolsVersion "23.0.3" 7 | 8 | defaultConfig { 9 | applicationId "com.byl.mvpdemo" 10 | minSdkVersion 14 11 | targetSdkVersion 23 12 | versionCode 1 13 | versionName "1.0" 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | 22 | //应用JDK1.8 23 | compileOptions { 24 | sourceCompatibility JavaVersion.VERSION_1_8 25 | targetCompatibility JavaVersion.VERSION_1_8 26 | } 27 | //应用拉姆达表达式 28 | retrolambda { 29 | jdk System.getenv("JAVA_HOME") 30 | javaVersion JavaVersion.VERSION_1_7 31 | } 32 | 33 | } 34 | 35 | dependencies { 36 | compile fileTree(include: ['*.jar'], dir: 'libs') 37 | compile 'com.squareup.retrofit2:retrofit:2.0.2' 38 | compile 'com.squareup.retrofit2:converter-gson:2.0.2' 39 | compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2' 40 | compile 'com.android.support:appcompat-v7:23.4.0' 41 | compile 'com.android.support:support-v4:23.4.0' 42 | compile 'com.squareup:otto:1.3.8' 43 | compile 'io.reactivex:rxandroid:1.1.0' 44 | compile 'io.reactivex:rxjava:1.1.0' 45 | compile 'com.android.support:design:23.4.0' 46 | compile 'com.android.support:recyclerview-v7:23.4.0' 47 | compile 'com.squareup.picasso:picasso:2.3.2' 48 | } 49 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\sunshine\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/MyApplication.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo; 2 | 3 | import android.app.Application; 4 | 5 | import com.byl.mvpdemo.util.LogUtil; 6 | 7 | /** 8 | * Created by baiyuliang on 2016-7-14. 9 | */ 10 | public class MyApplication extends Application { 11 | 12 | @Override 13 | public void onCreate() { 14 | super.onCreate(); 15 | LogUtil.isShowLog = true; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/adapter/BaseAdapter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * BaseAdapter 13 | * Created by baiyuliang on 2016-5-27. 14 | */ 15 | public class BaseAdapter extends RecyclerView.Adapter { 16 | 17 | public Context context;//上下文 18 | public List listDatas;//数据源 19 | public List listDatas1, listDatas2;//多数据源 20 | public LayoutInflater mInflater; 21 | public OnViewClickListener onViewClickListener;//item子view点击事件 22 | public OnItemClickListener onItemClickListener;//item点击事件 23 | public OnItemLongClickListener onItemLongClickListener;//item长按事件 24 | 25 | /** 26 | * 单数据源 27 | * 28 | * @param context 29 | * @param listDatas 30 | */ 31 | public BaseAdapter(Context context, List listDatas) { 32 | init(context, listDatas); 33 | } 34 | 35 | /** 36 | * 如果item的子View有点击事件,可使用该构造方法 37 | * 单数据源 38 | * 39 | * @param context 40 | * @param listDatas 41 | * @param onViewClickListener 42 | */ 43 | public BaseAdapter(Context context, List listDatas, OnViewClickListener onViewClickListener) { 44 | init(context, listDatas); 45 | this.onViewClickListener = onViewClickListener; 46 | } 47 | 48 | /** 49 | * 多数据源 50 | * 51 | * @param context 52 | * @param listDatas1 53 | * @param listDatas2 54 | */ 55 | public BaseAdapter(Context context, List listDatas1, List listDatas2) { 56 | init(context, listDatas1, listDatas2); 57 | } 58 | 59 | 60 | /** 61 | * 如果item的子View有点击事件,可使用该构造方法 62 | * 多数据源 63 | * 64 | * @param context 65 | * @param listDatas1,listDatas2 66 | * @param onViewClickListener 67 | */ 68 | public BaseAdapter(Context context, List listDatas1, List listDatas2, OnViewClickListener onViewClickListener) { 69 | init(context, listDatas1, listDatas2); 70 | this.onViewClickListener = onViewClickListener; 71 | } 72 | 73 | /** 74 | * 初始化 75 | * 单数据源 76 | * 77 | * @param context 78 | * @param listDatas 79 | */ 80 | void init(Context context, List listDatas) { 81 | this.context = context; 82 | this.listDatas = listDatas; 83 | this.mInflater = LayoutInflater.from(context); 84 | } 85 | 86 | /** 87 | * 初始化 88 | * 多数据源 89 | * 90 | * @param context 91 | * @param listDatas1 92 | * @param listDatas2 93 | */ 94 | void init(Context context, List listDatas1, List listDatas2) { 95 | this.context = context; 96 | this.listDatas1 = listDatas1; 97 | this.listDatas2 = listDatas2; 98 | this.mInflater = LayoutInflater.from(context); 99 | } 100 | 101 | @Override 102 | public T onCreateViewHolder(ViewGroup parent, int viewType) { 103 | return null; 104 | } 105 | 106 | @Override 107 | public void onBindViewHolder(T holder, final int position) { 108 | holder.itemView.setOnClickListener(new View.OnClickListener() {//item点击事件 109 | @Override 110 | public void onClick(View v) { 111 | if (onItemClickListener != null) { 112 | onItemClickListener.onItemClick(position); 113 | } 114 | } 115 | }); 116 | holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {//item长按事件 117 | @Override 118 | public boolean onLongClick(View v) { 119 | if (onItemLongClickListener != null) { 120 | onItemLongClickListener.onItemLongClick(position); 121 | } 122 | return true; 123 | } 124 | }); 125 | } 126 | 127 | @Override 128 | public int getItemCount() { 129 | return listDatas.size(); 130 | } 131 | 132 | /** 133 | * item中子view的点击事件(回调) 134 | */ 135 | public interface OnViewClickListener { 136 | /** 137 | * @param position item position 138 | * @param viewtype 点击的view的类型,调用时根据不同的view传入不同的值加以区分 139 | */ 140 | void onViewClick(int position, int viewtype); 141 | } 142 | 143 | /** 144 | * item点击事件 145 | */ 146 | public interface OnItemClickListener { 147 | void onItemClick(int position); 148 | } 149 | 150 | /** 151 | * item长按事件 152 | */ 153 | public interface OnItemLongClickListener { 154 | void onItemLongClick(int position); 155 | } 156 | 157 | /** 158 | * 设置item点击事件 159 | * 160 | * @param onItemClickListener 161 | */ 162 | public void setOnItemClickListener(OnItemClickListener onItemClickListener) { 163 | this.onItemClickListener = onItemClickListener; 164 | } 165 | 166 | /** 167 | * 设置item长按事件 168 | * 169 | * @param onItemLongClickListener 170 | */ 171 | public void setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener) { 172 | this.onItemLongClickListener = onItemLongClickListener; 173 | } 174 | 175 | /** 176 | * view的点击事件 177 | */ 178 | class ViewClikListener implements View.OnClickListener { 179 | 180 | OnViewClickListener onViewClickListener; 181 | int position; 182 | int viewtype; 183 | 184 | public ViewClikListener(OnViewClickListener onViewClickListener, int position, int viewtype) { 185 | this.onViewClickListener = onViewClickListener; 186 | this.position = position; 187 | this.viewtype = viewtype; 188 | } 189 | 190 | @Override 191 | public void onClick(View v) { 192 | onViewClickListener.onViewClick(position, viewtype); 193 | } 194 | } 195 | 196 | } 197 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/adapter/ImagesAdapter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.text.TextUtils; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | import android.widget.TextView; 10 | 11 | import com.byl.mvpdemo.R; 12 | import com.byl.mvpdemo.model.modelbean.News; 13 | import com.squareup.picasso.Picasso; 14 | 15 | import java.util.List; 16 | 17 | public class ImagesAdapter extends BaseAdapter { 18 | 19 | public ImagesAdapter(Context context, List listDatas, OnViewClickListener onViewClickListener) { 20 | super(context, listDatas, onViewClickListener); 21 | } 22 | 23 | @Override 24 | public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 25 | return new MyViewHolder(mInflater.inflate(R.layout.item_girls, parent, false)); 26 | } 27 | 28 | @Override 29 | public void onBindViewHolder(MyViewHolder holder, final int position) { 30 | super.onBindViewHolder(holder, position); 31 | News news = (News) listDatas.get(position);//转换 32 | if (!TextUtils.isEmpty(news.getPicUrl())) { 33 | Picasso.with(context).load(news.getPicUrl()).error(R.mipmap.banner).into(holder.img); 34 | } else { 35 | holder.img.setImageResource(R.mipmap.banner); 36 | } 37 | holder.tv_title.setText(news.getTitle()); 38 | holder.iv_zan.setOnClickListener(new ViewClikListener(onViewClickListener, position, 1));//赞 viewtype=1代表赞点击事件 39 | } 40 | 41 | @Override 42 | public int getItemCount() { 43 | return listDatas.size(); 44 | } 45 | 46 | @Override 47 | public int getItemViewType(int position) { 48 | return super.getItemViewType(position); 49 | } 50 | 51 | class MyViewHolder extends RecyclerView.ViewHolder { 52 | TextView tv_title;//内容 53 | ImageView img, iv_zan;//赞 54 | 55 | public MyViewHolder(View view) { 56 | super(view); 57 | img = (ImageView) view.findViewById(R.id.img); 58 | tv_title = (TextView) view.findViewById(R.id.tv_title); 59 | iv_zan = (ImageView) view.findViewById(R.id.iv_zan); 60 | 61 | } 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/adapter/NewsAdapter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v4.view.PagerAdapter; 5 | import android.support.v4.view.ViewPager; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.text.TextUtils; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.ImageView; 11 | import android.widget.LinearLayout; 12 | import android.widget.TextView; 13 | import android.widget.Toast; 14 | 15 | import com.byl.mvpdemo.R; 16 | import com.byl.mvpdemo.model.modelbean.ImageModel; 17 | import com.byl.mvpdemo.model.modelbean.News; 18 | import com.byl.mvpdemo.model.modelbean.NewsModel; 19 | import com.byl.mvpdemo.util.LogUtil; 20 | import com.squareup.picasso.Picasso; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | public class NewsAdapter extends BaseAdapter { 26 | 27 | boolean isViewPagerLoadScucess = false;//viewpager是否加载成功 28 | 29 | /** 30 | * @param context 31 | * @param listDatas1 banner图片数据 32 | * @param listDatas2 新闻列表数据 33 | * @param onViewClickListener 我们要设置item(header)中某控件的点击事件 34 | */ 35 | public NewsAdapter(Context context, List listDatas1, List listDatas2, OnViewClickListener onViewClickListener) { 36 | super(context, listDatas1, listDatas2, onViewClickListener); 37 | } 38 | 39 | @Override 40 | public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 41 | return new MyViewHolder(mInflater.inflate(viewType, parent, false)); 42 | } 43 | 44 | @Override 45 | public void onBindViewHolder(MyViewHolder holder, final int position) { 46 | // super.onBindViewHolder(holder, position);//当前环境不继承父类的点击事件 47 | if (position == 0) {//header 48 | if (!isViewPagerLoadScucess && listDatas1.size() > 0) { 49 | initViewPager(holder); 50 | } 51 | holder.ll_1.setOnClickListener(new ViewClikListener(onViewClickListener, position, 1)); 52 | holder.ll_2.setOnClickListener(new ViewClikListener(onViewClickListener, position, 2)); 53 | holder.ll_3.setOnClickListener(new ViewClikListener(onViewClickListener, position, 3)); 54 | holder.ll_4.setOnClickListener(new ViewClikListener(onViewClickListener, position, 4)); 55 | } else {//列表 56 | News news = (News) listDatas2.get(position - 1);//转换(注意:是position-1) 57 | if (!TextUtils.isEmpty(news.getPicUrl())) { 58 | Picasso.with(context).load(news.getPicUrl()).error(R.mipmap.banner).into(holder.iv_icon); 59 | } else { 60 | holder.iv_icon.setImageResource(R.mipmap.banner); 61 | } 62 | holder.tv_title.setText(news.getTitle());// 63 | holder.tv_des.setText(news.getDescription());// 64 | holder.tv_time.setText(news.getCtime());// 65 | holder.itemView.setOnClickListener((v) -> {//item点击事件 66 | if (onItemClickListener != null) { 67 | onItemClickListener.onItemClick(position - 1); 68 | } 69 | }); 70 | } 71 | } 72 | 73 | /** 74 | * 注意事项: 75 | * 因为banner为一个header,属于recycleview的一个item, 76 | * 当前情况下,listDatas1为banner数据,listDatas2为新闻列表数据 77 | * 即便此时listDatas1有多条数据,但是是属于头部item 的数据源,所以整体的ItemCount=1+listDatas2.size(),1即代表header; 78 | * 79 | * 如果是非header的情况,即两个数据源的列表,则ItemCount=listDatas1.size()+listDatas2.size(); 80 | * 81 | * @return 82 | */ 83 | @Override 84 | public int getItemCount() { 85 | return 1 + listDatas2.size(); 86 | } 87 | 88 | @Override 89 | public int getItemViewType(int position) { 90 | if (position == 0) { 91 | return R.layout.item_home_head; 92 | } else { 93 | return R.layout.item_news; 94 | } 95 | } 96 | 97 | class MyViewHolder extends RecyclerView.ViewHolder { 98 | ViewPager vp; 99 | LinearLayout ll_1, ll_2, ll_3, ll_4; 100 | 101 | ImageView iv_icon;// 102 | TextView tv_title, tv_des, tv_time;// 103 | 104 | public MyViewHolder(View view) { 105 | super(view); 106 | vp = (ViewPager) view.findViewById(R.id.vp);//banner 107 | ll_1 = (LinearLayout) view.findViewById(R.id.ll_1);//新闻1 108 | ll_2 = (LinearLayout) view.findViewById(R.id.ll_2);//新闻2 109 | ll_3 = (LinearLayout) view.findViewById(R.id.ll_3);//新闻3 110 | ll_4 = (LinearLayout) view.findViewById(R.id.ll_4);//新闻4 111 | 112 | iv_icon = (ImageView) view.findViewById(R.id.iv_icon);// 113 | tv_title = (TextView) view.findViewById(R.id.tv_title);//标题 114 | tv_des = (TextView) view.findViewById(R.id.tv_des);//内容 115 | tv_time = (TextView) view.findViewById(R.id.tv_time);//时间 116 | } 117 | } 118 | 119 | 120 | private void initViewPager(MyViewHolder holder) { 121 | isViewPagerLoadScucess = true; 122 | List imageViews = new ArrayList<>(); 123 | for (int i = 0; i < listDatas1.size(); i++) { 124 | final ImageModel imageModel = (ImageModel) listDatas1.get(i); 125 | View view = mInflater.inflate(R.layout.item_img, null); 126 | ImageView imageView = (ImageView) view.findViewById(R.id.img); 127 | Picasso.with(context).load(imageModel.getUrl()).error(R.mipmap.banner).into(imageView); 128 | //设置广告点击事件 129 | view.setOnClickListener(v -> { 130 | Toast.makeText(context, "图片>>" + imageModel.getUrl(), Toast.LENGTH_SHORT).show(); 131 | }); 132 | imageViews.add(view); 133 | } 134 | holder.vp.setAdapter(new PagerAdapter() { 135 | @Override 136 | public int getCount() { 137 | return imageViews.size(); 138 | } 139 | 140 | @Override 141 | public Object instantiateItem(ViewGroup arg0, int arg1) { 142 | arg0.addView(imageViews.get(arg1)); 143 | return imageViews.get(arg1); 144 | } 145 | 146 | @Override 147 | public void destroyItem(ViewGroup arg0, int arg1, Object arg2) { 148 | arg0.removeView((View) arg2); 149 | } 150 | 151 | @Override 152 | public boolean isViewFromObject(View view, Object object) { 153 | return view == object; 154 | } 155 | }); 156 | } 157 | 158 | public void setViewPagerLoadScucess(boolean viewPagerLoadScucess) { 159 | isViewPagerLoadScucess = viewPagerLoadScucess; 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/api/ApiService.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.api; 2 | 3 | import com.byl.mvpdemo.model.modelbean.LoginBean; 4 | import com.byl.mvpdemo.model.modelbean.NewsBean; 5 | 6 | import retrofit2.http.Field; 7 | import retrofit2.http.FormUrlEncoded; 8 | import retrofit2.http.GET; 9 | import retrofit2.http.POST; 10 | import retrofit2.http.Query; 11 | import rx.Observable; 12 | 13 | /** 14 | * Created by baiyuliang on 2016-7-14. 15 | */ 16 | public interface ApiService { 17 | 18 | String API_ROOT = "http://route.showapi.com/"; 19 | 20 | /** 21 | * 登录 22 | * 模拟登录,实际为手机号归属地查询接口 23 | * 24 | * @return 25 | */ 26 | @FormUrlEncoded 27 | @POST("6-1") 28 | Observable login(@Field("num") String num); 29 | 30 | /** 31 | * 新闻列表 32 | * 33 | * @param num 34 | * @param page 35 | * @return 36 | */ 37 | @GET("198-1") 38 | Observable news(@Query("num") String num, @Query("page") String page); 39 | 40 | /** 41 | * 美女图片列表 42 | * 参数类型与新闻列表相同,因此公用NewsBean 43 | * 44 | * @param num 45 | * @param page 46 | * @param rand 1.随机 0不随机 47 | * @return 48 | */ 49 | @GET("197-1") 50 | Observable girls(@Query("num") String num, @Query("page") String page, @Query("rand") String rand); 51 | 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/api/ApiUtil.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.api; 2 | 3 | import com.byl.mvpdemo.util.LogUtil; 4 | import com.google.gson.Gson; 5 | 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import okhttp3.HttpUrl; 9 | import okhttp3.MediaType; 10 | import okhttp3.OkHttpClient; 11 | import okhttp3.Request; 12 | import okhttp3.Response; 13 | import okhttp3.ResponseBody; 14 | import retrofit2.Retrofit; 15 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; 16 | import retrofit2.converter.gson.GsonConverterFactory; 17 | 18 | /** 19 | * Created by baiyuliang on 2016-7-14. 20 | */ 21 | public class ApiUtil { 22 | 23 | public static ApiService createApiService() { 24 | OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder(); 25 | okHttpClientBuilder.connectTimeout(10 * 1000, TimeUnit.MILLISECONDS);//设置请求超时时间10s 26 | OkHttpClient client = okHttpClientBuilder 27 | .addInterceptor((chain) -> {//添加统一参数 28 | Request request = chain.request(); 29 | HttpUrl url = request.url() 30 | .newBuilder() 31 | .addQueryParameter("showapi_appid", "20676") 32 | .addQueryParameter("showapi_sign", "f730cd8c4cf8498895f83d43ddaba8c2") 33 | .build(); 34 | request = request.newBuilder().url(url).build(); 35 | return chain.proceed(request); 36 | }) 37 | .addInterceptor((chain) -> {//log拦截器 38 | Request request = chain.request(); 39 | LogUtil.v("request>>" + request.toString()); 40 | Response response = chain.proceed(chain.request()); 41 | MediaType mediaType = response.body().contentType(); 42 | String content = response.body().string(); 43 | LogUtil.i("response>>" + content); 44 | return response.newBuilder().body(ResponseBody.create(mediaType, content)).build(); 45 | }) 46 | .hostnameVerifier((hostname, session) -> true) 47 | .build(); 48 | 49 | Retrofit retrofit = new Retrofit.Builder() 50 | .baseUrl(ApiService.API_ROOT) 51 | .client(client) 52 | .addConverterFactory(GsonConverterFactory.create(new Gson())) 53 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 54 | .build(); 55 | return retrofit.create(ApiService.class); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/modelbean/BaseBean.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.modelbean; 2 | 3 | /** 4 | * Created by baiyuliang on 2016-7-14. 5 | */ 6 | public class BaseBean { 7 | 8 | private String showapi_res_code; 9 | private String showapi_res_error; 10 | 11 | public String getShowapi_res_code() { 12 | return showapi_res_code; 13 | } 14 | 15 | public void setShowapi_res_code(String showapi_res_code) { 16 | this.showapi_res_code = showapi_res_code; 17 | } 18 | 19 | public String getShowapi_res_error() { 20 | return showapi_res_error; 21 | } 22 | 23 | public void setShowapi_res_error(String showapi_res_error) { 24 | this.showapi_res_error = showapi_res_error; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/modelbean/ImageModel.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.modelbean; 2 | 3 | /** 4 | * banner 5 | * Created by baiyuliang on 2016-7-20. 6 | */ 7 | public class ImageModel { 8 | 9 | private String url; 10 | private String link; 11 | private String des; 12 | 13 | public String getUrl() { 14 | return url; 15 | } 16 | 17 | public void setUrl(String url) { 18 | this.url = url; 19 | } 20 | 21 | public String getLink() { 22 | return link; 23 | } 24 | 25 | public void setLink(String link) { 26 | this.link = link; 27 | } 28 | 29 | public String getDes() { 30 | return des; 31 | } 32 | 33 | public void setDes(String des) { 34 | this.des = des; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/modelbean/LoginBean.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.modelbean; 2 | 3 | /** 4 | * Created by baiyuliang on 2016-7-14. 5 | */ 6 | public class LoginBean extends BaseBean { 7 | 8 | private LoginModel showapi_res_body; 9 | 10 | public LoginModel getShowapi_res_body() { 11 | return showapi_res_body; 12 | } 13 | 14 | public void setShowapi_res_body(LoginModel showapi_res_body) { 15 | this.showapi_res_body = showapi_res_body; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/modelbean/LoginModel.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.modelbean; 2 | 3 | /** 4 | * Created by baiyuliang on 2016-7-14. 5 | * 6 | * prov String 四川 省 7 | * city String test 市 8 | * name String test 运营商 9 | * num Number 1370011 号段 10 | * provCode Number 110000 省别编码 11 | * type Number 1 1为移动 2为电信 3为联通 12 | */ 13 | public class LoginModel{ 14 | 15 | private String ret_code; 16 | private String prov; 17 | private String city; 18 | private String name; 19 | private String num; 20 | private String provCode; 21 | private String type; 22 | 23 | public String getRet_code() { 24 | return ret_code; 25 | } 26 | 27 | public void setRet_code(String ret_code) { 28 | this.ret_code = ret_code; 29 | } 30 | 31 | public String getProv() { 32 | return prov; 33 | } 34 | 35 | public void setProv(String prov) { 36 | this.prov = prov; 37 | } 38 | 39 | public String getCity() { 40 | return city; 41 | } 42 | 43 | public void setCity(String city) { 44 | this.city = city; 45 | } 46 | 47 | public String getName() { 48 | return name; 49 | } 50 | 51 | public void setName(String name) { 52 | this.name = name; 53 | } 54 | 55 | public String getNum() { 56 | return num; 57 | } 58 | 59 | public void setNum(String num) { 60 | this.num = num; 61 | } 62 | 63 | public String getProvCode() { 64 | return provCode; 65 | } 66 | 67 | public void setProvCode(String provCode) { 68 | this.provCode = provCode; 69 | } 70 | 71 | public String getType() { 72 | return type; 73 | } 74 | 75 | public void setType(String type) { 76 | this.type = type; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/modelbean/News.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.modelbean; 2 | 3 | /** 4 | * 根据返回json类型,多级嵌套 5 | * Created by baiyuliang on 2016-7-14. 6 | */ 7 | public class News { 8 | private String title; 9 | private String picUrl; 10 | private String description; 11 | private String ctime; 12 | private String url; 13 | 14 | public String getTitle() { 15 | return title; 16 | } 17 | 18 | public void setTitle(String title) { 19 | this.title = title; 20 | } 21 | 22 | public String getPicUrl() { 23 | return picUrl; 24 | } 25 | 26 | public void setPicUrl(String picUrl) { 27 | this.picUrl = picUrl; 28 | } 29 | 30 | public String getDescription() { 31 | return description; 32 | } 33 | 34 | public void setDescription(String description) { 35 | this.description = description; 36 | } 37 | 38 | public String getCtime() { 39 | return ctime; 40 | } 41 | 42 | public void setCtime(String ctime) { 43 | this.ctime = ctime; 44 | } 45 | 46 | public String getUrl() { 47 | return url; 48 | } 49 | 50 | public void setUrl(String url) { 51 | this.url = url; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/modelbean/NewsBean.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.modelbean; 2 | 3 | /** 4 | * Created by baiyuliang on 2016-7-14. 5 | */ 6 | public class NewsBean extends BaseBean { 7 | 8 | private NewsModel showapi_res_body; 9 | 10 | public NewsModel getShowapi_res_body() { 11 | return showapi_res_body; 12 | } 13 | 14 | public void setShowapi_res_body(NewsModel showapi_res_body) { 15 | this.showapi_res_body = showapi_res_body; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/modelbean/NewsModel.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.modelbean; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 新聞 7 | * Created by baiyuliang on 2016-7-14. 8 | */ 9 | public class NewsModel { 10 | private String code; 11 | private String msg; 12 | private List newslist; 13 | 14 | public String getCode() { 15 | return code; 16 | } 17 | 18 | public void setCode(String code) { 19 | this.code = code; 20 | } 21 | 22 | public String getMsg() { 23 | return msg; 24 | } 25 | 26 | public void setMsg(String msg) { 27 | this.msg = msg; 28 | } 29 | 30 | public List getNewslist() { 31 | return newslist; 32 | } 33 | 34 | public void setNewslist(List newslist) { 35 | this.newslist = newslist; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/mvpview/ImagesMvpView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.mvpview; 2 | 3 | import com.byl.mvpdemo.model.modelbean.NewsBean; 4 | import com.byl.mvpdemo.model.mvpview.base.MvpView; 5 | 6 | /** 7 | * Created by baiyuliang on 2016-7-14. 8 | */ 9 | public interface ImagesMvpView extends MvpView { 10 | 11 | /** 12 | * 下拉刷新成功 13 | * 14 | * @param newsBean 15 | */ 16 | void refreshSuccess(NewsBean newsBean); 17 | 18 | /** 19 | * 上拉加载成功 20 | * 21 | * @param newsBean 22 | */ 23 | void loadMoreSuccess(NewsBean newsBean); 24 | 25 | /** 26 | * 失败 27 | * 28 | * @param message 29 | */ 30 | void fail(String message); 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/mvpview/LoginMvpView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.mvpview; 2 | 3 | import com.byl.mvpdemo.model.modelbean.LoginBean; 4 | import com.byl.mvpdemo.model.mvpview.base.MvpView; 5 | 6 | /** 7 | * Created by baiyuliang on 2016-7-14. 8 | */ 9 | public interface LoginMvpView extends MvpView { 10 | 11 | /** 12 | * 登录成功 13 | * @param loginBean 14 | */ 15 | void loginSuccess(LoginBean loginBean); 16 | 17 | /** 18 | * 登录失败 19 | * @param message 20 | */ 21 | void loginFail(String message); 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/mvpview/NewsMvpView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.mvpview; 2 | 3 | import com.byl.mvpdemo.model.modelbean.NewsBean; 4 | import com.byl.mvpdemo.model.mvpview.base.MvpView; 5 | 6 | /** 7 | * Created by baiyuliang on 2016-7-14. 8 | */ 9 | public interface NewsMvpView extends MvpView { 10 | 11 | /** 12 | * 下拉刷新成功 13 | * 14 | * @param newsBean 15 | */ 16 | void refreshSuccess(NewsBean newsBean); 17 | 18 | /** 19 | * 上拉加载成功 20 | * 21 | * @param newsBean 22 | */ 23 | void loadMoreSuccess(NewsBean newsBean); 24 | 25 | /** 26 | * 失败 27 | * 28 | * @param message 29 | */ 30 | void fail(String message); 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/mvpview/base/MvpView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.mvpview.base; 2 | 3 | 4 | /** 5 | * Base interface that any class that wants to act as a View in the MVP (Model View Presenter) 6 | * pattern must implement. Generally this interface will be extended by a more specific interface 7 | * that then usually will be implemented by an Activity or Fragment. 8 | */ 9 | public interface MvpView { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/presenter/ImagesPresenter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.presenter; 2 | 3 | import android.content.Context; 4 | import android.text.TextUtils; 5 | 6 | import com.byl.mvpdemo.model.modelbean.NewsBean; 7 | import com.byl.mvpdemo.model.mvpview.NewsMvpView; 8 | import com.byl.mvpdemo.presenter.base.BasePresenter; 9 | import com.byl.mvpdemo.util.LogUtil; 10 | 11 | import rx.Subscriber; 12 | import rx.Subscription; 13 | import rx.android.schedulers.AndroidSchedulers; 14 | import rx.schedulers.Schedulers; 15 | 16 | /** 17 | * Created by baiyuliang on 2016-7-14. 18 | */ 19 | public class ImagesPresenter extends BasePresenter { 20 | 21 | Subscription mSubscription; 22 | 23 | public ImagesPresenter(Context context) { 24 | this.context = context; 25 | } 26 | 27 | @Override 28 | public void attachView(NewsMvpView mvpView) { 29 | super.attachView(mvpView); 30 | } 31 | 32 | @Override 33 | public void detachView() { 34 | super.detachView(); 35 | if (mSubscription != null) mSubscription.unsubscribe(); 36 | } 37 | 38 | public void getImages(String num, String page, String rand) { 39 | checkViewAttached(); 40 | mSubscription = getApiService().girls(num, page, rand) 41 | .observeOn(AndroidSchedulers.mainThread()) 42 | .subscribeOn(Schedulers.io()) 43 | .subscribe(new Subscriber() { 44 | @Override 45 | public void onCompleted() { 46 | 47 | } 48 | 49 | @Override 50 | public void onError(Throwable e) { 51 | getMvpView().fail("获取图片失败"); 52 | LogUtil.e("获取图片失败>>" + e.getMessage()); 53 | } 54 | 55 | @Override 56 | public void onNext(NewsBean newsBean) { 57 | if (!newsBean.getShowapi_res_code().equals("0") 58 | || newsBean.getShowapi_res_body() == null 59 | || TextUtils.isEmpty(newsBean.getShowapi_res_body().getCode()) 60 | || !newsBean.getShowapi_res_body().getCode().equals("200")) { 61 | getMvpView().fail("获取图片失败"); 62 | } else { 63 | if (page.equals("1")) {//刷新 64 | if (newsBean.getShowapi_res_body().getNewslist() == null 65 | || newsBean.getShowapi_res_body().getNewslist().size() <= 0) { 66 | getMvpView().fail("当前无图片"); 67 | } else { 68 | getMvpView().refreshSuccess(newsBean); 69 | } 70 | } else {//加载更多 71 | if (newsBean.getShowapi_res_body().getNewslist() == null 72 | || newsBean.getShowapi_res_body().getNewslist().size() <= 0) { 73 | getMvpView().fail("没有更多数据啦"); 74 | } else { 75 | getMvpView().loadMoreSuccess(newsBean); 76 | } 77 | } 78 | 79 | } 80 | } 81 | }); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/presenter/LoginPresenter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.presenter; 2 | 3 | import android.content.Context; 4 | import android.text.TextUtils; 5 | 6 | import com.byl.mvpdemo.api.ApiService; 7 | import com.byl.mvpdemo.model.modelbean.LoginBean; 8 | import com.byl.mvpdemo.model.mvpview.LoginMvpView; 9 | import com.byl.mvpdemo.presenter.base.BasePresenter; 10 | import com.byl.mvpdemo.util.LogUtil; 11 | import com.byl.mvpdemo.view.MyProgressDialog; 12 | 13 | import rx.Subscriber; 14 | import rx.Subscription; 15 | import rx.android.schedulers.AndroidSchedulers; 16 | import rx.schedulers.Schedulers; 17 | 18 | /** 19 | * Created by baiyuliang on 2016-7-14. 20 | */ 21 | public class LoginPresenter extends BasePresenter { 22 | 23 | Subscription mSubscription; 24 | 25 | public LoginPresenter(Context context) { 26 | this.context = context; 27 | } 28 | 29 | @Override 30 | public void attachView(LoginMvpView mvpView) { 31 | super.attachView(mvpView); 32 | } 33 | 34 | @Override 35 | public void detachView() { 36 | super.detachView(); 37 | if (mSubscription != null) mSubscription.unsubscribe(); 38 | } 39 | 40 | public void login(String account) { 41 | checkViewAttached(); 42 | showProgressDialog(); 43 | mSubscription = getApiService().login(account) 44 | .observeOn(AndroidSchedulers.mainThread()) 45 | .subscribeOn(Schedulers.io()) 46 | .subscribe(new Subscriber() { 47 | @Override 48 | public void onCompleted() { 49 | 50 | } 51 | 52 | @Override 53 | public void onError(Throwable e) { 54 | dissmissProgressDialog(); 55 | getMvpView().loginFail("登录失败"); 56 | LogUtil.e("登录失败>>" + e.getMessage()); 57 | } 58 | 59 | @Override 60 | public void onNext(LoginBean loginBean) { 61 | dissmissProgressDialog(); 62 | if (!loginBean.getShowapi_res_code().equals("0") 63 | || loginBean.getShowapi_res_body() == null 64 | || TextUtils.isEmpty(loginBean.getShowapi_res_body().getRet_code()) 65 | || !loginBean.getShowapi_res_body().getRet_code().equals("0")) { 66 | getMvpView().loginFail("请检查您输入的手机号码是否正确"); 67 | } else { 68 | getMvpView().loginSuccess(loginBean); 69 | } 70 | } 71 | }); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/presenter/NewsPresenter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.presenter; 2 | 3 | import android.content.Context; 4 | import android.text.TextUtils; 5 | import android.util.Log; 6 | 7 | import com.byl.mvpdemo.model.modelbean.NewsBean; 8 | import com.byl.mvpdemo.model.mvpview.NewsMvpView; 9 | import com.byl.mvpdemo.presenter.base.BasePresenter; 10 | import com.byl.mvpdemo.util.LogUtil; 11 | 12 | import rx.Subscriber; 13 | import rx.Subscription; 14 | import rx.android.schedulers.AndroidSchedulers; 15 | import rx.schedulers.Schedulers; 16 | 17 | /** 18 | * Created by baiyuliang on 2016-7-14. 19 | */ 20 | public class NewsPresenter extends BasePresenter { 21 | 22 | boolean isFirstReq = true; 23 | Subscription mSubscription; 24 | 25 | public NewsPresenter(Context context) { 26 | this.context = context; 27 | } 28 | 29 | @Override 30 | public void attachView(NewsMvpView mvpView) { 31 | super.attachView(mvpView); 32 | } 33 | 34 | @Override 35 | public void detachView() { 36 | super.detachView(); 37 | if (mSubscription != null) mSubscription.unsubscribe(); 38 | } 39 | 40 | public void getNews(String num, String page) { 41 | checkViewAttached(); 42 | if (isFirstReq) {//只在第一次请求时显示dialog 43 | showProgressDialog(); 44 | isFirstReq = false; 45 | } 46 | mSubscription = getApiService().news(num, page) 47 | .observeOn(AndroidSchedulers.mainThread()) 48 | .subscribeOn(Schedulers.io()) 49 | .subscribe(new Subscriber() { 50 | @Override 51 | public void onCompleted() { 52 | 53 | } 54 | 55 | @Override 56 | public void onError(Throwable e) { 57 | dissmissProgressDialog(); 58 | getMvpView().fail("获取新闻失败"); 59 | LogUtil.e("获取新闻失败>>" + e.getMessage()); 60 | } 61 | 62 | @Override 63 | public void onNext(NewsBean newsBean) { 64 | dissmissProgressDialog(); 65 | if (!newsBean.getShowapi_res_code().equals("0") 66 | || newsBean.getShowapi_res_body() == null 67 | || TextUtils.isEmpty(newsBean.getShowapi_res_body().getCode()) 68 | || !newsBean.getShowapi_res_body().getCode().equals("200")) { 69 | getMvpView().fail("获取新闻失败"); 70 | } else { 71 | if (page.equals("1")) {//刷新 72 | if (newsBean.getShowapi_res_body().getNewslist() == null 73 | || newsBean.getShowapi_res_body().getNewslist().size() <= 0) { 74 | getMvpView().fail("当前无新闻"); 75 | } else { 76 | getMvpView().refreshSuccess(newsBean); 77 | } 78 | } else {//加载更多 79 | if (newsBean.getShowapi_res_body().getNewslist() == null 80 | || newsBean.getShowapi_res_body().getNewslist().size() <= 0) { 81 | getMvpView().fail("没有更多数据啦"); 82 | } else { 83 | getMvpView().loadMoreSuccess(newsBean); 84 | } 85 | } 86 | 87 | } 88 | } 89 | }); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/presenter/base/BasePresenter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.presenter.base; 2 | 3 | import android.content.Context; 4 | 5 | import com.byl.mvpdemo.api.ApiService; 6 | import com.byl.mvpdemo.api.ApiUtil; 7 | import com.byl.mvpdemo.model.mvpview.base.MvpView; 8 | import com.byl.mvpdemo.view.MyProgressDialog; 9 | 10 | /** 11 | * Base class that implements the Presenter interface and provides a base implementation for 12 | * attachView() and detachView(). It also handles keeping a reference to the mvpView that 13 | * can be accessed from the children classes by calling getMvpView(). 14 | */ 15 | public class BasePresenter implements Presenter { 16 | 17 | public Context context; 18 | private T mMvpView; 19 | private ApiService apiService; 20 | private MyProgressDialog myProgressDialog; 21 | 22 | 23 | @Override 24 | public void attachView(T mvpView) { 25 | mMvpView = mvpView; 26 | apiService = ApiUtil.createApiService(); 27 | } 28 | 29 | @Override 30 | public void detachView() { 31 | mMvpView = null; 32 | } 33 | 34 | public boolean isViewAttached() { 35 | return mMvpView != null; 36 | } 37 | 38 | public T getMvpView() { 39 | return mMvpView; 40 | } 41 | 42 | public ApiService getApiService() { 43 | return apiService; 44 | } 45 | 46 | public void showProgressDialog() { 47 | if (context != null) { 48 | if (myProgressDialog == null) { 49 | myProgressDialog = new MyProgressDialog(context); 50 | } 51 | myProgressDialog.show(); 52 | } 53 | } 54 | 55 | public void dissmissProgressDialog() { 56 | if (myProgressDialog != null) { 57 | myProgressDialog.dismiss(); 58 | } 59 | } 60 | 61 | public void checkViewAttached() { 62 | if (!isViewAttached()) throw new MvpViewNotAttachedException(); 63 | } 64 | 65 | public static class MvpViewNotAttachedException extends RuntimeException { 66 | public MvpViewNotAttachedException() { 67 | super("使用Presenter前,请先调用attachView"); 68 | } 69 | } 70 | } 71 | 72 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/presenter/base/Presenter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.presenter.base; 2 | 3 | import com.byl.mvpdemo.model.mvpview.base.MvpView; 4 | 5 | /** 6 | * Every presenter in the app must either implement this interface or extend BasePresenter 7 | * indicating the MvpView type that wants to be attached with. 8 | */ 9 | public interface Presenter { 10 | 11 | void attachView(V mvpView); 12 | 13 | void detachView(); 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/base/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.base; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.support.v4.app.FragmentActivity; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.text.TextUtils; 10 | import android.view.View; 11 | import android.widget.ImageView; 12 | import android.widget.ProgressBar; 13 | import android.widget.RelativeLayout; 14 | import android.widget.TextView; 15 | 16 | import com.byl.mvpdemo.R; 17 | import com.byl.mvpdemo.api.ApiService; 18 | import com.byl.mvpdemo.api.ApiUtil; 19 | 20 | /** 21 | * Created by baiyuliang on 2016-7-14. 22 | */ 23 | public abstract class BaseActivity extends FragmentActivity implements View.OnClickListener { 24 | 25 | public Activity context; 26 | 27 | public RelativeLayout title_bar; 28 | public TextView tv_left, tv_title, tv_right; 29 | public ImageView iv_right; 30 | public ProgressBar pb; 31 | 32 | @Override 33 | protected void onCreate(Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | setContentView(getContentView()); 36 | context = this; 37 | initView(); 38 | initClick(); 39 | initData(); 40 | } 41 | 42 | /** 43 | * 初始化titlebar,该方法只有在标题栏布局符合此规则时才能调用 44 | * 45 | * @param left titlebar左按钮 46 | * @param title titlebar标题 47 | * @param right titlebar 右按钮 48 | * @param res titlebar 右图片按钮 49 | * @param onClickListener 左右按钮点击事件 50 | */ 51 | public void initTitleBar(String left, String title, String right, int res, View.OnClickListener onClickListener) { 52 | title_bar = (RelativeLayout) $(R.id.title_bar); 53 | title_bar.setBackgroundColor(getResources().getColor(R.color.common_title_bg)); 54 | tv_left = (TextView) $(R.id.tv_left);//返回按钮 55 | tv_title = (TextView) $(R.id.tv_title);//标题 56 | tv_right = (TextView) $(R.id.tv_right);//(右侧)按钮 57 | iv_right = (ImageView) $(R.id.iv_right);//右侧图片按钮 58 | 59 | pb = (ProgressBar) $(R.id.pb);// 标题栏数据加载ProgressBar 60 | 61 | if (!TextUtils.isEmpty(left)) { 62 | tv_left.setText(left); 63 | tv_left.setVisibility(View.VISIBLE); 64 | tv_left.setOnClickListener(onClickListener); 65 | } else { 66 | tv_left.setVisibility(View.GONE); 67 | } 68 | 69 | if (!TextUtils.isEmpty(title)) { 70 | tv_title.setText(title); 71 | tv_title.setVisibility(View.VISIBLE); 72 | } else { 73 | tv_title.setVisibility(View.GONE); 74 | } 75 | 76 | if (!TextUtils.isEmpty(right)) { 77 | tv_right.setText(right); 78 | tv_right.setVisibility(View.VISIBLE); 79 | tv_right.setOnClickListener(onClickListener); 80 | } else { 81 | tv_right.setVisibility(View.GONE); 82 | } 83 | 84 | if (res != 0) { 85 | iv_right.setImageResource(res); 86 | iv_right.setVisibility(View.VISIBLE); 87 | iv_right.setOnClickListener(onClickListener); 88 | } else { 89 | iv_right.setVisibility(View.GONE); 90 | } 91 | 92 | } 93 | 94 | /** 95 | * 设置布局文件 96 | * 97 | * @return 98 | */ 99 | public abstract int getContentView(); 100 | 101 | /** 102 | * 初始化View 103 | */ 104 | public abstract void initView(); 105 | 106 | /** 107 | * 设置点击事件 108 | */ 109 | public abstract void initClick(); 110 | 111 | /** 112 | * 初始化数据 113 | */ 114 | public abstract void initData(); 115 | 116 | public View $(int id) { 117 | return findViewById(id); 118 | } 119 | 120 | @Override 121 | public void onClick(View v) { 122 | switch (v.getId()) { 123 | case R.id.tv_left: 124 | finish(); 125 | } 126 | } 127 | 128 | public void startActivity(Class cla) { 129 | startActivity(new Intent(this, cla)); 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/base/BaseFragment.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.base; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.text.TextUtils; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.ImageView; 12 | import android.widget.ProgressBar; 13 | import android.widget.RelativeLayout; 14 | import android.widget.TextView; 15 | 16 | import com.byl.mvpdemo.R; 17 | 18 | /** 19 | * Created by baiyuliang on 2016-7-14. 20 | */ 21 | public abstract class BaseFragment extends Fragment implements View.OnClickListener { 22 | 23 | public Activity context; 24 | public View view; 25 | 26 | public RelativeLayout title_bar; 27 | public TextView tv_left, tv_title, tv_right; 28 | public ImageView iv_right; 29 | public ProgressBar pb; 30 | 31 | @Override 32 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 33 | context = getActivity(); 34 | if (view == null) { 35 | view = inflater.inflate(getContentView(), null); 36 | initView(); 37 | initClick(); 38 | initData(); 39 | } 40 | return view; 41 | } 42 | 43 | /** 44 | * 初始化titlebar,该方法只有在标题栏布局符合此规则时才能调用 45 | * 46 | * @param left titlebar左按钮 47 | * @param title titlebar标题 48 | * @param right titlebar 右按钮 49 | * @param res titlebar 右图片按钮 50 | * @param onClickListener 左右按钮点击事件 51 | */ 52 | public void initTitleBar(String left, String title, String right, int res, View.OnClickListener onClickListener) { 53 | title_bar = (RelativeLayout) $(R.id.title_bar); 54 | title_bar.setBackgroundColor(getResources().getColor(R.color.common_title_bg)); 55 | tv_left = (TextView) $(R.id.tv_left);//返回按钮 56 | tv_title = (TextView) $(R.id.tv_title);//标题 57 | tv_right = (TextView) $(R.id.tv_right);//(右侧)按钮 58 | iv_right = (ImageView) $(R.id.iv_right);//右侧图片按钮 59 | 60 | pb = (ProgressBar) $(R.id.pb);// 标题栏数据加载ProgressBar 61 | 62 | if (!TextUtils.isEmpty(left)) { 63 | tv_left.setText(left); 64 | tv_left.setVisibility(View.VISIBLE); 65 | tv_left.setOnClickListener(onClickListener); 66 | } else { 67 | tv_left.setVisibility(View.GONE); 68 | } 69 | 70 | if (!TextUtils.isEmpty(title)) { 71 | tv_title.setText(title); 72 | tv_title.setVisibility(View.VISIBLE); 73 | } else { 74 | tv_title.setVisibility(View.GONE); 75 | } 76 | 77 | if (!TextUtils.isEmpty(right)) { 78 | tv_right.setText(right); 79 | tv_right.setVisibility(View.VISIBLE); 80 | tv_right.setOnClickListener(onClickListener); 81 | } else { 82 | tv_right.setVisibility(View.GONE); 83 | } 84 | 85 | if (res != 0) { 86 | iv_right.setImageResource(res); 87 | iv_right.setVisibility(View.VISIBLE); 88 | iv_right.setOnClickListener(onClickListener); 89 | } else { 90 | iv_right.setVisibility(View.GONE); 91 | } 92 | 93 | } 94 | 95 | /** 96 | * 设置布局文件 97 | * 98 | * @return 99 | */ 100 | public abstract int getContentView(); 101 | 102 | /** 103 | * 初始化View 104 | */ 105 | public abstract void initView(); 106 | 107 | /** 108 | * 设置点击事件 109 | */ 110 | public abstract void initClick(); 111 | 112 | /** 113 | * 初始化数据 114 | */ 115 | public abstract void initData(); 116 | 117 | public View $(int id) { 118 | return view.findViewById(id); 119 | } 120 | 121 | 122 | } 123 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/images/FragmentImageTab1.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.images; 2 | 3 | import android.support.v7.widget.GridLayoutManager; 4 | import android.view.View; 5 | import android.widget.Toast; 6 | 7 | import com.byl.mvpdemo.R; 8 | import com.byl.mvpdemo.adapter.BaseAdapter; 9 | import com.byl.mvpdemo.adapter.ImagesAdapter; 10 | import com.byl.mvpdemo.model.modelbean.News; 11 | import com.byl.mvpdemo.model.modelbean.NewsBean; 12 | import com.byl.mvpdemo.model.mvpview.NewsMvpView; 13 | import com.byl.mvpdemo.presenter.ImagesPresenter; 14 | import com.byl.mvpdemo.ui.base.BaseFragment; 15 | import com.byl.mvpdemo.view.pullrecyclerview.PullBaseView; 16 | import com.byl.mvpdemo.view.pullrecyclerview.PullRecyclerView; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | 22 | /** 23 | * 24 | */ 25 | public class FragmentImageTab1 extends BaseFragment implements NewsMvpView, 26 | PullBaseView.OnHeaderRefreshListener, 27 | PullBaseView.OnFooterRefreshListener, 28 | BaseAdapter.OnItemClickListener, 29 | BaseAdapter.OnViewClickListener { 30 | 31 | PullRecyclerView mPullRecyclerView; 32 | ImagesAdapter imagesAdapter; 33 | List objectList; 34 | 35 | ImagesPresenter imagesPresenter; 36 | int page; 37 | 38 | @Override 39 | public int getContentView() { 40 | return R.layout.fragment_images_tab1; 41 | } 42 | 43 | @Override 44 | public void initView() { 45 | mPullRecyclerView = (PullRecyclerView) $(R.id.mPullRecyclerView); 46 | mPullRecyclerView.setOnHeaderRefreshListener(this);//设置下拉监听 47 | mPullRecyclerView.setOnFooterRefreshListener(this);//设置上拉监听 48 | mPullRecyclerView.setCanScrollAtRereshing(false);//设置正在刷新时是否可以滑动,默认不可滑动 49 | mPullRecyclerView.setCanPullDown(true);//设置是否可下拉 50 | mPullRecyclerView.setCanPullUp(true);//设置是否可上拉 51 | } 52 | 53 | @Override 54 | public void initClick() { 55 | 56 | } 57 | 58 | @Override 59 | public void initData() { 60 | objectList = new ArrayList<>(); 61 | imagesPresenter = new ImagesPresenter(context); 62 | imagesPresenter.attachView(this); 63 | imagesPresenter.getImages("20", String.valueOf(++page), "0"); 64 | } 65 | 66 | @Override 67 | public void onClick(View v) { 68 | 69 | } 70 | 71 | 72 | @Override 73 | public void onFooterRefresh(PullBaseView view) { 74 | imagesPresenter.getImages("20", String.valueOf(++page), "0"); 75 | } 76 | 77 | @Override 78 | public void onHeaderRefresh(PullBaseView view) { 79 | page = 0; 80 | imagesPresenter.getImages("20", String.valueOf(++page), "0"); 81 | } 82 | 83 | @Override 84 | public void refreshSuccess(NewsBean newsBean) { 85 | mPullRecyclerView.onHeaderRefreshComplete(); 86 | objectList.clear(); 87 | List list = newsBean.getShowapi_res_body().getNewslist(); 88 | for (News news : list) { 89 | objectList.add(news); 90 | } 91 | imagesAdapter = new ImagesAdapter(context, objectList, this); 92 | mPullRecyclerView.setLayoutManager(new GridLayoutManager(context, 2)); 93 | imagesAdapter.setOnItemClickListener(this); 94 | mPullRecyclerView.setAdapter(imagesAdapter); 95 | } 96 | 97 | @Override 98 | public void loadMoreSuccess(NewsBean newsBean) { 99 | mPullRecyclerView.onFooterRefreshComplete(); 100 | List list = newsBean.getShowapi_res_body().getNewslist(); 101 | for (News news : list) { 102 | objectList.add(news); 103 | } 104 | imagesAdapter.notifyDataSetChanged(); 105 | } 106 | 107 | @Override 108 | public void fail(String message) { 109 | Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); 110 | } 111 | 112 | @Override 113 | public void onItemClick(int position) { 114 | Toast.makeText(context, "item>>" + position, Toast.LENGTH_SHORT).show(); 115 | } 116 | 117 | @Override 118 | public void onViewClick(int position, int viewtype) { 119 | switch (viewtype) { 120 | case 1: 121 | Toast.makeText(context, "赞>>" + position, Toast.LENGTH_SHORT).show(); 122 | break; 123 | } 124 | } 125 | 126 | @Override 127 | public void onDestroy() { 128 | super.onDestroy(); 129 | imagesPresenter.detachView(); 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/images/FragmentImageTab2.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.images; 2 | 3 | import android.support.v7.widget.GridLayoutManager; 4 | import android.view.View; 5 | import android.widget.Toast; 6 | 7 | import com.byl.mvpdemo.R; 8 | import com.byl.mvpdemo.adapter.BaseAdapter; 9 | import com.byl.mvpdemo.adapter.ImagesAdapter; 10 | import com.byl.mvpdemo.model.modelbean.News; 11 | import com.byl.mvpdemo.model.modelbean.NewsBean; 12 | import com.byl.mvpdemo.model.mvpview.NewsMvpView; 13 | import com.byl.mvpdemo.presenter.ImagesPresenter; 14 | import com.byl.mvpdemo.ui.base.BaseFragment; 15 | import com.byl.mvpdemo.view.pullrecyclerview.PullBaseView; 16 | import com.byl.mvpdemo.view.pullrecyclerview.PullRecyclerView; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | 22 | /** 23 | * 24 | */ 25 | public class FragmentImageTab2 extends BaseFragment implements NewsMvpView, 26 | PullBaseView.OnHeaderRefreshListener, 27 | PullBaseView.OnFooterRefreshListener, 28 | BaseAdapter.OnItemClickListener, 29 | BaseAdapter.OnViewClickListener { 30 | 31 | PullRecyclerView mPullRecyclerView; 32 | ImagesAdapter imagesAdapter; 33 | List objectList; 34 | 35 | ImagesPresenter imagesPresenter; 36 | int page; 37 | 38 | @Override 39 | public int getContentView() { 40 | return R.layout.fragment_images_tab2; 41 | } 42 | 43 | @Override 44 | public void initView() { 45 | mPullRecyclerView = (PullRecyclerView) $(R.id.mPullRecyclerView); 46 | mPullRecyclerView.setOnHeaderRefreshListener(this);//设置下拉监听 47 | mPullRecyclerView.setOnFooterRefreshListener(this);//设置上拉监听 48 | mPullRecyclerView.setCanScrollAtRereshing(false);//设置正在刷新时是否可以滑动,默认不可滑动 49 | mPullRecyclerView.setCanPullDown(true);//设置是否可下拉 50 | mPullRecyclerView.setCanPullUp(true);//设置是否可上拉 51 | } 52 | 53 | @Override 54 | public void initClick() { 55 | 56 | } 57 | 58 | @Override 59 | public void initData() { 60 | objectList = new ArrayList<>(); 61 | imagesPresenter = new ImagesPresenter(context); 62 | imagesPresenter.attachView(this); 63 | imagesPresenter.getImages("20", String.valueOf(++page), "1"); 64 | } 65 | 66 | @Override 67 | public void onClick(View v) { 68 | 69 | } 70 | 71 | 72 | @Override 73 | public void onFooterRefresh(PullBaseView view) { 74 | imagesPresenter.getImages("20", String.valueOf(++page), "1"); 75 | } 76 | 77 | @Override 78 | public void onHeaderRefresh(PullBaseView view) { 79 | page = 0; 80 | imagesPresenter.getImages("20", String.valueOf(++page), "1"); 81 | } 82 | 83 | @Override 84 | public void refreshSuccess(NewsBean newsBean) { 85 | mPullRecyclerView.onHeaderRefreshComplete(); 86 | objectList.clear(); 87 | List list = newsBean.getShowapi_res_body().getNewslist(); 88 | for (News news : list) { 89 | objectList.add(news); 90 | } 91 | imagesAdapter = new ImagesAdapter(context, objectList, this); 92 | mPullRecyclerView.setLayoutManager(new GridLayoutManager(context, 2)); 93 | imagesAdapter.setOnItemClickListener(this); 94 | mPullRecyclerView.setAdapter(imagesAdapter); 95 | } 96 | 97 | @Override 98 | public void loadMoreSuccess(NewsBean newsBean) { 99 | mPullRecyclerView.onFooterRefreshComplete(); 100 | List list = newsBean.getShowapi_res_body().getNewslist(); 101 | for (News news : list) { 102 | objectList.add(news); 103 | } 104 | imagesAdapter.notifyDataSetChanged(); 105 | } 106 | 107 | @Override 108 | public void fail(String message) { 109 | Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); 110 | } 111 | 112 | @Override 113 | public void onItemClick(int position) { 114 | Toast.makeText(context, "item>>" + position, Toast.LENGTH_SHORT).show(); 115 | } 116 | 117 | @Override 118 | public void onViewClick(int position, int viewtype) { 119 | switch (viewtype) { 120 | case 1: 121 | Toast.makeText(context, "赞>>" + position, Toast.LENGTH_SHORT).show(); 122 | break; 123 | } 124 | } 125 | 126 | @Override 127 | public void onDestroy() { 128 | super.onDestroy(); 129 | imagesPresenter.detachView(); 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/login/LoginActivity.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.login; 2 | 3 | import android.text.TextUtils; 4 | import android.view.View; 5 | import android.widget.Button; 6 | import android.widget.EditText; 7 | import android.widget.Toast; 8 | 9 | import com.byl.mvpdemo.R; 10 | import com.byl.mvpdemo.model.modelbean.LoginBean; 11 | import com.byl.mvpdemo.model.mvpview.LoginMvpView; 12 | import com.byl.mvpdemo.presenter.LoginPresenter; 13 | import com.byl.mvpdemo.ui.base.BaseActivity; 14 | import com.byl.mvpdemo.ui.main.MainActivity; 15 | 16 | public class LoginActivity extends BaseActivity implements LoginMvpView { 17 | 18 | EditText et_account, et_pwd; 19 | Button btn_login; 20 | LoginPresenter loginPresenter; 21 | 22 | @Override 23 | public int getContentView() { 24 | return R.layout.activity_login; 25 | } 26 | 27 | @Override 28 | public void initView() { 29 | initTitleBar("", "登录", "注册", 0, this); 30 | title_bar.setBackgroundColor(getResources().getColor(R.color.common_title_bg)); 31 | et_account = (EditText) $(R.id.account); 32 | et_pwd = (EditText) $(R.id.password); 33 | btn_login = (Button) $(R.id.login); 34 | } 35 | 36 | @Override 37 | public void initClick() { 38 | btn_login.setOnClickListener(this); 39 | } 40 | 41 | @Override 42 | public void initData() { 43 | loginPresenter = new LoginPresenter(this); 44 | loginPresenter.attachView(this); 45 | } 46 | 47 | @Override 48 | public void onClick(View v) { 49 | super.onClick(v); 50 | switch (v.getId()) { 51 | case R.id.tv_right: 52 | Toast.makeText(LoginActivity.this, "注册", Toast.LENGTH_SHORT).show(); 53 | break; 54 | case R.id.login: 55 | doLogin(); 56 | break; 57 | } 58 | } 59 | 60 | /** 61 | * 登录 62 | */ 63 | void doLogin() { 64 | String account = et_account.getText().toString(); 65 | if (TextUtils.isEmpty(account)) { 66 | Toast.makeText(LoginActivity.this, "请输入您的手机号", Toast.LENGTH_SHORT).show(); 67 | return; 68 | } 69 | String pwd = et_pwd.getText().toString(); 70 | if (TextUtils.isEmpty(pwd)) { 71 | Toast.makeText(LoginActivity.this, "请输入您的密码", Toast.LENGTH_SHORT).show(); 72 | return; 73 | } 74 | loginPresenter.login(account); 75 | } 76 | 77 | @Override 78 | public void loginSuccess(LoginBean loginBean) { 79 | startActivity(MainActivity.class); 80 | finish(); 81 | Toast.makeText(LoginActivity.this, "登录成功", Toast.LENGTH_SHORT).show(); 82 | } 83 | 84 | @Override 85 | public void loginFail(String message) { 86 | Toast.makeText(LoginActivity.this, message, Toast.LENGTH_SHORT).show(); 87 | } 88 | 89 | @Override 90 | protected void onDestroy() { 91 | super.onDestroy(); 92 | loginPresenter.detachView(); 93 | } 94 | } 95 | 96 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/main/FragmentTab1.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.main; 2 | 3 | import android.support.v7.widget.LinearLayoutManager; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.util.Log; 6 | import android.view.View; 7 | import android.widget.ImageView; 8 | import android.widget.RelativeLayout; 9 | import android.widget.TextView; 10 | import android.widget.Toast; 11 | 12 | import com.byl.mvpdemo.R; 13 | import com.byl.mvpdemo.adapter.BaseAdapter; 14 | import com.byl.mvpdemo.adapter.NewsAdapter; 15 | import com.byl.mvpdemo.model.modelbean.ImageModel; 16 | import com.byl.mvpdemo.model.modelbean.News; 17 | import com.byl.mvpdemo.model.modelbean.NewsBean; 18 | import com.byl.mvpdemo.model.mvpview.NewsMvpView; 19 | import com.byl.mvpdemo.presenter.NewsPresenter; 20 | import com.byl.mvpdemo.ui.base.BaseFragment; 21 | import com.byl.mvpdemo.util.SysUtil; 22 | import com.byl.mvpdemo.view.pullrecyclerview.PullBaseView; 23 | import com.byl.mvpdemo.view.pullrecyclerview.PullRecyclerView; 24 | 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | 29 | public class FragmentTab1 extends BaseFragment implements 30 | BaseAdapter.OnItemClickListener, 31 | PullBaseView.OnHeaderRefreshListener, 32 | PullBaseView.OnFooterRefreshListener, 33 | PullBaseView.OnPullDownScrollListener, 34 | View.OnClickListener, 35 | BaseAdapter.OnViewClickListener, 36 | NewsMvpView { 37 | 38 | RelativeLayout rl_title; 39 | TextView tv_search; 40 | ImageView iv_qr;//二维码 41 | PullRecyclerView mRecyclerView; 42 | NewsAdapter newsAdapter; 43 | List listbanner, listnews; 44 | 45 | int y, //滑动距离 46 | bannerH;//banner高度 47 | boolean isPullDown = false;//是否是下拉状态 48 | 49 | NewsPresenter newsPresenter; 50 | int page; 51 | 52 | @Override 53 | public int getContentView() { 54 | return R.layout.fragment_1; 55 | } 56 | 57 | /** 58 | * 注意:rl_title.getBackground().setAlpha(0),设置标题栏背景透明度,会影响其它界面的背景, 59 | * 如果加上这个效果,那么其他界面的背景色在xml中设置将失效,需代码中动态设置, 60 | * 这个问题很奇葩,未找到原因, 61 | * 现在要么不要这个滑动改变透明度的效果,要么其他界面中的背景色就动态设置 62 | */ 63 | @Override 64 | public void initView() { 65 | rl_title = (RelativeLayout) $(R.id.rl_title);//标题栏 66 | rl_title.getBackground().setAlpha(0); 67 | tv_search = (TextView) $(R.id.tv_search); 68 | iv_qr = (ImageView) $(R.id.iv_qr); 69 | 70 | mRecyclerView = (PullRecyclerView) $(R.id.mRecyclerView); 71 | mRecyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER); 72 | mRecyclerView.setOnHeaderRefreshListener(this);//设置下拉监听 73 | mRecyclerView.setOnFooterRefreshListener(this);//设置上拉监听 74 | mRecyclerView.setOnPullDownScrollListener(this);//设置下拉滑动监听 75 | mRecyclerView.setCanScrollAtRereshing(false);//设置正在刷新时是否可以滑动,默认不可滑动 76 | mRecyclerView.setCanPullDown(true);//设置是否可下拉 77 | mRecyclerView.setCanPullUp(true);//设置是否可上拉 78 | mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { 79 | @Override 80 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 81 | super.onScrollStateChanged(recyclerView, newState); 82 | } 83 | 84 | @Override 85 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) {//监听滑动距离以改变标题栏透明度 86 | super.onScrolled(recyclerView, dx, dy); 87 | y += dy; 88 | if (y >= bannerH) { 89 | rl_title.getBackground().setAlpha(255); 90 | rl_title.setVisibility(View.VISIBLE); 91 | } else if (y >= 0 && y < bannerH) { 92 | if (isPullDown) { 93 | rl_title.setVisibility(View.GONE); 94 | } else { 95 | rl_title.getBackground().setAlpha((int) (255 * ((double) y / bannerH))); 96 | rl_title.setVisibility(View.VISIBLE); 97 | } 98 | } else { 99 | rl_title.getBackground().setAlpha(0); 100 | rl_title.setVisibility(View.GONE); 101 | } 102 | } 103 | }); 104 | } 105 | 106 | @Override 107 | public void initClick() { 108 | tv_search.setOnClickListener(this); 109 | iv_qr.setOnClickListener(this); 110 | } 111 | 112 | @Override 113 | public void initData() { 114 | bannerH = SysUtil.dip2px(context, 200);//将banner高度转为px 115 | listbanner = new ArrayList<>(); 116 | listnews = new ArrayList<>(); 117 | 118 | newsPresenter = new NewsPresenter(context); 119 | newsPresenter.attachView(this); 120 | newsPresenter.getNews("10", String.valueOf(++page)); 121 | 122 | initRecyclerView(); 123 | } 124 | 125 | void initRecyclerView() { 126 | newsAdapter = new NewsAdapter(context, listbanner, listnews, this); 127 | mRecyclerView.setLayoutManager(new LinearLayoutManager(context)); 128 | newsAdapter.setOnItemClickListener(this); 129 | mRecyclerView.setAdapter(newsAdapter); 130 | } 131 | 132 | @Override 133 | public void onClick(View v) { 134 | switch (v.getId()) { 135 | case R.id.tv_search: 136 | Toast.makeText(context, "搜索", Toast.LENGTH_SHORT).show(); 137 | break; 138 | case R.id.iv_qr: 139 | Toast.makeText(context, "二维码", Toast.LENGTH_SHORT).show(); 140 | break; 141 | } 142 | } 143 | 144 | /** 145 | * 上拉加载 146 | * 147 | * @param view 148 | */ 149 | @Override 150 | public void onFooterRefresh(PullBaseView view) { 151 | newsPresenter.getNews("10", String.valueOf(++page)); 152 | } 153 | 154 | /** 155 | * 下拉刷新 156 | * 157 | * @param view 158 | */ 159 | @Override 160 | public void onHeaderRefresh(PullBaseView view) { 161 | page = 0; 162 | newsPresenter.getNews("10", String.valueOf(++page)); 163 | } 164 | 165 | @Override 166 | public void onPullDownScrolled() { 167 | isPullDown = true; 168 | rl_title.setVisibility(View.GONE); 169 | } 170 | 171 | @Override 172 | public void onPullDownFinished() { 173 | isPullDown = false; 174 | rl_title.setVisibility(View.VISIBLE); 175 | } 176 | 177 | 178 | /** 179 | * item点击监听 180 | * 181 | * @param position 182 | */ 183 | @Override 184 | public void onItemClick(int position) { 185 | Toast.makeText(context, ((News) listnews.get(position)).getTitle(), Toast.LENGTH_SHORT).show(); 186 | } 187 | 188 | /** 189 | * @param position item position 190 | * @param viewtype 点击的view的类型,调用时根据不同的view传入不同的值加以区分 191 | */ 192 | @Override 193 | public void onViewClick(int position, int viewtype) { 194 | switch (viewtype) { 195 | case 1: 196 | Toast.makeText(context, "新闻1", Toast.LENGTH_SHORT).show(); 197 | break; 198 | case 2: 199 | Toast.makeText(context, "新闻2", Toast.LENGTH_SHORT).show(); 200 | break; 201 | case 3: 202 | Toast.makeText(context, "新闻3", Toast.LENGTH_SHORT).show(); 203 | break; 204 | case 4: 205 | Toast.makeText(context, "新闻4", Toast.LENGTH_SHORT).show(); 206 | break; 207 | } 208 | 209 | } 210 | 211 | /** 212 | * 下拉请求成功 213 | * 214 | * @param newsBean 215 | */ 216 | @Override 217 | public void refreshSuccess(NewsBean newsBean) { 218 | mRecyclerView.onHeaderRefreshComplete(); 219 | //banner 模拟数据 220 | listbanner.clear(); 221 | ImageModel imageModel = new ImageModel(); 222 | imageModel.setUrl("https://ss2.baidu.com/-vo3dSag_xI4khGko9WTAnF6hhy/image/h%3D200/sign=650d5402a318972bbc3a07cad6cd7b9d/9f2f070828381f305c3fe5bfa1014c086e06f086.jpg"); 223 | listbanner.add(imageModel); 224 | imageModel = new ImageModel(); 225 | imageModel.setUrl("https://ss0.baidu.com/7Po3dSag_xI4khGko9WTAnF6hhy/image/h%3D200/sign=a219dde79125bc31345d06986ede8de7/a5c27d1ed21b0ef494399077d5c451da80cb3ec1.jpg"); 226 | listbanner.add(imageModel); 227 | imageModel = new ImageModel(); 228 | imageModel.setUrl("https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2040796625,1810502195&fm=111&gp=0.jpg"); 229 | listbanner.add(imageModel); 230 | //news 真实数据 231 | listnews.clear(); 232 | List list = newsBean.getShowapi_res_body().getNewslist(); 233 | for (News news : list) { 234 | listnews.add(news); 235 | } 236 | initRecyclerView(); 237 | } 238 | 239 | @Override 240 | public void loadMoreSuccess(NewsBean newsBean) { 241 | mRecyclerView.onFooterRefreshComplete(); 242 | List list = newsBean.getShowapi_res_body().getNewslist(); 243 | for (News news : list) { 244 | listnews.add(news); 245 | } 246 | newsAdapter.notifyDataSetChanged(); 247 | } 248 | 249 | /** 250 | * 请求失败 251 | * 252 | * @param message 253 | */ 254 | @Override 255 | public void fail(String message) { 256 | mRecyclerView.onHeaderRefreshComplete(); 257 | mRecyclerView.onFooterRefreshComplete(); 258 | Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); 259 | } 260 | 261 | @Override 262 | public void onDestroy() { 263 | super.onDestroy(); 264 | newsPresenter.detachView(); 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/main/FragmentTab2.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.main; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.app.FragmentActivity; 5 | import android.support.v4.view.ViewPager; 6 | import android.view.View; 7 | import android.support.design.widget.TabLayout; 8 | import android.widget.Toast; 9 | 10 | import com.byl.mvpdemo.R; 11 | import com.byl.mvpdemo.ui.base.BaseFragment; 12 | import com.byl.mvpdemo.ui.main.adapter.FragmentVedioAdapter; 13 | import com.byl.mvpdemo.ui.images.FragmentImageTab1; 14 | import com.byl.mvpdemo.ui.images.FragmentImageTab2; 15 | import com.byl.mvpdemo.util.LogUtil; 16 | 17 | 18 | public class FragmentTab2 extends BaseFragment { 19 | 20 | TabLayout mTabLayout; 21 | ViewPager mViewPager; 22 | 23 | Fragment[] mFragments; 24 | String[] mTitles; 25 | FragmentVedioAdapter fragmentVedioAdapter; 26 | 27 | @Override 28 | public int getContentView() { 29 | return R.layout.fragment_2; 30 | } 31 | 32 | @Override 33 | public void initView() { 34 | initTitleBar("", "图片", "", R.mipmap.ic_search, this); 35 | mTabLayout = (TabLayout) $(R.id.mTabLayout); 36 | mTabLayout.setBackgroundColor(getResources().getColor(R.color.common_title_bg)); 37 | mViewPager = (ViewPager) $(R.id.mViewPager); 38 | } 39 | 40 | @Override 41 | public void initClick() { 42 | 43 | } 44 | 45 | @Override 46 | public void initData() { 47 | mFragments = new Fragment[]{new FragmentImageTab1(), new FragmentImageTab2()}; 48 | mTitles = new String[]{"美女1", "美女2"}; 49 | fragmentVedioAdapter = new FragmentVedioAdapter(context, ((FragmentActivity) context).getSupportFragmentManager(), mFragments, mTitles); 50 | mViewPager.setAdapter(fragmentVedioAdapter); 51 | mTabLayout.setupWithViewPager(mViewPager); 52 | mTabLayout.getTabAt(0).select(); 53 | } 54 | 55 | @Override 56 | public void onClick(View v) { 57 | switch (v.getId()) { 58 | case R.id.iv_right://标题栏右侧图标 59 | Toast.makeText(context, "搜索", Toast.LENGTH_SHORT).show(); 60 | break; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/main/FragmentTab3.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.main; 2 | 3 | import android.view.View; 4 | import android.widget.LinearLayout; 5 | import android.widget.RelativeLayout; 6 | 7 | import com.byl.mvpdemo.R; 8 | import com.byl.mvpdemo.ui.base.BaseFragment; 9 | import com.byl.mvpdemo.util.LogUtil; 10 | 11 | 12 | /** 13 | */ 14 | public class FragmentTab3 extends BaseFragment { 15 | 16 | LinearLayout ll_head; 17 | 18 | @Override 19 | public int getContentView() { 20 | return R.layout.fragment_3; 21 | } 22 | 23 | @Override 24 | public void initView() { 25 | initTitleBar("", "我的", "", 0, this); 26 | ll_head = (LinearLayout) $(R.id.ll_head); 27 | ll_head.setBackgroundColor(getResources().getColor(R.color.common_title_bg)); 28 | } 29 | 30 | @Override 31 | public void initClick() { 32 | 33 | } 34 | 35 | @Override 36 | public void initData() { 37 | LogUtil.e("FragmentTab3"); 38 | } 39 | 40 | @Override 41 | public void onClick(View v) { 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/main/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.main; 2 | 3 | import android.support.design.widget.TabLayout; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v4.view.ViewPager; 6 | 7 | import com.byl.mvpdemo.R; 8 | import com.byl.mvpdemo.ui.base.BaseActivity; 9 | import com.byl.mvpdemo.ui.main.adapter.FragmentMainTabAdapter; 10 | 11 | 12 | /** 13 | * 主页 14 | */ 15 | public class MainActivity extends BaseActivity { 16 | 17 | ViewPager viewPager; 18 | TabLayout tabLayout; 19 | 20 | private String[] mTabTitles; 21 | private Integer[] mTabIcons; 22 | private Fragment[] mFragments; 23 | private FragmentMainTabAdapter fragmentMainTabAdapter; 24 | 25 | @Override 26 | public int getContentView() { 27 | return R.layout.activity_main; 28 | } 29 | 30 | @Override 31 | public void initView() { 32 | viewPager = (ViewPager) $(R.id.vp_content); 33 | tabLayout = (TabLayout) $(R.id.tabl_navigation); 34 | } 35 | 36 | @Override 37 | public void initClick() { 38 | 39 | } 40 | 41 | @Override 42 | public void initData() { 43 | mTabTitles = new String[]{"新闻", "图片", "我的"}; 44 | mTabIcons = new Integer[]{R.drawable.tab1_selector, R.drawable.tab2_selector, R.drawable.tab3_selector}; 45 | mFragments = new Fragment[]{new FragmentTab1(), new FragmentTab2(), new FragmentTab3()}; 46 | setupViewPager(); 47 | setupTabLayout(); 48 | tabLayout.getTabAt(0).select(); 49 | } 50 | 51 | private void setupTabLayout() { 52 | tabLayout.setTabMode(TabLayout.MODE_FIXED); 53 | tabLayout.setTabGravity(TabLayout.GRAVITY_FILL); 54 | tabLayout.setupWithViewPager(viewPager); 55 | for (int i = 0; i < tabLayout.getTabCount(); i++) { 56 | TabLayout.Tab tab = tabLayout.getTabAt(i); 57 | tab.setCustomView(fragmentMainTabAdapter.getTabView(i)); 58 | } 59 | tabLayout.requestFocus(); 60 | } 61 | 62 | private void setupViewPager() { 63 | fragmentMainTabAdapter = new FragmentMainTabAdapter(context, getSupportFragmentManager(), mFragments, mTabTitles, mTabIcons); 64 | viewPager.setAdapter(fragmentMainTabAdapter); 65 | viewPager.setOffscreenPageLimit(2); 66 | } 67 | 68 | 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/main/adapter/FragmentMainTabAdapter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.main.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v4.app.FragmentManager; 6 | import android.support.v4.app.FragmentStatePagerAdapter; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.widget.ImageView; 10 | import android.widget.TextView; 11 | 12 | import com.byl.mvpdemo.R; 13 | 14 | public class FragmentMainTabAdapter extends FragmentStatePagerAdapter { 15 | private Context mContext; 16 | 17 | private Fragment[] mFragments = null; 18 | private String[] mFragmentTitles =null; 19 | private Integer[] mFragmentIcons = null; 20 | 21 | public FragmentMainTabAdapter(Context context, FragmentManager fm, Fragment[] fragments, String[] titles, Integer[] icons) { 22 | super(fm); 23 | this.mContext = context; 24 | mFragments = fragments; 25 | mFragmentTitles = titles; 26 | mFragmentIcons = icons; 27 | } 28 | 29 | @Override 30 | public Fragment getItem(int position) { 31 | return mFragments[position]; 32 | } 33 | 34 | @Override 35 | public int getCount() { 36 | return mFragments.length; 37 | } 38 | 39 | @Override 40 | public CharSequence getPageTitle(int position) { 41 | return mFragmentTitles[position]; 42 | } 43 | 44 | public View getTabView(int position) { 45 | View tab = LayoutInflater.from(mContext).inflate(R.layout.item_main_tab, null); 46 | TextView tabText = (TextView) tab.findViewById(R.id.tv_title); 47 | ImageView tabImage = (ImageView) tab.findViewById(R.id.iv_icon); 48 | tabText.setText(mFragmentTitles[position]); 49 | tabImage.setBackgroundResource(mFragmentIcons[position]); 50 | if (position == 0) { 51 | tab.setSelected(true); 52 | } 53 | return tab; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/main/adapter/FragmentVedioAdapter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.main.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v4.app.FragmentManager; 6 | import android.support.v4.app.FragmentStatePagerAdapter; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.widget.ImageView; 10 | import android.widget.TextView; 11 | 12 | import com.byl.mvpdemo.R; 13 | 14 | public class FragmentVedioAdapter extends FragmentStatePagerAdapter { 15 | private Context mContext; 16 | 17 | private Fragment[] mFragments = null; 18 | private String[] mFragmentTitles = null; 19 | 20 | public FragmentVedioAdapter(Context context, FragmentManager fm, Fragment[] fragments, String[] titles) { 21 | super(fm); 22 | this.mContext = context; 23 | mFragments = fragments; 24 | mFragmentTitles = titles; 25 | } 26 | 27 | @Override 28 | public Fragment getItem(int position) { 29 | return mFragments[position]; 30 | } 31 | 32 | @Override 33 | public int getCount() { 34 | return mFragments.length; 35 | } 36 | 37 | //此方法用来显示tab上的名字 38 | @Override 39 | public CharSequence getPageTitle(int position) { 40 | return mFragmentTitles[position]; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/util/LogUtil.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.util; 2 | 3 | import android.util.Log; 4 | 5 | public class LogUtil { 6 | 7 | public static final String LOG = "mvp"; 8 | 9 | public static boolean isShowLog = false;//true:打印log,false:不打印log 10 | 11 | public static void e(String message) { 12 | if (!isShowLog) return; 13 | Log.e(LOG, message); 14 | } 15 | 16 | public static void i(String message) { 17 | if (!isShowLog) return; 18 | Log.i(LOG, message); 19 | } 20 | 21 | public static void v(String message) { 22 | if (!isShowLog) return; 23 | Log.v(LOG, message); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/util/SysUtil.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.util; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * Created by baiyuliang on 2016-7-19. 7 | */ 8 | public class SysUtil { 9 | 10 | /** 11 | * 将dp转px 12 | * 13 | * @param context 14 | * @param dpValue 15 | * @return 16 | */ 17 | public static int dip2px(Context context, float dpValue) { 18 | final float scale = context.getResources().getDisplayMetrics().density; 19 | return (int) (dpValue * scale + 0.5f); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/view/MyLinearLayoutManager.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.view; 2 | 3 | /** 4 | * Created by baiyuliang on 2016-7-19. 5 | */ 6 | 7 | import android.content.Context; 8 | import android.support.v7.widget.LinearLayoutManager; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | 13 | public class MyLinearLayoutManager extends LinearLayoutManager { 14 | 15 | 16 | public MyLinearLayoutManager(Context context) { 17 | super(context); 18 | } 19 | 20 | public MyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { 21 | super(context, orientation, reverseLayout); 22 | } 23 | 24 | private int[] mMeasuredDimension = new int[2]; 25 | 26 | @Override 27 | public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, 28 | int widthSpec, int heightSpec) { 29 | 30 | final int widthMode = View.MeasureSpec.getMode(widthSpec); 31 | final int heightMode = View.MeasureSpec.getMode(heightSpec); 32 | final int widthSize = View.MeasureSpec.getSize(widthSpec); 33 | final int heightSize = View.MeasureSpec.getSize(heightSpec); 34 | 35 | int width = 0; 36 | int height = 0; 37 | for (int i = 0; i < getItemCount(); i++) { 38 | measureScrapChild(recycler, i, 39 | View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), 40 | View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), 41 | mMeasuredDimension); 42 | 43 | if (getOrientation() == HORIZONTAL) { 44 | width = width + mMeasuredDimension[0]; 45 | if (i == 0) { 46 | height = mMeasuredDimension[1]; 47 | } 48 | } else { 49 | height = height + mMeasuredDimension[1]; 50 | if (i == 0) { 51 | width = mMeasuredDimension[0]; 52 | } 53 | } 54 | } 55 | switch (widthMode) { 56 | case View.MeasureSpec.EXACTLY: 57 | width = widthSize; 58 | case View.MeasureSpec.AT_MOST: 59 | case View.MeasureSpec.UNSPECIFIED: 60 | } 61 | 62 | switch (heightMode) { 63 | case View.MeasureSpec.EXACTLY: 64 | height = heightSize; 65 | case View.MeasureSpec.AT_MOST: 66 | case View.MeasureSpec.UNSPECIFIED: 67 | } 68 | 69 | setMeasuredDimension(width, height); 70 | } 71 | 72 | private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, 73 | int heightSpec, int[] measuredDimension) { 74 | try { 75 | View view = recycler.getViewForPosition(0);//fix 动态添加时报IndexOutOfBoundsException 76 | 77 | if (view != null) { 78 | RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams(); 79 | 80 | int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, 81 | getPaddingLeft() + getPaddingRight(), p.width); 82 | 83 | int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, 84 | getPaddingTop() + getPaddingBottom(), p.height); 85 | 86 | view.measure(childWidthSpec, childHeightSpec); 87 | measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin; 88 | measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin; 89 | recycler.recycleView(view); 90 | } 91 | } catch (Exception e) { 92 | e.printStackTrace(); 93 | } finally { 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/view/MyProgressDialog.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.view; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Dialog; 5 | import android.content.Context; 6 | import android.os.Build; 7 | import android.view.View; 8 | import android.view.Window; 9 | import android.view.WindowManager; 10 | import android.view.animation.Animation; 11 | import android.view.animation.LinearInterpolator; 12 | import android.view.animation.RotateAnimation; 13 | import android.widget.ImageView; 14 | import android.widget.TextView; 15 | 16 | import com.byl.mvpdemo.R; 17 | 18 | 19 | /** 20 | * 21 | * Date: 2014-06-19 22 | * 23 | * @author byl 24 | */ 25 | public class MyProgressDialog extends Dialog { 26 | 27 | private ImageView iv_route; 28 | private TextView tv; 29 | private RotateAnimation mAnim; 30 | private boolean cancelable = true; 31 | 32 | 33 | public MyProgressDialog(Context context) { 34 | super(context, R.style.Dialog_bocop); 35 | init(); 36 | } 37 | 38 | @SuppressWarnings("ResourceType") 39 | private void init() { 40 | View contentView = View.inflate(getContext(), R.layout.loading_dialog, null); 41 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 42 | Window win = getWindow(); 43 | WindowManager.LayoutParams winParams = win.getAttributes(); 44 | winParams.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; 45 | win.setAttributes(winParams); 46 | } 47 | setContentView(contentView); 48 | 49 | contentView.setOnClickListener(new View.OnClickListener() { 50 | @Override 51 | public void onClick(View v) { 52 | if (cancelable) { 53 | dismiss(); 54 | } 55 | } 56 | }); 57 | iv_route = (ImageView) findViewById(R.id.iv_route); 58 | tv = (TextView) findViewById(R.id.tv); 59 | initAnim(); 60 | getWindow().setWindowAnimations(R.anim.alpha_in); 61 | } 62 | 63 | 64 | private void initAnim() { 65 | mAnim=new RotateAnimation(0, 359, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); 66 | mAnim.setDuration(1500); 67 | mAnim.setInterpolator(new LinearInterpolator()); 68 | mAnim.setFillAfter(true); 69 | mAnim.setRepeatCount(-1); 70 | } 71 | 72 | @Override 73 | public void show() { 74 | iv_route.startAnimation(mAnim); 75 | super.show(); 76 | } 77 | 78 | @SuppressLint("NewApi") 79 | @Override 80 | public void dismiss() { 81 | mAnim.cancel(); 82 | super.dismiss(); 83 | } 84 | 85 | 86 | @Override 87 | public void setCancelable(boolean flag) { 88 | cancelable = flag; 89 | super.setCancelable(flag); 90 | } 91 | 92 | @Override 93 | public void setTitle(CharSequence title) { 94 | tv.setText(title); 95 | } 96 | 97 | public void setMessage(String title) { 98 | tv.setText(title); 99 | } 100 | 101 | @Override 102 | public void setTitle(int titleId) { 103 | setTitle(getContext().getString(titleId)); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/view/pullrecyclerview/PullBaseView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.view.pullrecyclerview; 2 | 3 | import android.content.Context; 4 | import android.graphics.drawable.AnimationDrawable; 5 | import android.support.v7.widget.LinearLayoutManager; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.util.AttributeSet; 8 | import android.view.LayoutInflater; 9 | import android.view.MotionEvent; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.LinearLayout; 13 | import android.widget.ProgressBar; 14 | import android.widget.TextView; 15 | 16 | import com.byl.mvpdemo.R; 17 | 18 | 19 | /** 20 | * 基类:重写LinearLayout,在LinearLayout中依次添加headerview-RecyclerView-footerview, 21 | * 并对LinearLayout进行手势监听 22 | * http://blog.csdn.net/baiyuliang2013 23 | */ 24 | public abstract class PullBaseView extends LinearLayout { 25 | 26 | protected T mRecyclerView; 27 | private boolean isCanScrollAtRereshing = false;//刷新时是否可滑动 28 | private boolean isCanPullDown = true;//是否可下拉 29 | private boolean isCanPullUp = true;//是否可上拉 30 | 31 | // pull state 32 | private static final int PULL_DOWN_STATE = 0;//下拉 33 | private static final int PULL_UP_STATE = 1;//上拉 34 | // refresh states 35 | private static final int PULL_TO_REFRESH = 2;//未达到刷新条件 36 | private static final int RELEASE_TO_REFRESH = 3;//已达到刷新条件 37 | private static final int REFRESHING = 4;//正在刷新 38 | 39 | private int mLastMotionY;//last y 40 | private View mHeaderView;//HeaderView 41 | private View mFooterView;//FooterView 42 | private int mHeaderViewHeight;//HeaderView的高度 43 | private int mFooterViewHeight;//FooterView的高度 44 | private TextView mFooterTextView;//FooterView提示语 45 | private ProgressBar mFooterProgressBar;//FooterView ProgressBar 46 | 47 | private int mHeaderState;//HeaderView当前刷新状态 48 | private int mFooterState;//FooterView当前刷新状态 49 | private int mPullState;//刷新状态:下拉或上拉 50 | 51 | private OnHeaderRefreshListener mOnHeaderRefreshListener;//HeaderView刷新监听 52 | private OnFooterRefreshListener mOnFooterRefreshListener;//FooterView刷新监听 53 | private OnPullDownScrollListener onPullDownScrollListener; 54 | 55 | private float startY;//手指落点 56 | private float offsetY;//手指滑动的距离 57 | 58 | //headview中的动画实现 59 | private RefreshAnimView refreshAnimView; 60 | private RefreshLoadingView refreshLoadingView; 61 | private AnimationDrawable loadAnimation; 62 | 63 | private LayoutInflater mInflater; 64 | 65 | public PullBaseView(Context context) { 66 | super(context); 67 | } 68 | 69 | public PullBaseView(Context context, AttributeSet attrs) { 70 | super(context, attrs); 71 | init(context, attrs); 72 | } 73 | 74 | /** 75 | * init 76 | */ 77 | private void init(Context context, AttributeSet attrs) { 78 | mInflater = LayoutInflater.from(getContext()); 79 | addHeaderView();//首先在Linear中添加headview 80 | mRecyclerView = createRecyclerView(context, attrs); 81 | mRecyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER); 82 | addView(mRecyclerView);//添加RecyclerView 83 | } 84 | 85 | /** 86 | * header view 87 | */ 88 | private void addHeaderView() { 89 | mHeaderView = mInflater.inflate(R.layout.refresh_header, this, false); 90 | refreshAnimView = (RefreshAnimView) mHeaderView.findViewById(R.id.first_step_view); 91 | refreshLoadingView = (RefreshLoadingView) mHeaderView.findViewById(R.id.second_step_view); 92 | refreshLoadingView.setBackgroundResource(R.drawable.anim_refresh); 93 | loadAnimation = (AnimationDrawable) refreshLoadingView.getBackground(); 94 | measureView(mHeaderView);//测量高度 95 | mHeaderViewHeight = mHeaderView.getMeasuredHeight(); 96 | LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mHeaderViewHeight); 97 | params.topMargin = -(mHeaderViewHeight);// 设置topMargin的值为负的header View高度,即将其隐藏在最上方 98 | addView(mHeaderView, params); 99 | 100 | } 101 | 102 | /** 103 | * footer view 104 | */ 105 | private void addFooterView() { 106 | mFooterView = mInflater.inflate(R.layout.refresh_footer, this, false); 107 | mFooterTextView = (TextView) mFooterView.findViewById(R.id.pull_to_load_text); 108 | mFooterProgressBar = (ProgressBar) mFooterView.findViewById(R.id.pull_to_load_progress); 109 | measureView(mFooterView); 110 | mFooterViewHeight = mFooterView.getMeasuredHeight(); 111 | LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mFooterViewHeight); 112 | addView(mFooterView, params); 113 | } 114 | 115 | @Override 116 | protected void onFinishInflate() { 117 | super.onFinishInflate(); 118 | addFooterView();//最后添加footview 119 | } 120 | 121 | /** 122 | * dispatchTouchEvent 在最顶级也就是父布局(Linear)中拦截手势监听 123 | * 1.处理正在刷新时是否可以滑动 124 | * 2.处理头部动画 125 | * 126 | * @param ev 127 | * @return 128 | */ 129 | @Override 130 | public boolean dispatchTouchEvent(MotionEvent ev) { 131 | switch (ev.getAction()) { 132 | case MotionEvent.ACTION_DOWN: 133 | startY = ev.getY(); 134 | break; 135 | case MotionEvent.ACTION_MOVE: 136 | offsetY = ev.getY() - startY; 137 | if (!isCanScrollAtRereshing) { 138 | if (mHeaderState == REFRESHING || mFooterState == REFRESHING) { 139 | return true; 140 | } 141 | } 142 | if (isCanPullUp && offsetY > 0) { 143 | float headerViewShowHeight = offsetY * 0.3f;//headview露出的高度 144 | float currentProgress = headerViewShowHeight / mHeaderViewHeight;//根据此比例,在滑动时改变动图大小 145 | if (currentProgress >= 1) { 146 | currentProgress = 1; 147 | } 148 | if (mHeaderState == PULL_TO_REFRESH || mHeaderState == RELEASE_TO_REFRESH) { 149 | refreshAnimView.setCurrentProgress(currentProgress);//绘制headview中的动画 150 | refreshAnimView.postInvalidate(); 151 | } 152 | } 153 | break; 154 | } 155 | return super.dispatchTouchEvent(ev); 156 | } 157 | 158 | @Override 159 | public boolean onInterceptTouchEvent(MotionEvent e) { 160 | int y = (int) e.getRawY(); 161 | switch (e.getAction()) { 162 | case MotionEvent.ACTION_DOWN: 163 | mLastMotionY = y;// 首先拦截down事件,记录y坐标 164 | break; 165 | case MotionEvent.ACTION_MOVE: 166 | int deltaY = y - mLastMotionY; // deltaY > 0 是向下运动,< 0是向上运动 167 | if (isRefreshViewScroll(deltaY)) { 168 | return true; 169 | } 170 | break; 171 | } 172 | return false; 173 | } 174 | 175 | /** 176 | * 如果在onInterceptTouchEvent()方法中没有拦截(即onInterceptTouchEvent()方法中 return false), 177 | * 则由PullBaseView的子View来处理;否则由下面的方法来处理(即由PullBaseView自己来处理) 178 | */ 179 | @Override 180 | public boolean onTouchEvent(MotionEvent event) { 181 | int y = (int) event.getRawY(); 182 | switch (event.getAction()) { 183 | case MotionEvent.ACTION_MOVE: 184 | int deltaY = y - mLastMotionY; 185 | if (isCanPullDown && mPullState == PULL_DOWN_STATE) { 186 | if (onPullDownScrollListener != null) { 187 | onPullDownScrollListener.onPullDownScrolled(); 188 | } 189 | headerPrepareToRefresh(deltaY); 190 | } else if (isCanPullUp && mPullState == PULL_UP_STATE) { 191 | footerPrepareToRefresh(deltaY); 192 | } 193 | mLastMotionY = y; 194 | break; 195 | case MotionEvent.ACTION_UP: 196 | case MotionEvent.ACTION_CANCEL: 197 | int topMargin = getHeaderTopMargin(); 198 | if (isCanPullDown && mPullState == PULL_DOWN_STATE) { 199 | if (topMargin >= 0) { 200 | headerRefreshing(); // 开始刷新 201 | } else { 202 | if (onPullDownScrollListener != null) { 203 | onPullDownScrollListener.onPullDownFinished(); 204 | } 205 | setHeaderTopMargin(-mHeaderViewHeight); // 还没有执行刷新,重新隐藏 206 | } 207 | } else if (isCanPullUp && mPullState == PULL_UP_STATE) { 208 | if (Math.abs(topMargin) >= mHeaderViewHeight + mFooterViewHeight) { 209 | footerRefreshing();// 开始执行footer 刷新 210 | } else { 211 | setHeaderTopMargin(-mHeaderViewHeight);// 还没有执行刷新,重新隐藏 212 | } 213 | } 214 | break; 215 | } 216 | return super.onTouchEvent(event); 217 | } 218 | 219 | /** 220 | * 是否应该到了父View,即PullBaseView滑动 221 | * 222 | * @param deltaY , deltaY > 0 是向下运动,< 0是向上运动 223 | * @return 224 | */ 225 | private boolean isRefreshViewScroll(int deltaY) { 226 | if (mHeaderState == REFRESHING || mFooterState == REFRESHING) { 227 | return false; 228 | } 229 | if (deltaY >= -20 && deltaY <= 20) 230 | return false; 231 | 232 | if (mRecyclerView != null) { 233 | // 滑动到最顶端 234 | if (deltaY > 0) { 235 | View child = mRecyclerView.getChildAt(0); 236 | if (child == null) { 237 | // mRecyclerView,不拦截 238 | return false; 239 | } 240 | if (isScrollTop() && child.getTop() == 0) { 241 | mPullState = PULL_DOWN_STATE; 242 | return true; 243 | } 244 | int top = child.getTop(); 245 | int padding = mRecyclerView.getPaddingTop(); 246 | if (isScrollTop() && Math.abs(top - padding) <= 8) { 247 | mPullState = PULL_DOWN_STATE; 248 | return true; 249 | } 250 | 251 | } else if (deltaY < 0) { 252 | View lastChild = mRecyclerView.getChildAt(mRecyclerView.getChildCount() - 1); 253 | if (lastChild == null) { 254 | // mRecyclerView,不拦截 255 | return false; 256 | } 257 | // 最后一个子view的Bottom小于父View的高度说明mRecyclerView的数据没有填满父view, 258 | // 等于父View的高度说明mRecyclerView已经滑动到最后 259 | if (lastChild.getBottom() <= getHeight() && isScrollBottom()) { 260 | mPullState = PULL_UP_STATE; 261 | return true; 262 | } 263 | } 264 | } 265 | return false; 266 | } 267 | 268 | /** 269 | * 判断mRecyclerView是否滑动到顶部 270 | * 271 | * @return 272 | */ 273 | boolean isScrollTop() { 274 | LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager(); 275 | if (linearLayoutManager.findFirstVisibleItemPosition() == 0) { 276 | return true; 277 | } else { 278 | return false; 279 | } 280 | } 281 | 282 | /** 283 | * 判断mRecyclerView是否滑动到底部 284 | * 285 | * @return 286 | */ 287 | boolean isScrollBottom() { 288 | LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager(); 289 | if (linearLayoutManager.findLastVisibleItemPosition() == (mRecyclerView.getAdapter().getItemCount() - 1)) { 290 | return true; 291 | } else { 292 | return false; 293 | } 294 | } 295 | 296 | /** 297 | * header 准备刷新,手指移动过程,还没有释放 298 | * 299 | * @param deltaY ,手指滑动的距离 300 | */ 301 | private void headerPrepareToRefresh(int deltaY) { 302 | int newTopMargin = changingHeaderViewTopMargin(deltaY); 303 | // 当header view的topMargin>=0时,说明已经完全显示出来了,修改header view 的提示状态 304 | if (newTopMargin >= 0 && mHeaderState != RELEASE_TO_REFRESH) { 305 | mHeaderState = RELEASE_TO_REFRESH; 306 | } else if (newTopMargin < 0 && newTopMargin > -mHeaderViewHeight) {// 拖动时没有释放 307 | mHeaderState = PULL_TO_REFRESH; 308 | } 309 | } 310 | 311 | /** 312 | * footer 准备刷新,手指移动过程,还没有释放 移动footer view高度同样和移动header view 313 | * 高度是一样,都是通过修改header view的topmargin的值来达到 314 | * 315 | * @param deltaY ,手指滑动的距离 316 | */ 317 | private void footerPrepareToRefresh(int deltaY) { 318 | int newTopMargin = changingHeaderViewTopMargin(deltaY); 319 | // 如果header view topMargin 的绝对值大于或等于header + footer 的高度 320 | // 说明footer view 完全显示出来了,修改footer view 的提示状态 321 | if (Math.abs(newTopMargin) >= (mHeaderViewHeight + mFooterViewHeight) && mFooterState != RELEASE_TO_REFRESH) { 322 | mFooterTextView.setText(R.string.pull_to_refresh_footer_release_label); 323 | mFooterState = RELEASE_TO_REFRESH; 324 | } else if (Math.abs(newTopMargin) < (mHeaderViewHeight + mFooterViewHeight)) { 325 | mFooterTextView.setText(R.string.pull_to_refresh_footer_pull_label); 326 | mFooterState = PULL_TO_REFRESH; 327 | } 328 | } 329 | 330 | /** 331 | * 修改Header view top margin的值 332 | * 333 | * @param deltaY 334 | */ 335 | private int changingHeaderViewTopMargin(int deltaY) { 336 | LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams(); 337 | float newTopMargin = params.topMargin + deltaY * 0.3f; 338 | // 这里对上拉做一下限制,因为当前上拉后然后不释放手指直接下拉,会把下拉刷新给触发了 339 | // 表示如果是在上拉后一段距离,然后直接下拉 340 | if (deltaY > 0 && mPullState == PULL_UP_STATE && Math.abs(params.topMargin) <= mHeaderViewHeight) { 341 | return params.topMargin; 342 | } 343 | // 同样地,对下拉做一下限制,避免出现跟上拉操作时一样的bug 344 | if (deltaY < 0 && mPullState == PULL_DOWN_STATE && Math.abs(params.topMargin) >= mHeaderViewHeight) { 345 | return params.topMargin; 346 | } 347 | params.topMargin = (int) newTopMargin; 348 | mHeaderView.setLayoutParams(params); 349 | invalidate(); 350 | return params.topMargin; 351 | } 352 | 353 | /** 354 | * header refreshing 355 | */ 356 | public void headerRefreshing() { 357 | mHeaderState = REFRESHING; 358 | setHeaderTopMargin(0); 359 | refreshAnimView.setVisibility(View.GONE); 360 | refreshLoadingView.setVisibility(View.VISIBLE); 361 | loadAnimation.start(); 362 | if (mOnHeaderRefreshListener != null) { 363 | mOnHeaderRefreshListener.onHeaderRefresh(this); 364 | } 365 | } 366 | 367 | /** 368 | * footer refreshing 369 | */ 370 | private void footerRefreshing() { 371 | mFooterState = REFRESHING; 372 | int top = mHeaderViewHeight + mFooterViewHeight; 373 | setHeaderTopMargin(-top); 374 | mFooterTextView.setText(R.string.pull_to_refresh_footer_refreshing_label); 375 | mFooterProgressBar.setVisibility(View.VISIBLE); 376 | if (mOnFooterRefreshListener != null) { 377 | mOnFooterRefreshListener.onFooterRefresh(this); 378 | } 379 | } 380 | 381 | /** 382 | * 设置header view 的topMargin的值 383 | * 384 | * @param topMargin ,为0时,说明header view 刚好完全显示出来; 为-mHeaderViewHeight时,说明完全隐藏了 385 | */ 386 | private void setHeaderTopMargin(int topMargin) { 387 | LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams(); 388 | params.topMargin = topMargin; 389 | mHeaderView.setLayoutParams(params); 390 | invalidate(); 391 | } 392 | 393 | /** 394 | * header view 完成更新后恢复初始状态 395 | */ 396 | public void onHeaderRefreshComplete() { 397 | setHeaderTopMargin(-mHeaderViewHeight); 398 | refreshAnimView.setVisibility(View.VISIBLE); 399 | refreshLoadingView.setVisibility(View.GONE); 400 | loadAnimation.stop(); 401 | mHeaderState = PULL_TO_REFRESH; 402 | if (onPullDownScrollListener != null) { 403 | onPullDownScrollListener.onPullDownFinished(); 404 | } 405 | } 406 | 407 | 408 | /** 409 | * footer view 完成更新后恢复初始状态 410 | */ 411 | public void onFooterRefreshComplete() { 412 | setHeaderTopMargin(-mHeaderViewHeight); 413 | mFooterTextView.setText(R.string.pull_to_refresh_footer_pull_label); 414 | mFooterProgressBar.setVisibility(View.GONE); 415 | mFooterState = PULL_TO_REFRESH; 416 | if (mRecyclerView != null) { 417 | mRecyclerView.scrollToPosition(mRecyclerView.getAdapter().getItemCount() - 1); 418 | } 419 | 420 | } 421 | 422 | /** 423 | * 获取当前header view 的topMargin 424 | */ 425 | private int getHeaderTopMargin() { 426 | LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams(); 427 | return params.topMargin; 428 | } 429 | 430 | 431 | /** 432 | * 设置下拉监听接口 433 | */ 434 | public void setOnHeaderRefreshListener(OnHeaderRefreshListener headerRefreshListener) { 435 | mOnHeaderRefreshListener = headerRefreshListener; 436 | } 437 | 438 | /** 439 | * 设置上拉监听接口 440 | */ 441 | public void setOnFooterRefreshListener(OnFooterRefreshListener footerRefreshListener) { 442 | mOnFooterRefreshListener = footerRefreshListener; 443 | } 444 | 445 | /** 446 | * 上拉监听 447 | */ 448 | public interface OnFooterRefreshListener { 449 | void onFooterRefresh(PullBaseView view); 450 | } 451 | 452 | /** 453 | * 下拉监听 454 | */ 455 | public interface OnHeaderRefreshListener { 456 | void onHeaderRefresh(PullBaseView view); 457 | } 458 | 459 | /** 460 | * 下拉滑动动作监听 461 | */ 462 | public interface OnPullDownScrollListener { 463 | void onPullDownScrolled(); 464 | 465 | void onPullDownFinished(); 466 | } 467 | 468 | public void setOnPullDownScrollListener(OnPullDownScrollListener onPullDownScrollListener) { 469 | this.onPullDownScrollListener = onPullDownScrollListener; 470 | } 471 | 472 | /** 473 | * 设置是否可以在刷新时滑动 474 | * 475 | * @param canScrollAtRereshing 476 | */ 477 | public void setCanScrollAtRereshing(boolean canScrollAtRereshing) { 478 | isCanScrollAtRereshing = canScrollAtRereshing; 479 | } 480 | 481 | /** 482 | * 设置是否可上拉 483 | * 484 | * @param canPullUp 485 | */ 486 | public void setCanPullUp(boolean canPullUp) { 487 | isCanPullUp = canPullUp; 488 | } 489 | 490 | /** 491 | * 设置是否可下拉 492 | * 493 | * @param canPullDown 494 | */ 495 | public void setCanPullDown(boolean canPullDown) { 496 | isCanPullDown = canPullDown; 497 | } 498 | 499 | private void measureView(View child) { 500 | ViewGroup.LayoutParams p = child.getLayoutParams(); 501 | if (p == null) { 502 | p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); 503 | } 504 | int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width); 505 | int lpHeight = p.height; 506 | int childHeightSpec; 507 | if (lpHeight > 0) { 508 | childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); 509 | } else { 510 | childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 511 | } 512 | child.measure(childWidthSpec, childHeightSpec); 513 | } 514 | 515 | 516 | /** 517 | * 抽象方法,子类实现,传入View 518 | * 519 | * @param context 520 | * @param attrs 521 | * @return 522 | */ 523 | protected abstract T createRecyclerView(Context context, AttributeSet attrs); 524 | 525 | } 526 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/view/pullrecyclerview/PullRecyclerView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.view.pullrecyclerview; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.util.AttributeSet; 6 | 7 | /** 8 | * RecyclerView中的所有方法都可以在此类中设置,暴露出去以供调用 9 | */ 10 | public class PullRecyclerView extends PullBaseView { 11 | 12 | 13 | public PullRecyclerView(Context context) { 14 | this(context, null); 15 | } 16 | 17 | public PullRecyclerView(Context context, AttributeSet attrs) { 18 | super(context, attrs); 19 | } 20 | 21 | 22 | @Override 23 | protected RecyclerView createRecyclerView(Context context, AttributeSet attrs) { 24 | return new RecyclerView(context, attrs); 25 | } 26 | 27 | public void setAdapter(RecyclerView.Adapter adapter) { 28 | mRecyclerView.setAdapter(adapter); 29 | } 30 | 31 | public void setLayoutManager(RecyclerView.LayoutManager manager) { 32 | mRecyclerView.setLayoutManager(manager); 33 | } 34 | 35 | public void addOnScrollListener(RecyclerView.OnScrollListener onScrollListener) { 36 | mRecyclerView.addOnScrollListener(onScrollListener); 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/view/pullrecyclerview/RefreshAnimView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.view.pullrecyclerview; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.graphics.Canvas; 7 | import android.graphics.Paint; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | 11 | import com.byl.mvpdemo.R; 12 | 13 | 14 | public class RefreshAnimView extends View{ 15 | 16 | private Bitmap daishu; 17 | private int measuredWidth; 18 | private int measuredHeight; 19 | private float mCurrentProgress; 20 | private int mCurrentAlpha; 21 | private Paint mPaint; 22 | private Bitmap scaleDaishu; 23 | 24 | public RefreshAnimView(Context context, AttributeSet attrs, int defStyle) { 25 | super(context, attrs, defStyle); 26 | init(); 27 | } 28 | 29 | public RefreshAnimView(Context context, AttributeSet attrs) { 30 | super(context, attrs); 31 | init(); 32 | } 33 | 34 | public RefreshAnimView(Context context) { 35 | super(context); 36 | init(); 37 | } 38 | private void init(){ 39 | //袋鼠bitmap 40 | daishu = BitmapFactory.decodeResource(getResources(), R.mipmap.takeout_img_list_loading_pic1); 41 | //来个画笔,我们注意到袋鼠都有一个渐变效果的,我们用 42 | //mPaint.setAlpha来实现这个渐变的效果 43 | mPaint = new Paint(); 44 | //首先设置为完全透明 45 | mPaint.setAlpha(0); 46 | } 47 | 48 | /** 49 | * 测量方法 50 | * @param widthMeasureSpec 51 | * @param heightMeasureSpec 52 | */ 53 | @Override 54 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 55 | setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); 56 | } 57 | //测量宽度 58 | private int measureWidth(int widthMeasureSpec){ 59 | int result = 0; 60 | int size = MeasureSpec.getSize(widthMeasureSpec); 61 | int mode = MeasureSpec.getMode(widthMeasureSpec); 62 | if (MeasureSpec.EXACTLY == mode) { 63 | result = size; 64 | }else { 65 | result = daishu.getWidth(); 66 | if (MeasureSpec.AT_MOST == mode) { 67 | result = Math.min(result, size); 68 | } 69 | } 70 | return result; 71 | } 72 | //测量高度 73 | private int measureHeight(int heightMeasureSpec){ 74 | int result = 0; 75 | int size = MeasureSpec.getSize(heightMeasureSpec); 76 | int mode = MeasureSpec.getMode(heightMeasureSpec); 77 | if (MeasureSpec.EXACTLY == mode) { 78 | result = size; 79 | }else { 80 | result = daishu.getHeight(); 81 | if (MeasureSpec.AT_MOST == mode) { 82 | result = Math.min(result, size); 83 | } 84 | } 85 | return result; 86 | } 87 | //在这里面拿到测量后的宽和高,w就是测量后的宽,h是测量后的高 88 | @Override 89 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 90 | super.onSizeChanged(w, h, oldw, oldh); 91 | measuredWidth = w; 92 | measuredHeight = h; 93 | //根据测量后的宽高来对袋鼠做一个缩放 94 | scaleDaishu = Bitmap.createScaledBitmap(daishu,measuredWidth,measuredHeight,true); 95 | } 96 | 97 | /** 98 | * 绘制方法 99 | * @param canvas 100 | */ 101 | @Override 102 | protected void onDraw(Canvas canvas) { 103 | super.onDraw(canvas); 104 | canvas.scale(mCurrentProgress, mCurrentProgress, measuredWidth/2, measuredHeight); 105 | mPaint.setAlpha(mCurrentAlpha); 106 | canvas.drawBitmap(scaleDaishu, 0, 0, mPaint); 107 | } 108 | 109 | /** 110 | * 根据进度对袋鼠进行缩放 111 | * @param currentProgress 112 | */ 113 | public void setCurrentProgress(float currentProgress){ 114 | this.mCurrentProgress = currentProgress; 115 | this.mCurrentAlpha = (int) (currentProgress*255); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/view/pullrecyclerview/RefreshLoadingView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.view.pullrecyclerview; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.util.AttributeSet; 7 | import android.view.View; 8 | 9 | import com.byl.mvpdemo.R; 10 | 11 | 12 | public class RefreshLoadingView extends View { 13 | 14 | private Bitmap endBitmap; 15 | 16 | public RefreshLoadingView(Context context, AttributeSet attrs, int defStyle) { 17 | super(context, attrs, defStyle); 18 | init(); 19 | } 20 | 21 | public RefreshLoadingView(Context context, AttributeSet attrs) { 22 | super(context, attrs); 23 | init(); 24 | } 25 | 26 | public RefreshLoadingView(Context context) { 27 | super(context); 28 | init(); 29 | } 30 | 31 | private void init() { 32 | endBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.takeout_img_list_loading_pic1); 33 | } 34 | 35 | /** 36 | * 只需要测量方法 37 | * 38 | * @param widthMeasureSpec 39 | * @param heightMeasureSpec 40 | */ 41 | @Override 42 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 43 | setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); 44 | } 45 | 46 | private int measureWidth(int widthMeasureSpec) { 47 | int result = 0; 48 | int size = MeasureSpec.getSize(widthMeasureSpec); 49 | int mode = MeasureSpec.getMode(widthMeasureSpec); 50 | if (MeasureSpec.EXACTLY == mode) { 51 | result = size; 52 | } else { 53 | result = endBitmap.getWidth(); 54 | if (MeasureSpec.AT_MOST == mode) { 55 | result = Math.min(size, result); 56 | } 57 | } 58 | return result; 59 | } 60 | 61 | private int measureHeight(int heightMeasureSpec) { 62 | int result = 0; 63 | int size = MeasureSpec.getSize(heightMeasureSpec); 64 | int mode = MeasureSpec.getMode(heightMeasureSpec); 65 | if (MeasureSpec.EXACTLY == mode) { 66 | result = size; 67 | } else { 68 | result = endBitmap.getHeight(); 69 | if (MeasureSpec.AT_MOST == mode) { 70 | result = Math.min(size, result); 71 | } 72 | } 73 | return result; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/res/anim/alpha_in.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/color/main_tab_text_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 13 | 14 | 19 | 24 | 25 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/anim_refresh.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/common_back_arrow_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/common_btn_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/common_image_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/common_text_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_common.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_common_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_common_button_press.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_common_transparent.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_common_white.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tab1_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tab2_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tab3_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tab_text_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_login.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 17 | 18 | 28 | 29 | 38 | 39 | 40 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 12 | 13 | 17 | 18 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/layout/common_title_bar.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 19 | 20 | 27 | 28 | 37 | 38 | 50 | 51 | 61 | 62 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 15 | 20 | 21 | 35 | 36 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 23 | 24 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 15 | 16 | 20 | 21 | 28 | 29 | 34 | 35 | 42 | 43 | 44 | 45 | 53 | 54 | 60 | 61 | 62 | 63 | 71 | 72 | 78 | 79 | 80 | 81 | 89 | 90 | 96 | 97 | 98 | 99 | 100 | 108 | 109 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_images_tab1.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_images_tab2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_girls.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 22 | 23 | 34 | 35 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_home_head.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 19 | 20 | 26 | 27 | 36 | 37 | 41 | 42 | 49 | 50 | 51 | 52 | 58 | 59 | 68 | 69 | 73 | 74 | 81 | 82 | 83 | 84 | 90 | 91 | 100 | 101 | 105 | 106 | 113 | 114 | 115 | 116 | 122 | 123 | 132 | 133 | 137 | 138 | 145 | 146 | 147 | 148 | 149 | 150 | 154 | 155 | 160 | 161 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_img.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_main_tab.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_news.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 21 | 22 | 28 | 29 | 38 | 39 | 49 | 50 | 59 | 60 | 61 | 62 | 63 | 67 | -------------------------------------------------------------------------------- /app/src/main/res/layout/loading_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | 20 | 21 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/refresh_footer.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/refresh_header.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 10 | 11 | 18 | 19 | 27 | 28 | 29 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/banner.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/fop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/fop.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/head_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/head_default.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/home_icon_cg_glfriends.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/home_icon_cg_glfriends.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/home_icon_cg_glhouse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/home_icon_cg_glhouse.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/home_icon_cg_gllaw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/home_icon_cg_gllaw.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/home_icon_cg_gllife.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/home_icon_cg_gllife.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_common_back_arrow_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/ic_common_back_arrow_normal.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_common_back_arrow_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/ic_common_back_arrow_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_loading_dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/ic_loading_dialog.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_pulltorefresh_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/ic_pulltorefresh_arrow.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_pulltorefresh_arrow_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/ic_pulltorefresh_arrow_up.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/ic_search.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_tabbar_favorites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/icon_tabbar_favorites.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_tabbar_favorites_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/icon_tabbar_favorites_selected.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_tabbar_library.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/icon_tabbar_library.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_tabbar_library_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/icon_tabbar_library_selected.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_tabbar_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/icon_tabbar_settings.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_tabbar_settings_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/icon_tabbar_settings_selected.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/iv_qr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/iv_qr.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/takeout_img_list_loading_pic1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/takeout_img_list_loading_pic1.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/takeout_img_list_loading_pic2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/takeout_img_list_loading_pic2.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FF0000 4 | #FF0000 5 | #FF0000 6 | 7 | 8 | #FF0000 9 | #F00000 10 | #000000 11 | #F0F0F0 12 | 13 | 14 | #A2A2A2 15 | #2D6EFA 16 | 17 | #999999 18 | #50000000 19 | #FFFFFF 20 | #EEEEEE 21 | #cccccc 22 | #999999 23 | 24 | #30000000 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | MVPDemo 3 | 登录 4 | 5 | 6 | 请输入手机号 7 | 请输入密码 8 | 登录 9 | 10 | 下拉刷新 11 | 松开刷新 12 | 正在刷新\u2026 13 | 松开加载更多 14 | 上拉加载更多 15 | 加载中\u2026 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 16 | 17 | 18 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /appdemo.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/appdemo.apk -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.1.2' 9 | classpath 'me.tatarka:gradle-retrolambda:3.1.0' 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------
79 | * 如果是非header的情况,即两个数据源的列表,则ItemCount=listDatas1.size()+listDatas2.size(); 80 | * 81 | * @return 82 | */ 83 | @Override 84 | public int getItemCount() { 85 | return 1 + listDatas2.size(); 86 | } 87 | 88 | @Override 89 | public int getItemViewType(int position) { 90 | if (position == 0) { 91 | return R.layout.item_home_head; 92 | } else { 93 | return R.layout.item_news; 94 | } 95 | } 96 | 97 | class MyViewHolder extends RecyclerView.ViewHolder { 98 | ViewPager vp; 99 | LinearLayout ll_1, ll_2, ll_3, ll_4; 100 | 101 | ImageView iv_icon;// 102 | TextView tv_title, tv_des, tv_time;// 103 | 104 | public MyViewHolder(View view) { 105 | super(view); 106 | vp = (ViewPager) view.findViewById(R.id.vp);//banner 107 | ll_1 = (LinearLayout) view.findViewById(R.id.ll_1);//新闻1 108 | ll_2 = (LinearLayout) view.findViewById(R.id.ll_2);//新闻2 109 | ll_3 = (LinearLayout) view.findViewById(R.id.ll_3);//新闻3 110 | ll_4 = (LinearLayout) view.findViewById(R.id.ll_4);//新闻4 111 | 112 | iv_icon = (ImageView) view.findViewById(R.id.iv_icon);// 113 | tv_title = (TextView) view.findViewById(R.id.tv_title);//标题 114 | tv_des = (TextView) view.findViewById(R.id.tv_des);//内容 115 | tv_time = (TextView) view.findViewById(R.id.tv_time);//时间 116 | } 117 | } 118 | 119 | 120 | private void initViewPager(MyViewHolder holder) { 121 | isViewPagerLoadScucess = true; 122 | List imageViews = new ArrayList<>(); 123 | for (int i = 0; i < listDatas1.size(); i++) { 124 | final ImageModel imageModel = (ImageModel) listDatas1.get(i); 125 | View view = mInflater.inflate(R.layout.item_img, null); 126 | ImageView imageView = (ImageView) view.findViewById(R.id.img); 127 | Picasso.with(context).load(imageModel.getUrl()).error(R.mipmap.banner).into(imageView); 128 | //设置广告点击事件 129 | view.setOnClickListener(v -> { 130 | Toast.makeText(context, "图片>>" + imageModel.getUrl(), Toast.LENGTH_SHORT).show(); 131 | }); 132 | imageViews.add(view); 133 | } 134 | holder.vp.setAdapter(new PagerAdapter() { 135 | @Override 136 | public int getCount() { 137 | return imageViews.size(); 138 | } 139 | 140 | @Override 141 | public Object instantiateItem(ViewGroup arg0, int arg1) { 142 | arg0.addView(imageViews.get(arg1)); 143 | return imageViews.get(arg1); 144 | } 145 | 146 | @Override 147 | public void destroyItem(ViewGroup arg0, int arg1, Object arg2) { 148 | arg0.removeView((View) arg2); 149 | } 150 | 151 | @Override 152 | public boolean isViewFromObject(View view, Object object) { 153 | return view == object; 154 | } 155 | }); 156 | } 157 | 158 | public void setViewPagerLoadScucess(boolean viewPagerLoadScucess) { 159 | isViewPagerLoadScucess = viewPagerLoadScucess; 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/api/ApiService.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.api; 2 | 3 | import com.byl.mvpdemo.model.modelbean.LoginBean; 4 | import com.byl.mvpdemo.model.modelbean.NewsBean; 5 | 6 | import retrofit2.http.Field; 7 | import retrofit2.http.FormUrlEncoded; 8 | import retrofit2.http.GET; 9 | import retrofit2.http.POST; 10 | import retrofit2.http.Query; 11 | import rx.Observable; 12 | 13 | /** 14 | * Created by baiyuliang on 2016-7-14. 15 | */ 16 | public interface ApiService { 17 | 18 | String API_ROOT = "http://route.showapi.com/"; 19 | 20 | /** 21 | * 登录 22 | * 模拟登录,实际为手机号归属地查询接口 23 | * 24 | * @return 25 | */ 26 | @FormUrlEncoded 27 | @POST("6-1") 28 | Observable login(@Field("num") String num); 29 | 30 | /** 31 | * 新闻列表 32 | * 33 | * @param num 34 | * @param page 35 | * @return 36 | */ 37 | @GET("198-1") 38 | Observable news(@Query("num") String num, @Query("page") String page); 39 | 40 | /** 41 | * 美女图片列表 42 | * 参数类型与新闻列表相同,因此公用NewsBean 43 | * 44 | * @param num 45 | * @param page 46 | * @param rand 1.随机 0不随机 47 | * @return 48 | */ 49 | @GET("197-1") 50 | Observable girls(@Query("num") String num, @Query("page") String page, @Query("rand") String rand); 51 | 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/api/ApiUtil.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.api; 2 | 3 | import com.byl.mvpdemo.util.LogUtil; 4 | import com.google.gson.Gson; 5 | 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import okhttp3.HttpUrl; 9 | import okhttp3.MediaType; 10 | import okhttp3.OkHttpClient; 11 | import okhttp3.Request; 12 | import okhttp3.Response; 13 | import okhttp3.ResponseBody; 14 | import retrofit2.Retrofit; 15 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; 16 | import retrofit2.converter.gson.GsonConverterFactory; 17 | 18 | /** 19 | * Created by baiyuliang on 2016-7-14. 20 | */ 21 | public class ApiUtil { 22 | 23 | public static ApiService createApiService() { 24 | OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder(); 25 | okHttpClientBuilder.connectTimeout(10 * 1000, TimeUnit.MILLISECONDS);//设置请求超时时间10s 26 | OkHttpClient client = okHttpClientBuilder 27 | .addInterceptor((chain) -> {//添加统一参数 28 | Request request = chain.request(); 29 | HttpUrl url = request.url() 30 | .newBuilder() 31 | .addQueryParameter("showapi_appid", "20676") 32 | .addQueryParameter("showapi_sign", "f730cd8c4cf8498895f83d43ddaba8c2") 33 | .build(); 34 | request = request.newBuilder().url(url).build(); 35 | return chain.proceed(request); 36 | }) 37 | .addInterceptor((chain) -> {//log拦截器 38 | Request request = chain.request(); 39 | LogUtil.v("request>>" + request.toString()); 40 | Response response = chain.proceed(chain.request()); 41 | MediaType mediaType = response.body().contentType(); 42 | String content = response.body().string(); 43 | LogUtil.i("response>>" + content); 44 | return response.newBuilder().body(ResponseBody.create(mediaType, content)).build(); 45 | }) 46 | .hostnameVerifier((hostname, session) -> true) 47 | .build(); 48 | 49 | Retrofit retrofit = new Retrofit.Builder() 50 | .baseUrl(ApiService.API_ROOT) 51 | .client(client) 52 | .addConverterFactory(GsonConverterFactory.create(new Gson())) 53 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 54 | .build(); 55 | return retrofit.create(ApiService.class); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/modelbean/BaseBean.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.modelbean; 2 | 3 | /** 4 | * Created by baiyuliang on 2016-7-14. 5 | */ 6 | public class BaseBean { 7 | 8 | private String showapi_res_code; 9 | private String showapi_res_error; 10 | 11 | public String getShowapi_res_code() { 12 | return showapi_res_code; 13 | } 14 | 15 | public void setShowapi_res_code(String showapi_res_code) { 16 | this.showapi_res_code = showapi_res_code; 17 | } 18 | 19 | public String getShowapi_res_error() { 20 | return showapi_res_error; 21 | } 22 | 23 | public void setShowapi_res_error(String showapi_res_error) { 24 | this.showapi_res_error = showapi_res_error; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/modelbean/ImageModel.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.modelbean; 2 | 3 | /** 4 | * banner 5 | * Created by baiyuliang on 2016-7-20. 6 | */ 7 | public class ImageModel { 8 | 9 | private String url; 10 | private String link; 11 | private String des; 12 | 13 | public String getUrl() { 14 | return url; 15 | } 16 | 17 | public void setUrl(String url) { 18 | this.url = url; 19 | } 20 | 21 | public String getLink() { 22 | return link; 23 | } 24 | 25 | public void setLink(String link) { 26 | this.link = link; 27 | } 28 | 29 | public String getDes() { 30 | return des; 31 | } 32 | 33 | public void setDes(String des) { 34 | this.des = des; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/modelbean/LoginBean.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.modelbean; 2 | 3 | /** 4 | * Created by baiyuliang on 2016-7-14. 5 | */ 6 | public class LoginBean extends BaseBean { 7 | 8 | private LoginModel showapi_res_body; 9 | 10 | public LoginModel getShowapi_res_body() { 11 | return showapi_res_body; 12 | } 13 | 14 | public void setShowapi_res_body(LoginModel showapi_res_body) { 15 | this.showapi_res_body = showapi_res_body; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/modelbean/LoginModel.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.modelbean; 2 | 3 | /** 4 | * Created by baiyuliang on 2016-7-14. 5 | * 6 | * prov String 四川 省 7 | * city String test 市 8 | * name String test 运营商 9 | * num Number 1370011 号段 10 | * provCode Number 110000 省别编码 11 | * type Number 1 1为移动 2为电信 3为联通 12 | */ 13 | public class LoginModel{ 14 | 15 | private String ret_code; 16 | private String prov; 17 | private String city; 18 | private String name; 19 | private String num; 20 | private String provCode; 21 | private String type; 22 | 23 | public String getRet_code() { 24 | return ret_code; 25 | } 26 | 27 | public void setRet_code(String ret_code) { 28 | this.ret_code = ret_code; 29 | } 30 | 31 | public String getProv() { 32 | return prov; 33 | } 34 | 35 | public void setProv(String prov) { 36 | this.prov = prov; 37 | } 38 | 39 | public String getCity() { 40 | return city; 41 | } 42 | 43 | public void setCity(String city) { 44 | this.city = city; 45 | } 46 | 47 | public String getName() { 48 | return name; 49 | } 50 | 51 | public void setName(String name) { 52 | this.name = name; 53 | } 54 | 55 | public String getNum() { 56 | return num; 57 | } 58 | 59 | public void setNum(String num) { 60 | this.num = num; 61 | } 62 | 63 | public String getProvCode() { 64 | return provCode; 65 | } 66 | 67 | public void setProvCode(String provCode) { 68 | this.provCode = provCode; 69 | } 70 | 71 | public String getType() { 72 | return type; 73 | } 74 | 75 | public void setType(String type) { 76 | this.type = type; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/modelbean/News.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.modelbean; 2 | 3 | /** 4 | * 根据返回json类型,多级嵌套 5 | * Created by baiyuliang on 2016-7-14. 6 | */ 7 | public class News { 8 | private String title; 9 | private String picUrl; 10 | private String description; 11 | private String ctime; 12 | private String url; 13 | 14 | public String getTitle() { 15 | return title; 16 | } 17 | 18 | public void setTitle(String title) { 19 | this.title = title; 20 | } 21 | 22 | public String getPicUrl() { 23 | return picUrl; 24 | } 25 | 26 | public void setPicUrl(String picUrl) { 27 | this.picUrl = picUrl; 28 | } 29 | 30 | public String getDescription() { 31 | return description; 32 | } 33 | 34 | public void setDescription(String description) { 35 | this.description = description; 36 | } 37 | 38 | public String getCtime() { 39 | return ctime; 40 | } 41 | 42 | public void setCtime(String ctime) { 43 | this.ctime = ctime; 44 | } 45 | 46 | public String getUrl() { 47 | return url; 48 | } 49 | 50 | public void setUrl(String url) { 51 | this.url = url; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/modelbean/NewsBean.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.modelbean; 2 | 3 | /** 4 | * Created by baiyuliang on 2016-7-14. 5 | */ 6 | public class NewsBean extends BaseBean { 7 | 8 | private NewsModel showapi_res_body; 9 | 10 | public NewsModel getShowapi_res_body() { 11 | return showapi_res_body; 12 | } 13 | 14 | public void setShowapi_res_body(NewsModel showapi_res_body) { 15 | this.showapi_res_body = showapi_res_body; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/modelbean/NewsModel.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.modelbean; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 新聞 7 | * Created by baiyuliang on 2016-7-14. 8 | */ 9 | public class NewsModel { 10 | private String code; 11 | private String msg; 12 | private List newslist; 13 | 14 | public String getCode() { 15 | return code; 16 | } 17 | 18 | public void setCode(String code) { 19 | this.code = code; 20 | } 21 | 22 | public String getMsg() { 23 | return msg; 24 | } 25 | 26 | public void setMsg(String msg) { 27 | this.msg = msg; 28 | } 29 | 30 | public List getNewslist() { 31 | return newslist; 32 | } 33 | 34 | public void setNewslist(List newslist) { 35 | this.newslist = newslist; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/mvpview/ImagesMvpView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.mvpview; 2 | 3 | import com.byl.mvpdemo.model.modelbean.NewsBean; 4 | import com.byl.mvpdemo.model.mvpview.base.MvpView; 5 | 6 | /** 7 | * Created by baiyuliang on 2016-7-14. 8 | */ 9 | public interface ImagesMvpView extends MvpView { 10 | 11 | /** 12 | * 下拉刷新成功 13 | * 14 | * @param newsBean 15 | */ 16 | void refreshSuccess(NewsBean newsBean); 17 | 18 | /** 19 | * 上拉加载成功 20 | * 21 | * @param newsBean 22 | */ 23 | void loadMoreSuccess(NewsBean newsBean); 24 | 25 | /** 26 | * 失败 27 | * 28 | * @param message 29 | */ 30 | void fail(String message); 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/mvpview/LoginMvpView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.mvpview; 2 | 3 | import com.byl.mvpdemo.model.modelbean.LoginBean; 4 | import com.byl.mvpdemo.model.mvpview.base.MvpView; 5 | 6 | /** 7 | * Created by baiyuliang on 2016-7-14. 8 | */ 9 | public interface LoginMvpView extends MvpView { 10 | 11 | /** 12 | * 登录成功 13 | * @param loginBean 14 | */ 15 | void loginSuccess(LoginBean loginBean); 16 | 17 | /** 18 | * 登录失败 19 | * @param message 20 | */ 21 | void loginFail(String message); 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/mvpview/NewsMvpView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.mvpview; 2 | 3 | import com.byl.mvpdemo.model.modelbean.NewsBean; 4 | import com.byl.mvpdemo.model.mvpview.base.MvpView; 5 | 6 | /** 7 | * Created by baiyuliang on 2016-7-14. 8 | */ 9 | public interface NewsMvpView extends MvpView { 10 | 11 | /** 12 | * 下拉刷新成功 13 | * 14 | * @param newsBean 15 | */ 16 | void refreshSuccess(NewsBean newsBean); 17 | 18 | /** 19 | * 上拉加载成功 20 | * 21 | * @param newsBean 22 | */ 23 | void loadMoreSuccess(NewsBean newsBean); 24 | 25 | /** 26 | * 失败 27 | * 28 | * @param message 29 | */ 30 | void fail(String message); 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/mvpview/base/MvpView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.mvpview.base; 2 | 3 | 4 | /** 5 | * Base interface that any class that wants to act as a View in the MVP (Model View Presenter) 6 | * pattern must implement. Generally this interface will be extended by a more specific interface 7 | * that then usually will be implemented by an Activity or Fragment. 8 | */ 9 | public interface MvpView { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/presenter/ImagesPresenter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.presenter; 2 | 3 | import android.content.Context; 4 | import android.text.TextUtils; 5 | 6 | import com.byl.mvpdemo.model.modelbean.NewsBean; 7 | import com.byl.mvpdemo.model.mvpview.NewsMvpView; 8 | import com.byl.mvpdemo.presenter.base.BasePresenter; 9 | import com.byl.mvpdemo.util.LogUtil; 10 | 11 | import rx.Subscriber; 12 | import rx.Subscription; 13 | import rx.android.schedulers.AndroidSchedulers; 14 | import rx.schedulers.Schedulers; 15 | 16 | /** 17 | * Created by baiyuliang on 2016-7-14. 18 | */ 19 | public class ImagesPresenter extends BasePresenter { 20 | 21 | Subscription mSubscription; 22 | 23 | public ImagesPresenter(Context context) { 24 | this.context = context; 25 | } 26 | 27 | @Override 28 | public void attachView(NewsMvpView mvpView) { 29 | super.attachView(mvpView); 30 | } 31 | 32 | @Override 33 | public void detachView() { 34 | super.detachView(); 35 | if (mSubscription != null) mSubscription.unsubscribe(); 36 | } 37 | 38 | public void getImages(String num, String page, String rand) { 39 | checkViewAttached(); 40 | mSubscription = getApiService().girls(num, page, rand) 41 | .observeOn(AndroidSchedulers.mainThread()) 42 | .subscribeOn(Schedulers.io()) 43 | .subscribe(new Subscriber() { 44 | @Override 45 | public void onCompleted() { 46 | 47 | } 48 | 49 | @Override 50 | public void onError(Throwable e) { 51 | getMvpView().fail("获取图片失败"); 52 | LogUtil.e("获取图片失败>>" + e.getMessage()); 53 | } 54 | 55 | @Override 56 | public void onNext(NewsBean newsBean) { 57 | if (!newsBean.getShowapi_res_code().equals("0") 58 | || newsBean.getShowapi_res_body() == null 59 | || TextUtils.isEmpty(newsBean.getShowapi_res_body().getCode()) 60 | || !newsBean.getShowapi_res_body().getCode().equals("200")) { 61 | getMvpView().fail("获取图片失败"); 62 | } else { 63 | if (page.equals("1")) {//刷新 64 | if (newsBean.getShowapi_res_body().getNewslist() == null 65 | || newsBean.getShowapi_res_body().getNewslist().size() <= 0) { 66 | getMvpView().fail("当前无图片"); 67 | } else { 68 | getMvpView().refreshSuccess(newsBean); 69 | } 70 | } else {//加载更多 71 | if (newsBean.getShowapi_res_body().getNewslist() == null 72 | || newsBean.getShowapi_res_body().getNewslist().size() <= 0) { 73 | getMvpView().fail("没有更多数据啦"); 74 | } else { 75 | getMvpView().loadMoreSuccess(newsBean); 76 | } 77 | } 78 | 79 | } 80 | } 81 | }); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/presenter/LoginPresenter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.presenter; 2 | 3 | import android.content.Context; 4 | import android.text.TextUtils; 5 | 6 | import com.byl.mvpdemo.api.ApiService; 7 | import com.byl.mvpdemo.model.modelbean.LoginBean; 8 | import com.byl.mvpdemo.model.mvpview.LoginMvpView; 9 | import com.byl.mvpdemo.presenter.base.BasePresenter; 10 | import com.byl.mvpdemo.util.LogUtil; 11 | import com.byl.mvpdemo.view.MyProgressDialog; 12 | 13 | import rx.Subscriber; 14 | import rx.Subscription; 15 | import rx.android.schedulers.AndroidSchedulers; 16 | import rx.schedulers.Schedulers; 17 | 18 | /** 19 | * Created by baiyuliang on 2016-7-14. 20 | */ 21 | public class LoginPresenter extends BasePresenter { 22 | 23 | Subscription mSubscription; 24 | 25 | public LoginPresenter(Context context) { 26 | this.context = context; 27 | } 28 | 29 | @Override 30 | public void attachView(LoginMvpView mvpView) { 31 | super.attachView(mvpView); 32 | } 33 | 34 | @Override 35 | public void detachView() { 36 | super.detachView(); 37 | if (mSubscription != null) mSubscription.unsubscribe(); 38 | } 39 | 40 | public void login(String account) { 41 | checkViewAttached(); 42 | showProgressDialog(); 43 | mSubscription = getApiService().login(account) 44 | .observeOn(AndroidSchedulers.mainThread()) 45 | .subscribeOn(Schedulers.io()) 46 | .subscribe(new Subscriber() { 47 | @Override 48 | public void onCompleted() { 49 | 50 | } 51 | 52 | @Override 53 | public void onError(Throwable e) { 54 | dissmissProgressDialog(); 55 | getMvpView().loginFail("登录失败"); 56 | LogUtil.e("登录失败>>" + e.getMessage()); 57 | } 58 | 59 | @Override 60 | public void onNext(LoginBean loginBean) { 61 | dissmissProgressDialog(); 62 | if (!loginBean.getShowapi_res_code().equals("0") 63 | || loginBean.getShowapi_res_body() == null 64 | || TextUtils.isEmpty(loginBean.getShowapi_res_body().getRet_code()) 65 | || !loginBean.getShowapi_res_body().getRet_code().equals("0")) { 66 | getMvpView().loginFail("请检查您输入的手机号码是否正确"); 67 | } else { 68 | getMvpView().loginSuccess(loginBean); 69 | } 70 | } 71 | }); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/presenter/NewsPresenter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.presenter; 2 | 3 | import android.content.Context; 4 | import android.text.TextUtils; 5 | import android.util.Log; 6 | 7 | import com.byl.mvpdemo.model.modelbean.NewsBean; 8 | import com.byl.mvpdemo.model.mvpview.NewsMvpView; 9 | import com.byl.mvpdemo.presenter.base.BasePresenter; 10 | import com.byl.mvpdemo.util.LogUtil; 11 | 12 | import rx.Subscriber; 13 | import rx.Subscription; 14 | import rx.android.schedulers.AndroidSchedulers; 15 | import rx.schedulers.Schedulers; 16 | 17 | /** 18 | * Created by baiyuliang on 2016-7-14. 19 | */ 20 | public class NewsPresenter extends BasePresenter { 21 | 22 | boolean isFirstReq = true; 23 | Subscription mSubscription; 24 | 25 | public NewsPresenter(Context context) { 26 | this.context = context; 27 | } 28 | 29 | @Override 30 | public void attachView(NewsMvpView mvpView) { 31 | super.attachView(mvpView); 32 | } 33 | 34 | @Override 35 | public void detachView() { 36 | super.detachView(); 37 | if (mSubscription != null) mSubscription.unsubscribe(); 38 | } 39 | 40 | public void getNews(String num, String page) { 41 | checkViewAttached(); 42 | if (isFirstReq) {//只在第一次请求时显示dialog 43 | showProgressDialog(); 44 | isFirstReq = false; 45 | } 46 | mSubscription = getApiService().news(num, page) 47 | .observeOn(AndroidSchedulers.mainThread()) 48 | .subscribeOn(Schedulers.io()) 49 | .subscribe(new Subscriber() { 50 | @Override 51 | public void onCompleted() { 52 | 53 | } 54 | 55 | @Override 56 | public void onError(Throwable e) { 57 | dissmissProgressDialog(); 58 | getMvpView().fail("获取新闻失败"); 59 | LogUtil.e("获取新闻失败>>" + e.getMessage()); 60 | } 61 | 62 | @Override 63 | public void onNext(NewsBean newsBean) { 64 | dissmissProgressDialog(); 65 | if (!newsBean.getShowapi_res_code().equals("0") 66 | || newsBean.getShowapi_res_body() == null 67 | || TextUtils.isEmpty(newsBean.getShowapi_res_body().getCode()) 68 | || !newsBean.getShowapi_res_body().getCode().equals("200")) { 69 | getMvpView().fail("获取新闻失败"); 70 | } else { 71 | if (page.equals("1")) {//刷新 72 | if (newsBean.getShowapi_res_body().getNewslist() == null 73 | || newsBean.getShowapi_res_body().getNewslist().size() <= 0) { 74 | getMvpView().fail("当前无新闻"); 75 | } else { 76 | getMvpView().refreshSuccess(newsBean); 77 | } 78 | } else {//加载更多 79 | if (newsBean.getShowapi_res_body().getNewslist() == null 80 | || newsBean.getShowapi_res_body().getNewslist().size() <= 0) { 81 | getMvpView().fail("没有更多数据啦"); 82 | } else { 83 | getMvpView().loadMoreSuccess(newsBean); 84 | } 85 | } 86 | 87 | } 88 | } 89 | }); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/presenter/base/BasePresenter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.presenter.base; 2 | 3 | import android.content.Context; 4 | 5 | import com.byl.mvpdemo.api.ApiService; 6 | import com.byl.mvpdemo.api.ApiUtil; 7 | import com.byl.mvpdemo.model.mvpview.base.MvpView; 8 | import com.byl.mvpdemo.view.MyProgressDialog; 9 | 10 | /** 11 | * Base class that implements the Presenter interface and provides a base implementation for 12 | * attachView() and detachView(). It also handles keeping a reference to the mvpView that 13 | * can be accessed from the children classes by calling getMvpView(). 14 | */ 15 | public class BasePresenter implements Presenter { 16 | 17 | public Context context; 18 | private T mMvpView; 19 | private ApiService apiService; 20 | private MyProgressDialog myProgressDialog; 21 | 22 | 23 | @Override 24 | public void attachView(T mvpView) { 25 | mMvpView = mvpView; 26 | apiService = ApiUtil.createApiService(); 27 | } 28 | 29 | @Override 30 | public void detachView() { 31 | mMvpView = null; 32 | } 33 | 34 | public boolean isViewAttached() { 35 | return mMvpView != null; 36 | } 37 | 38 | public T getMvpView() { 39 | return mMvpView; 40 | } 41 | 42 | public ApiService getApiService() { 43 | return apiService; 44 | } 45 | 46 | public void showProgressDialog() { 47 | if (context != null) { 48 | if (myProgressDialog == null) { 49 | myProgressDialog = new MyProgressDialog(context); 50 | } 51 | myProgressDialog.show(); 52 | } 53 | } 54 | 55 | public void dissmissProgressDialog() { 56 | if (myProgressDialog != null) { 57 | myProgressDialog.dismiss(); 58 | } 59 | } 60 | 61 | public void checkViewAttached() { 62 | if (!isViewAttached()) throw new MvpViewNotAttachedException(); 63 | } 64 | 65 | public static class MvpViewNotAttachedException extends RuntimeException { 66 | public MvpViewNotAttachedException() { 67 | super("使用Presenter前,请先调用attachView"); 68 | } 69 | } 70 | } 71 | 72 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/presenter/base/Presenter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.presenter.base; 2 | 3 | import com.byl.mvpdemo.model.mvpview.base.MvpView; 4 | 5 | /** 6 | * Every presenter in the app must either implement this interface or extend BasePresenter 7 | * indicating the MvpView type that wants to be attached with. 8 | */ 9 | public interface Presenter { 10 | 11 | void attachView(V mvpView); 12 | 13 | void detachView(); 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/base/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.base; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.support.v4.app.FragmentActivity; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.text.TextUtils; 10 | import android.view.View; 11 | import android.widget.ImageView; 12 | import android.widget.ProgressBar; 13 | import android.widget.RelativeLayout; 14 | import android.widget.TextView; 15 | 16 | import com.byl.mvpdemo.R; 17 | import com.byl.mvpdemo.api.ApiService; 18 | import com.byl.mvpdemo.api.ApiUtil; 19 | 20 | /** 21 | * Created by baiyuliang on 2016-7-14. 22 | */ 23 | public abstract class BaseActivity extends FragmentActivity implements View.OnClickListener { 24 | 25 | public Activity context; 26 | 27 | public RelativeLayout title_bar; 28 | public TextView tv_left, tv_title, tv_right; 29 | public ImageView iv_right; 30 | public ProgressBar pb; 31 | 32 | @Override 33 | protected void onCreate(Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | setContentView(getContentView()); 36 | context = this; 37 | initView(); 38 | initClick(); 39 | initData(); 40 | } 41 | 42 | /** 43 | * 初始化titlebar,该方法只有在标题栏布局符合此规则时才能调用 44 | * 45 | * @param left titlebar左按钮 46 | * @param title titlebar标题 47 | * @param right titlebar 右按钮 48 | * @param res titlebar 右图片按钮 49 | * @param onClickListener 左右按钮点击事件 50 | */ 51 | public void initTitleBar(String left, String title, String right, int res, View.OnClickListener onClickListener) { 52 | title_bar = (RelativeLayout) $(R.id.title_bar); 53 | title_bar.setBackgroundColor(getResources().getColor(R.color.common_title_bg)); 54 | tv_left = (TextView) $(R.id.tv_left);//返回按钮 55 | tv_title = (TextView) $(R.id.tv_title);//标题 56 | tv_right = (TextView) $(R.id.tv_right);//(右侧)按钮 57 | iv_right = (ImageView) $(R.id.iv_right);//右侧图片按钮 58 | 59 | pb = (ProgressBar) $(R.id.pb);// 标题栏数据加载ProgressBar 60 | 61 | if (!TextUtils.isEmpty(left)) { 62 | tv_left.setText(left); 63 | tv_left.setVisibility(View.VISIBLE); 64 | tv_left.setOnClickListener(onClickListener); 65 | } else { 66 | tv_left.setVisibility(View.GONE); 67 | } 68 | 69 | if (!TextUtils.isEmpty(title)) { 70 | tv_title.setText(title); 71 | tv_title.setVisibility(View.VISIBLE); 72 | } else { 73 | tv_title.setVisibility(View.GONE); 74 | } 75 | 76 | if (!TextUtils.isEmpty(right)) { 77 | tv_right.setText(right); 78 | tv_right.setVisibility(View.VISIBLE); 79 | tv_right.setOnClickListener(onClickListener); 80 | } else { 81 | tv_right.setVisibility(View.GONE); 82 | } 83 | 84 | if (res != 0) { 85 | iv_right.setImageResource(res); 86 | iv_right.setVisibility(View.VISIBLE); 87 | iv_right.setOnClickListener(onClickListener); 88 | } else { 89 | iv_right.setVisibility(View.GONE); 90 | } 91 | 92 | } 93 | 94 | /** 95 | * 设置布局文件 96 | * 97 | * @return 98 | */ 99 | public abstract int getContentView(); 100 | 101 | /** 102 | * 初始化View 103 | */ 104 | public abstract void initView(); 105 | 106 | /** 107 | * 设置点击事件 108 | */ 109 | public abstract void initClick(); 110 | 111 | /** 112 | * 初始化数据 113 | */ 114 | public abstract void initData(); 115 | 116 | public View $(int id) { 117 | return findViewById(id); 118 | } 119 | 120 | @Override 121 | public void onClick(View v) { 122 | switch (v.getId()) { 123 | case R.id.tv_left: 124 | finish(); 125 | } 126 | } 127 | 128 | public void startActivity(Class cla) { 129 | startActivity(new Intent(this, cla)); 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/base/BaseFragment.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.base; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.text.TextUtils; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.ImageView; 12 | import android.widget.ProgressBar; 13 | import android.widget.RelativeLayout; 14 | import android.widget.TextView; 15 | 16 | import com.byl.mvpdemo.R; 17 | 18 | /** 19 | * Created by baiyuliang on 2016-7-14. 20 | */ 21 | public abstract class BaseFragment extends Fragment implements View.OnClickListener { 22 | 23 | public Activity context; 24 | public View view; 25 | 26 | public RelativeLayout title_bar; 27 | public TextView tv_left, tv_title, tv_right; 28 | public ImageView iv_right; 29 | public ProgressBar pb; 30 | 31 | @Override 32 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 33 | context = getActivity(); 34 | if (view == null) { 35 | view = inflater.inflate(getContentView(), null); 36 | initView(); 37 | initClick(); 38 | initData(); 39 | } 40 | return view; 41 | } 42 | 43 | /** 44 | * 初始化titlebar,该方法只有在标题栏布局符合此规则时才能调用 45 | * 46 | * @param left titlebar左按钮 47 | * @param title titlebar标题 48 | * @param right titlebar 右按钮 49 | * @param res titlebar 右图片按钮 50 | * @param onClickListener 左右按钮点击事件 51 | */ 52 | public void initTitleBar(String left, String title, String right, int res, View.OnClickListener onClickListener) { 53 | title_bar = (RelativeLayout) $(R.id.title_bar); 54 | title_bar.setBackgroundColor(getResources().getColor(R.color.common_title_bg)); 55 | tv_left = (TextView) $(R.id.tv_left);//返回按钮 56 | tv_title = (TextView) $(R.id.tv_title);//标题 57 | tv_right = (TextView) $(R.id.tv_right);//(右侧)按钮 58 | iv_right = (ImageView) $(R.id.iv_right);//右侧图片按钮 59 | 60 | pb = (ProgressBar) $(R.id.pb);// 标题栏数据加载ProgressBar 61 | 62 | if (!TextUtils.isEmpty(left)) { 63 | tv_left.setText(left); 64 | tv_left.setVisibility(View.VISIBLE); 65 | tv_left.setOnClickListener(onClickListener); 66 | } else { 67 | tv_left.setVisibility(View.GONE); 68 | } 69 | 70 | if (!TextUtils.isEmpty(title)) { 71 | tv_title.setText(title); 72 | tv_title.setVisibility(View.VISIBLE); 73 | } else { 74 | tv_title.setVisibility(View.GONE); 75 | } 76 | 77 | if (!TextUtils.isEmpty(right)) { 78 | tv_right.setText(right); 79 | tv_right.setVisibility(View.VISIBLE); 80 | tv_right.setOnClickListener(onClickListener); 81 | } else { 82 | tv_right.setVisibility(View.GONE); 83 | } 84 | 85 | if (res != 0) { 86 | iv_right.setImageResource(res); 87 | iv_right.setVisibility(View.VISIBLE); 88 | iv_right.setOnClickListener(onClickListener); 89 | } else { 90 | iv_right.setVisibility(View.GONE); 91 | } 92 | 93 | } 94 | 95 | /** 96 | * 设置布局文件 97 | * 98 | * @return 99 | */ 100 | public abstract int getContentView(); 101 | 102 | /** 103 | * 初始化View 104 | */ 105 | public abstract void initView(); 106 | 107 | /** 108 | * 设置点击事件 109 | */ 110 | public abstract void initClick(); 111 | 112 | /** 113 | * 初始化数据 114 | */ 115 | public abstract void initData(); 116 | 117 | public View $(int id) { 118 | return view.findViewById(id); 119 | } 120 | 121 | 122 | } 123 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/images/FragmentImageTab1.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.images; 2 | 3 | import android.support.v7.widget.GridLayoutManager; 4 | import android.view.View; 5 | import android.widget.Toast; 6 | 7 | import com.byl.mvpdemo.R; 8 | import com.byl.mvpdemo.adapter.BaseAdapter; 9 | import com.byl.mvpdemo.adapter.ImagesAdapter; 10 | import com.byl.mvpdemo.model.modelbean.News; 11 | import com.byl.mvpdemo.model.modelbean.NewsBean; 12 | import com.byl.mvpdemo.model.mvpview.NewsMvpView; 13 | import com.byl.mvpdemo.presenter.ImagesPresenter; 14 | import com.byl.mvpdemo.ui.base.BaseFragment; 15 | import com.byl.mvpdemo.view.pullrecyclerview.PullBaseView; 16 | import com.byl.mvpdemo.view.pullrecyclerview.PullRecyclerView; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | 22 | /** 23 | * 24 | */ 25 | public class FragmentImageTab1 extends BaseFragment implements NewsMvpView, 26 | PullBaseView.OnHeaderRefreshListener, 27 | PullBaseView.OnFooterRefreshListener, 28 | BaseAdapter.OnItemClickListener, 29 | BaseAdapter.OnViewClickListener { 30 | 31 | PullRecyclerView mPullRecyclerView; 32 | ImagesAdapter imagesAdapter; 33 | List objectList; 34 | 35 | ImagesPresenter imagesPresenter; 36 | int page; 37 | 38 | @Override 39 | public int getContentView() { 40 | return R.layout.fragment_images_tab1; 41 | } 42 | 43 | @Override 44 | public void initView() { 45 | mPullRecyclerView = (PullRecyclerView) $(R.id.mPullRecyclerView); 46 | mPullRecyclerView.setOnHeaderRefreshListener(this);//设置下拉监听 47 | mPullRecyclerView.setOnFooterRefreshListener(this);//设置上拉监听 48 | mPullRecyclerView.setCanScrollAtRereshing(false);//设置正在刷新时是否可以滑动,默认不可滑动 49 | mPullRecyclerView.setCanPullDown(true);//设置是否可下拉 50 | mPullRecyclerView.setCanPullUp(true);//设置是否可上拉 51 | } 52 | 53 | @Override 54 | public void initClick() { 55 | 56 | } 57 | 58 | @Override 59 | public void initData() { 60 | objectList = new ArrayList<>(); 61 | imagesPresenter = new ImagesPresenter(context); 62 | imagesPresenter.attachView(this); 63 | imagesPresenter.getImages("20", String.valueOf(++page), "0"); 64 | } 65 | 66 | @Override 67 | public void onClick(View v) { 68 | 69 | } 70 | 71 | 72 | @Override 73 | public void onFooterRefresh(PullBaseView view) { 74 | imagesPresenter.getImages("20", String.valueOf(++page), "0"); 75 | } 76 | 77 | @Override 78 | public void onHeaderRefresh(PullBaseView view) { 79 | page = 0; 80 | imagesPresenter.getImages("20", String.valueOf(++page), "0"); 81 | } 82 | 83 | @Override 84 | public void refreshSuccess(NewsBean newsBean) { 85 | mPullRecyclerView.onHeaderRefreshComplete(); 86 | objectList.clear(); 87 | List list = newsBean.getShowapi_res_body().getNewslist(); 88 | for (News news : list) { 89 | objectList.add(news); 90 | } 91 | imagesAdapter = new ImagesAdapter(context, objectList, this); 92 | mPullRecyclerView.setLayoutManager(new GridLayoutManager(context, 2)); 93 | imagesAdapter.setOnItemClickListener(this); 94 | mPullRecyclerView.setAdapter(imagesAdapter); 95 | } 96 | 97 | @Override 98 | public void loadMoreSuccess(NewsBean newsBean) { 99 | mPullRecyclerView.onFooterRefreshComplete(); 100 | List list = newsBean.getShowapi_res_body().getNewslist(); 101 | for (News news : list) { 102 | objectList.add(news); 103 | } 104 | imagesAdapter.notifyDataSetChanged(); 105 | } 106 | 107 | @Override 108 | public void fail(String message) { 109 | Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); 110 | } 111 | 112 | @Override 113 | public void onItemClick(int position) { 114 | Toast.makeText(context, "item>>" + position, Toast.LENGTH_SHORT).show(); 115 | } 116 | 117 | @Override 118 | public void onViewClick(int position, int viewtype) { 119 | switch (viewtype) { 120 | case 1: 121 | Toast.makeText(context, "赞>>" + position, Toast.LENGTH_SHORT).show(); 122 | break; 123 | } 124 | } 125 | 126 | @Override 127 | public void onDestroy() { 128 | super.onDestroy(); 129 | imagesPresenter.detachView(); 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/images/FragmentImageTab2.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.images; 2 | 3 | import android.support.v7.widget.GridLayoutManager; 4 | import android.view.View; 5 | import android.widget.Toast; 6 | 7 | import com.byl.mvpdemo.R; 8 | import com.byl.mvpdemo.adapter.BaseAdapter; 9 | import com.byl.mvpdemo.adapter.ImagesAdapter; 10 | import com.byl.mvpdemo.model.modelbean.News; 11 | import com.byl.mvpdemo.model.modelbean.NewsBean; 12 | import com.byl.mvpdemo.model.mvpview.NewsMvpView; 13 | import com.byl.mvpdemo.presenter.ImagesPresenter; 14 | import com.byl.mvpdemo.ui.base.BaseFragment; 15 | import com.byl.mvpdemo.view.pullrecyclerview.PullBaseView; 16 | import com.byl.mvpdemo.view.pullrecyclerview.PullRecyclerView; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | 22 | /** 23 | * 24 | */ 25 | public class FragmentImageTab2 extends BaseFragment implements NewsMvpView, 26 | PullBaseView.OnHeaderRefreshListener, 27 | PullBaseView.OnFooterRefreshListener, 28 | BaseAdapter.OnItemClickListener, 29 | BaseAdapter.OnViewClickListener { 30 | 31 | PullRecyclerView mPullRecyclerView; 32 | ImagesAdapter imagesAdapter; 33 | List objectList; 34 | 35 | ImagesPresenter imagesPresenter; 36 | int page; 37 | 38 | @Override 39 | public int getContentView() { 40 | return R.layout.fragment_images_tab2; 41 | } 42 | 43 | @Override 44 | public void initView() { 45 | mPullRecyclerView = (PullRecyclerView) $(R.id.mPullRecyclerView); 46 | mPullRecyclerView.setOnHeaderRefreshListener(this);//设置下拉监听 47 | mPullRecyclerView.setOnFooterRefreshListener(this);//设置上拉监听 48 | mPullRecyclerView.setCanScrollAtRereshing(false);//设置正在刷新时是否可以滑动,默认不可滑动 49 | mPullRecyclerView.setCanPullDown(true);//设置是否可下拉 50 | mPullRecyclerView.setCanPullUp(true);//设置是否可上拉 51 | } 52 | 53 | @Override 54 | public void initClick() { 55 | 56 | } 57 | 58 | @Override 59 | public void initData() { 60 | objectList = new ArrayList<>(); 61 | imagesPresenter = new ImagesPresenter(context); 62 | imagesPresenter.attachView(this); 63 | imagesPresenter.getImages("20", String.valueOf(++page), "1"); 64 | } 65 | 66 | @Override 67 | public void onClick(View v) { 68 | 69 | } 70 | 71 | 72 | @Override 73 | public void onFooterRefresh(PullBaseView view) { 74 | imagesPresenter.getImages("20", String.valueOf(++page), "1"); 75 | } 76 | 77 | @Override 78 | public void onHeaderRefresh(PullBaseView view) { 79 | page = 0; 80 | imagesPresenter.getImages("20", String.valueOf(++page), "1"); 81 | } 82 | 83 | @Override 84 | public void refreshSuccess(NewsBean newsBean) { 85 | mPullRecyclerView.onHeaderRefreshComplete(); 86 | objectList.clear(); 87 | List list = newsBean.getShowapi_res_body().getNewslist(); 88 | for (News news : list) { 89 | objectList.add(news); 90 | } 91 | imagesAdapter = new ImagesAdapter(context, objectList, this); 92 | mPullRecyclerView.setLayoutManager(new GridLayoutManager(context, 2)); 93 | imagesAdapter.setOnItemClickListener(this); 94 | mPullRecyclerView.setAdapter(imagesAdapter); 95 | } 96 | 97 | @Override 98 | public void loadMoreSuccess(NewsBean newsBean) { 99 | mPullRecyclerView.onFooterRefreshComplete(); 100 | List list = newsBean.getShowapi_res_body().getNewslist(); 101 | for (News news : list) { 102 | objectList.add(news); 103 | } 104 | imagesAdapter.notifyDataSetChanged(); 105 | } 106 | 107 | @Override 108 | public void fail(String message) { 109 | Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); 110 | } 111 | 112 | @Override 113 | public void onItemClick(int position) { 114 | Toast.makeText(context, "item>>" + position, Toast.LENGTH_SHORT).show(); 115 | } 116 | 117 | @Override 118 | public void onViewClick(int position, int viewtype) { 119 | switch (viewtype) { 120 | case 1: 121 | Toast.makeText(context, "赞>>" + position, Toast.LENGTH_SHORT).show(); 122 | break; 123 | } 124 | } 125 | 126 | @Override 127 | public void onDestroy() { 128 | super.onDestroy(); 129 | imagesPresenter.detachView(); 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/login/LoginActivity.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.login; 2 | 3 | import android.text.TextUtils; 4 | import android.view.View; 5 | import android.widget.Button; 6 | import android.widget.EditText; 7 | import android.widget.Toast; 8 | 9 | import com.byl.mvpdemo.R; 10 | import com.byl.mvpdemo.model.modelbean.LoginBean; 11 | import com.byl.mvpdemo.model.mvpview.LoginMvpView; 12 | import com.byl.mvpdemo.presenter.LoginPresenter; 13 | import com.byl.mvpdemo.ui.base.BaseActivity; 14 | import com.byl.mvpdemo.ui.main.MainActivity; 15 | 16 | public class LoginActivity extends BaseActivity implements LoginMvpView { 17 | 18 | EditText et_account, et_pwd; 19 | Button btn_login; 20 | LoginPresenter loginPresenter; 21 | 22 | @Override 23 | public int getContentView() { 24 | return R.layout.activity_login; 25 | } 26 | 27 | @Override 28 | public void initView() { 29 | initTitleBar("", "登录", "注册", 0, this); 30 | title_bar.setBackgroundColor(getResources().getColor(R.color.common_title_bg)); 31 | et_account = (EditText) $(R.id.account); 32 | et_pwd = (EditText) $(R.id.password); 33 | btn_login = (Button) $(R.id.login); 34 | } 35 | 36 | @Override 37 | public void initClick() { 38 | btn_login.setOnClickListener(this); 39 | } 40 | 41 | @Override 42 | public void initData() { 43 | loginPresenter = new LoginPresenter(this); 44 | loginPresenter.attachView(this); 45 | } 46 | 47 | @Override 48 | public void onClick(View v) { 49 | super.onClick(v); 50 | switch (v.getId()) { 51 | case R.id.tv_right: 52 | Toast.makeText(LoginActivity.this, "注册", Toast.LENGTH_SHORT).show(); 53 | break; 54 | case R.id.login: 55 | doLogin(); 56 | break; 57 | } 58 | } 59 | 60 | /** 61 | * 登录 62 | */ 63 | void doLogin() { 64 | String account = et_account.getText().toString(); 65 | if (TextUtils.isEmpty(account)) { 66 | Toast.makeText(LoginActivity.this, "请输入您的手机号", Toast.LENGTH_SHORT).show(); 67 | return; 68 | } 69 | String pwd = et_pwd.getText().toString(); 70 | if (TextUtils.isEmpty(pwd)) { 71 | Toast.makeText(LoginActivity.this, "请输入您的密码", Toast.LENGTH_SHORT).show(); 72 | return; 73 | } 74 | loginPresenter.login(account); 75 | } 76 | 77 | @Override 78 | public void loginSuccess(LoginBean loginBean) { 79 | startActivity(MainActivity.class); 80 | finish(); 81 | Toast.makeText(LoginActivity.this, "登录成功", Toast.LENGTH_SHORT).show(); 82 | } 83 | 84 | @Override 85 | public void loginFail(String message) { 86 | Toast.makeText(LoginActivity.this, message, Toast.LENGTH_SHORT).show(); 87 | } 88 | 89 | @Override 90 | protected void onDestroy() { 91 | super.onDestroy(); 92 | loginPresenter.detachView(); 93 | } 94 | } 95 | 96 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/main/FragmentTab1.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.main; 2 | 3 | import android.support.v7.widget.LinearLayoutManager; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.util.Log; 6 | import android.view.View; 7 | import android.widget.ImageView; 8 | import android.widget.RelativeLayout; 9 | import android.widget.TextView; 10 | import android.widget.Toast; 11 | 12 | import com.byl.mvpdemo.R; 13 | import com.byl.mvpdemo.adapter.BaseAdapter; 14 | import com.byl.mvpdemo.adapter.NewsAdapter; 15 | import com.byl.mvpdemo.model.modelbean.ImageModel; 16 | import com.byl.mvpdemo.model.modelbean.News; 17 | import com.byl.mvpdemo.model.modelbean.NewsBean; 18 | import com.byl.mvpdemo.model.mvpview.NewsMvpView; 19 | import com.byl.mvpdemo.presenter.NewsPresenter; 20 | import com.byl.mvpdemo.ui.base.BaseFragment; 21 | import com.byl.mvpdemo.util.SysUtil; 22 | import com.byl.mvpdemo.view.pullrecyclerview.PullBaseView; 23 | import com.byl.mvpdemo.view.pullrecyclerview.PullRecyclerView; 24 | 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | 29 | public class FragmentTab1 extends BaseFragment implements 30 | BaseAdapter.OnItemClickListener, 31 | PullBaseView.OnHeaderRefreshListener, 32 | PullBaseView.OnFooterRefreshListener, 33 | PullBaseView.OnPullDownScrollListener, 34 | View.OnClickListener, 35 | BaseAdapter.OnViewClickListener, 36 | NewsMvpView { 37 | 38 | RelativeLayout rl_title; 39 | TextView tv_search; 40 | ImageView iv_qr;//二维码 41 | PullRecyclerView mRecyclerView; 42 | NewsAdapter newsAdapter; 43 | List listbanner, listnews; 44 | 45 | int y, //滑动距离 46 | bannerH;//banner高度 47 | boolean isPullDown = false;//是否是下拉状态 48 | 49 | NewsPresenter newsPresenter; 50 | int page; 51 | 52 | @Override 53 | public int getContentView() { 54 | return R.layout.fragment_1; 55 | } 56 | 57 | /** 58 | * 注意:rl_title.getBackground().setAlpha(0),设置标题栏背景透明度,会影响其它界面的背景, 59 | * 如果加上这个效果,那么其他界面的背景色在xml中设置将失效,需代码中动态设置, 60 | * 这个问题很奇葩,未找到原因, 61 | * 现在要么不要这个滑动改变透明度的效果,要么其他界面中的背景色就动态设置 62 | */ 63 | @Override 64 | public void initView() { 65 | rl_title = (RelativeLayout) $(R.id.rl_title);//标题栏 66 | rl_title.getBackground().setAlpha(0); 67 | tv_search = (TextView) $(R.id.tv_search); 68 | iv_qr = (ImageView) $(R.id.iv_qr); 69 | 70 | mRecyclerView = (PullRecyclerView) $(R.id.mRecyclerView); 71 | mRecyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER); 72 | mRecyclerView.setOnHeaderRefreshListener(this);//设置下拉监听 73 | mRecyclerView.setOnFooterRefreshListener(this);//设置上拉监听 74 | mRecyclerView.setOnPullDownScrollListener(this);//设置下拉滑动监听 75 | mRecyclerView.setCanScrollAtRereshing(false);//设置正在刷新时是否可以滑动,默认不可滑动 76 | mRecyclerView.setCanPullDown(true);//设置是否可下拉 77 | mRecyclerView.setCanPullUp(true);//设置是否可上拉 78 | mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { 79 | @Override 80 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 81 | super.onScrollStateChanged(recyclerView, newState); 82 | } 83 | 84 | @Override 85 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) {//监听滑动距离以改变标题栏透明度 86 | super.onScrolled(recyclerView, dx, dy); 87 | y += dy; 88 | if (y >= bannerH) { 89 | rl_title.getBackground().setAlpha(255); 90 | rl_title.setVisibility(View.VISIBLE); 91 | } else if (y >= 0 && y < bannerH) { 92 | if (isPullDown) { 93 | rl_title.setVisibility(View.GONE); 94 | } else { 95 | rl_title.getBackground().setAlpha((int) (255 * ((double) y / bannerH))); 96 | rl_title.setVisibility(View.VISIBLE); 97 | } 98 | } else { 99 | rl_title.getBackground().setAlpha(0); 100 | rl_title.setVisibility(View.GONE); 101 | } 102 | } 103 | }); 104 | } 105 | 106 | @Override 107 | public void initClick() { 108 | tv_search.setOnClickListener(this); 109 | iv_qr.setOnClickListener(this); 110 | } 111 | 112 | @Override 113 | public void initData() { 114 | bannerH = SysUtil.dip2px(context, 200);//将banner高度转为px 115 | listbanner = new ArrayList<>(); 116 | listnews = new ArrayList<>(); 117 | 118 | newsPresenter = new NewsPresenter(context); 119 | newsPresenter.attachView(this); 120 | newsPresenter.getNews("10", String.valueOf(++page)); 121 | 122 | initRecyclerView(); 123 | } 124 | 125 | void initRecyclerView() { 126 | newsAdapter = new NewsAdapter(context, listbanner, listnews, this); 127 | mRecyclerView.setLayoutManager(new LinearLayoutManager(context)); 128 | newsAdapter.setOnItemClickListener(this); 129 | mRecyclerView.setAdapter(newsAdapter); 130 | } 131 | 132 | @Override 133 | public void onClick(View v) { 134 | switch (v.getId()) { 135 | case R.id.tv_search: 136 | Toast.makeText(context, "搜索", Toast.LENGTH_SHORT).show(); 137 | break; 138 | case R.id.iv_qr: 139 | Toast.makeText(context, "二维码", Toast.LENGTH_SHORT).show(); 140 | break; 141 | } 142 | } 143 | 144 | /** 145 | * 上拉加载 146 | * 147 | * @param view 148 | */ 149 | @Override 150 | public void onFooterRefresh(PullBaseView view) { 151 | newsPresenter.getNews("10", String.valueOf(++page)); 152 | } 153 | 154 | /** 155 | * 下拉刷新 156 | * 157 | * @param view 158 | */ 159 | @Override 160 | public void onHeaderRefresh(PullBaseView view) { 161 | page = 0; 162 | newsPresenter.getNews("10", String.valueOf(++page)); 163 | } 164 | 165 | @Override 166 | public void onPullDownScrolled() { 167 | isPullDown = true; 168 | rl_title.setVisibility(View.GONE); 169 | } 170 | 171 | @Override 172 | public void onPullDownFinished() { 173 | isPullDown = false; 174 | rl_title.setVisibility(View.VISIBLE); 175 | } 176 | 177 | 178 | /** 179 | * item点击监听 180 | * 181 | * @param position 182 | */ 183 | @Override 184 | public void onItemClick(int position) { 185 | Toast.makeText(context, ((News) listnews.get(position)).getTitle(), Toast.LENGTH_SHORT).show(); 186 | } 187 | 188 | /** 189 | * @param position item position 190 | * @param viewtype 点击的view的类型,调用时根据不同的view传入不同的值加以区分 191 | */ 192 | @Override 193 | public void onViewClick(int position, int viewtype) { 194 | switch (viewtype) { 195 | case 1: 196 | Toast.makeText(context, "新闻1", Toast.LENGTH_SHORT).show(); 197 | break; 198 | case 2: 199 | Toast.makeText(context, "新闻2", Toast.LENGTH_SHORT).show(); 200 | break; 201 | case 3: 202 | Toast.makeText(context, "新闻3", Toast.LENGTH_SHORT).show(); 203 | break; 204 | case 4: 205 | Toast.makeText(context, "新闻4", Toast.LENGTH_SHORT).show(); 206 | break; 207 | } 208 | 209 | } 210 | 211 | /** 212 | * 下拉请求成功 213 | * 214 | * @param newsBean 215 | */ 216 | @Override 217 | public void refreshSuccess(NewsBean newsBean) { 218 | mRecyclerView.onHeaderRefreshComplete(); 219 | //banner 模拟数据 220 | listbanner.clear(); 221 | ImageModel imageModel = new ImageModel(); 222 | imageModel.setUrl("https://ss2.baidu.com/-vo3dSag_xI4khGko9WTAnF6hhy/image/h%3D200/sign=650d5402a318972bbc3a07cad6cd7b9d/9f2f070828381f305c3fe5bfa1014c086e06f086.jpg"); 223 | listbanner.add(imageModel); 224 | imageModel = new ImageModel(); 225 | imageModel.setUrl("https://ss0.baidu.com/7Po3dSag_xI4khGko9WTAnF6hhy/image/h%3D200/sign=a219dde79125bc31345d06986ede8de7/a5c27d1ed21b0ef494399077d5c451da80cb3ec1.jpg"); 226 | listbanner.add(imageModel); 227 | imageModel = new ImageModel(); 228 | imageModel.setUrl("https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2040796625,1810502195&fm=111&gp=0.jpg"); 229 | listbanner.add(imageModel); 230 | //news 真实数据 231 | listnews.clear(); 232 | List list = newsBean.getShowapi_res_body().getNewslist(); 233 | for (News news : list) { 234 | listnews.add(news); 235 | } 236 | initRecyclerView(); 237 | } 238 | 239 | @Override 240 | public void loadMoreSuccess(NewsBean newsBean) { 241 | mRecyclerView.onFooterRefreshComplete(); 242 | List list = newsBean.getShowapi_res_body().getNewslist(); 243 | for (News news : list) { 244 | listnews.add(news); 245 | } 246 | newsAdapter.notifyDataSetChanged(); 247 | } 248 | 249 | /** 250 | * 请求失败 251 | * 252 | * @param message 253 | */ 254 | @Override 255 | public void fail(String message) { 256 | mRecyclerView.onHeaderRefreshComplete(); 257 | mRecyclerView.onFooterRefreshComplete(); 258 | Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); 259 | } 260 | 261 | @Override 262 | public void onDestroy() { 263 | super.onDestroy(); 264 | newsPresenter.detachView(); 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/main/FragmentTab2.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.main; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.app.FragmentActivity; 5 | import android.support.v4.view.ViewPager; 6 | import android.view.View; 7 | import android.support.design.widget.TabLayout; 8 | import android.widget.Toast; 9 | 10 | import com.byl.mvpdemo.R; 11 | import com.byl.mvpdemo.ui.base.BaseFragment; 12 | import com.byl.mvpdemo.ui.main.adapter.FragmentVedioAdapter; 13 | import com.byl.mvpdemo.ui.images.FragmentImageTab1; 14 | import com.byl.mvpdemo.ui.images.FragmentImageTab2; 15 | import com.byl.mvpdemo.util.LogUtil; 16 | 17 | 18 | public class FragmentTab2 extends BaseFragment { 19 | 20 | TabLayout mTabLayout; 21 | ViewPager mViewPager; 22 | 23 | Fragment[] mFragments; 24 | String[] mTitles; 25 | FragmentVedioAdapter fragmentVedioAdapter; 26 | 27 | @Override 28 | public int getContentView() { 29 | return R.layout.fragment_2; 30 | } 31 | 32 | @Override 33 | public void initView() { 34 | initTitleBar("", "图片", "", R.mipmap.ic_search, this); 35 | mTabLayout = (TabLayout) $(R.id.mTabLayout); 36 | mTabLayout.setBackgroundColor(getResources().getColor(R.color.common_title_bg)); 37 | mViewPager = (ViewPager) $(R.id.mViewPager); 38 | } 39 | 40 | @Override 41 | public void initClick() { 42 | 43 | } 44 | 45 | @Override 46 | public void initData() { 47 | mFragments = new Fragment[]{new FragmentImageTab1(), new FragmentImageTab2()}; 48 | mTitles = new String[]{"美女1", "美女2"}; 49 | fragmentVedioAdapter = new FragmentVedioAdapter(context, ((FragmentActivity) context).getSupportFragmentManager(), mFragments, mTitles); 50 | mViewPager.setAdapter(fragmentVedioAdapter); 51 | mTabLayout.setupWithViewPager(mViewPager); 52 | mTabLayout.getTabAt(0).select(); 53 | } 54 | 55 | @Override 56 | public void onClick(View v) { 57 | switch (v.getId()) { 58 | case R.id.iv_right://标题栏右侧图标 59 | Toast.makeText(context, "搜索", Toast.LENGTH_SHORT).show(); 60 | break; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/main/FragmentTab3.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.main; 2 | 3 | import android.view.View; 4 | import android.widget.LinearLayout; 5 | import android.widget.RelativeLayout; 6 | 7 | import com.byl.mvpdemo.R; 8 | import com.byl.mvpdemo.ui.base.BaseFragment; 9 | import com.byl.mvpdemo.util.LogUtil; 10 | 11 | 12 | /** 13 | */ 14 | public class FragmentTab3 extends BaseFragment { 15 | 16 | LinearLayout ll_head; 17 | 18 | @Override 19 | public int getContentView() { 20 | return R.layout.fragment_3; 21 | } 22 | 23 | @Override 24 | public void initView() { 25 | initTitleBar("", "我的", "", 0, this); 26 | ll_head = (LinearLayout) $(R.id.ll_head); 27 | ll_head.setBackgroundColor(getResources().getColor(R.color.common_title_bg)); 28 | } 29 | 30 | @Override 31 | public void initClick() { 32 | 33 | } 34 | 35 | @Override 36 | public void initData() { 37 | LogUtil.e("FragmentTab3"); 38 | } 39 | 40 | @Override 41 | public void onClick(View v) { 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/main/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.main; 2 | 3 | import android.support.design.widget.TabLayout; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v4.view.ViewPager; 6 | 7 | import com.byl.mvpdemo.R; 8 | import com.byl.mvpdemo.ui.base.BaseActivity; 9 | import com.byl.mvpdemo.ui.main.adapter.FragmentMainTabAdapter; 10 | 11 | 12 | /** 13 | * 主页 14 | */ 15 | public class MainActivity extends BaseActivity { 16 | 17 | ViewPager viewPager; 18 | TabLayout tabLayout; 19 | 20 | private String[] mTabTitles; 21 | private Integer[] mTabIcons; 22 | private Fragment[] mFragments; 23 | private FragmentMainTabAdapter fragmentMainTabAdapter; 24 | 25 | @Override 26 | public int getContentView() { 27 | return R.layout.activity_main; 28 | } 29 | 30 | @Override 31 | public void initView() { 32 | viewPager = (ViewPager) $(R.id.vp_content); 33 | tabLayout = (TabLayout) $(R.id.tabl_navigation); 34 | } 35 | 36 | @Override 37 | public void initClick() { 38 | 39 | } 40 | 41 | @Override 42 | public void initData() { 43 | mTabTitles = new String[]{"新闻", "图片", "我的"}; 44 | mTabIcons = new Integer[]{R.drawable.tab1_selector, R.drawable.tab2_selector, R.drawable.tab3_selector}; 45 | mFragments = new Fragment[]{new FragmentTab1(), new FragmentTab2(), new FragmentTab3()}; 46 | setupViewPager(); 47 | setupTabLayout(); 48 | tabLayout.getTabAt(0).select(); 49 | } 50 | 51 | private void setupTabLayout() { 52 | tabLayout.setTabMode(TabLayout.MODE_FIXED); 53 | tabLayout.setTabGravity(TabLayout.GRAVITY_FILL); 54 | tabLayout.setupWithViewPager(viewPager); 55 | for (int i = 0; i < tabLayout.getTabCount(); i++) { 56 | TabLayout.Tab tab = tabLayout.getTabAt(i); 57 | tab.setCustomView(fragmentMainTabAdapter.getTabView(i)); 58 | } 59 | tabLayout.requestFocus(); 60 | } 61 | 62 | private void setupViewPager() { 63 | fragmentMainTabAdapter = new FragmentMainTabAdapter(context, getSupportFragmentManager(), mFragments, mTabTitles, mTabIcons); 64 | viewPager.setAdapter(fragmentMainTabAdapter); 65 | viewPager.setOffscreenPageLimit(2); 66 | } 67 | 68 | 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/main/adapter/FragmentMainTabAdapter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.main.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v4.app.FragmentManager; 6 | import android.support.v4.app.FragmentStatePagerAdapter; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.widget.ImageView; 10 | import android.widget.TextView; 11 | 12 | import com.byl.mvpdemo.R; 13 | 14 | public class FragmentMainTabAdapter extends FragmentStatePagerAdapter { 15 | private Context mContext; 16 | 17 | private Fragment[] mFragments = null; 18 | private String[] mFragmentTitles =null; 19 | private Integer[] mFragmentIcons = null; 20 | 21 | public FragmentMainTabAdapter(Context context, FragmentManager fm, Fragment[] fragments, String[] titles, Integer[] icons) { 22 | super(fm); 23 | this.mContext = context; 24 | mFragments = fragments; 25 | mFragmentTitles = titles; 26 | mFragmentIcons = icons; 27 | } 28 | 29 | @Override 30 | public Fragment getItem(int position) { 31 | return mFragments[position]; 32 | } 33 | 34 | @Override 35 | public int getCount() { 36 | return mFragments.length; 37 | } 38 | 39 | @Override 40 | public CharSequence getPageTitle(int position) { 41 | return mFragmentTitles[position]; 42 | } 43 | 44 | public View getTabView(int position) { 45 | View tab = LayoutInflater.from(mContext).inflate(R.layout.item_main_tab, null); 46 | TextView tabText = (TextView) tab.findViewById(R.id.tv_title); 47 | ImageView tabImage = (ImageView) tab.findViewById(R.id.iv_icon); 48 | tabText.setText(mFragmentTitles[position]); 49 | tabImage.setBackgroundResource(mFragmentIcons[position]); 50 | if (position == 0) { 51 | tab.setSelected(true); 52 | } 53 | return tab; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/main/adapter/FragmentVedioAdapter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.main.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v4.app.FragmentManager; 6 | import android.support.v4.app.FragmentStatePagerAdapter; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.widget.ImageView; 10 | import android.widget.TextView; 11 | 12 | import com.byl.mvpdemo.R; 13 | 14 | public class FragmentVedioAdapter extends FragmentStatePagerAdapter { 15 | private Context mContext; 16 | 17 | private Fragment[] mFragments = null; 18 | private String[] mFragmentTitles = null; 19 | 20 | public FragmentVedioAdapter(Context context, FragmentManager fm, Fragment[] fragments, String[] titles) { 21 | super(fm); 22 | this.mContext = context; 23 | mFragments = fragments; 24 | mFragmentTitles = titles; 25 | } 26 | 27 | @Override 28 | public Fragment getItem(int position) { 29 | return mFragments[position]; 30 | } 31 | 32 | @Override 33 | public int getCount() { 34 | return mFragments.length; 35 | } 36 | 37 | //此方法用来显示tab上的名字 38 | @Override 39 | public CharSequence getPageTitle(int position) { 40 | return mFragmentTitles[position]; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/util/LogUtil.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.util; 2 | 3 | import android.util.Log; 4 | 5 | public class LogUtil { 6 | 7 | public static final String LOG = "mvp"; 8 | 9 | public static boolean isShowLog = false;//true:打印log,false:不打印log 10 | 11 | public static void e(String message) { 12 | if (!isShowLog) return; 13 | Log.e(LOG, message); 14 | } 15 | 16 | public static void i(String message) { 17 | if (!isShowLog) return; 18 | Log.i(LOG, message); 19 | } 20 | 21 | public static void v(String message) { 22 | if (!isShowLog) return; 23 | Log.v(LOG, message); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/util/SysUtil.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.util; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * Created by baiyuliang on 2016-7-19. 7 | */ 8 | public class SysUtil { 9 | 10 | /** 11 | * 将dp转px 12 | * 13 | * @param context 14 | * @param dpValue 15 | * @return 16 | */ 17 | public static int dip2px(Context context, float dpValue) { 18 | final float scale = context.getResources().getDisplayMetrics().density; 19 | return (int) (dpValue * scale + 0.5f); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/view/MyLinearLayoutManager.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.view; 2 | 3 | /** 4 | * Created by baiyuliang on 2016-7-19. 5 | */ 6 | 7 | import android.content.Context; 8 | import android.support.v7.widget.LinearLayoutManager; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | 13 | public class MyLinearLayoutManager extends LinearLayoutManager { 14 | 15 | 16 | public MyLinearLayoutManager(Context context) { 17 | super(context); 18 | } 19 | 20 | public MyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { 21 | super(context, orientation, reverseLayout); 22 | } 23 | 24 | private int[] mMeasuredDimension = new int[2]; 25 | 26 | @Override 27 | public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, 28 | int widthSpec, int heightSpec) { 29 | 30 | final int widthMode = View.MeasureSpec.getMode(widthSpec); 31 | final int heightMode = View.MeasureSpec.getMode(heightSpec); 32 | final int widthSize = View.MeasureSpec.getSize(widthSpec); 33 | final int heightSize = View.MeasureSpec.getSize(heightSpec); 34 | 35 | int width = 0; 36 | int height = 0; 37 | for (int i = 0; i < getItemCount(); i++) { 38 | measureScrapChild(recycler, i, 39 | View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), 40 | View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), 41 | mMeasuredDimension); 42 | 43 | if (getOrientation() == HORIZONTAL) { 44 | width = width + mMeasuredDimension[0]; 45 | if (i == 0) { 46 | height = mMeasuredDimension[1]; 47 | } 48 | } else { 49 | height = height + mMeasuredDimension[1]; 50 | if (i == 0) { 51 | width = mMeasuredDimension[0]; 52 | } 53 | } 54 | } 55 | switch (widthMode) { 56 | case View.MeasureSpec.EXACTLY: 57 | width = widthSize; 58 | case View.MeasureSpec.AT_MOST: 59 | case View.MeasureSpec.UNSPECIFIED: 60 | } 61 | 62 | switch (heightMode) { 63 | case View.MeasureSpec.EXACTLY: 64 | height = heightSize; 65 | case View.MeasureSpec.AT_MOST: 66 | case View.MeasureSpec.UNSPECIFIED: 67 | } 68 | 69 | setMeasuredDimension(width, height); 70 | } 71 | 72 | private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, 73 | int heightSpec, int[] measuredDimension) { 74 | try { 75 | View view = recycler.getViewForPosition(0);//fix 动态添加时报IndexOutOfBoundsException 76 | 77 | if (view != null) { 78 | RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams(); 79 | 80 | int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, 81 | getPaddingLeft() + getPaddingRight(), p.width); 82 | 83 | int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, 84 | getPaddingTop() + getPaddingBottom(), p.height); 85 | 86 | view.measure(childWidthSpec, childHeightSpec); 87 | measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin; 88 | measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin; 89 | recycler.recycleView(view); 90 | } 91 | } catch (Exception e) { 92 | e.printStackTrace(); 93 | } finally { 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/view/MyProgressDialog.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.view; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Dialog; 5 | import android.content.Context; 6 | import android.os.Build; 7 | import android.view.View; 8 | import android.view.Window; 9 | import android.view.WindowManager; 10 | import android.view.animation.Animation; 11 | import android.view.animation.LinearInterpolator; 12 | import android.view.animation.RotateAnimation; 13 | import android.widget.ImageView; 14 | import android.widget.TextView; 15 | 16 | import com.byl.mvpdemo.R; 17 | 18 | 19 | /** 20 | * 21 | * Date: 2014-06-19 22 | * 23 | * @author byl 24 | */ 25 | public class MyProgressDialog extends Dialog { 26 | 27 | private ImageView iv_route; 28 | private TextView tv; 29 | private RotateAnimation mAnim; 30 | private boolean cancelable = true; 31 | 32 | 33 | public MyProgressDialog(Context context) { 34 | super(context, R.style.Dialog_bocop); 35 | init(); 36 | } 37 | 38 | @SuppressWarnings("ResourceType") 39 | private void init() { 40 | View contentView = View.inflate(getContext(), R.layout.loading_dialog, null); 41 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 42 | Window win = getWindow(); 43 | WindowManager.LayoutParams winParams = win.getAttributes(); 44 | winParams.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; 45 | win.setAttributes(winParams); 46 | } 47 | setContentView(contentView); 48 | 49 | contentView.setOnClickListener(new View.OnClickListener() { 50 | @Override 51 | public void onClick(View v) { 52 | if (cancelable) { 53 | dismiss(); 54 | } 55 | } 56 | }); 57 | iv_route = (ImageView) findViewById(R.id.iv_route); 58 | tv = (TextView) findViewById(R.id.tv); 59 | initAnim(); 60 | getWindow().setWindowAnimations(R.anim.alpha_in); 61 | } 62 | 63 | 64 | private void initAnim() { 65 | mAnim=new RotateAnimation(0, 359, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); 66 | mAnim.setDuration(1500); 67 | mAnim.setInterpolator(new LinearInterpolator()); 68 | mAnim.setFillAfter(true); 69 | mAnim.setRepeatCount(-1); 70 | } 71 | 72 | @Override 73 | public void show() { 74 | iv_route.startAnimation(mAnim); 75 | super.show(); 76 | } 77 | 78 | @SuppressLint("NewApi") 79 | @Override 80 | public void dismiss() { 81 | mAnim.cancel(); 82 | super.dismiss(); 83 | } 84 | 85 | 86 | @Override 87 | public void setCancelable(boolean flag) { 88 | cancelable = flag; 89 | super.setCancelable(flag); 90 | } 91 | 92 | @Override 93 | public void setTitle(CharSequence title) { 94 | tv.setText(title); 95 | } 96 | 97 | public void setMessage(String title) { 98 | tv.setText(title); 99 | } 100 | 101 | @Override 102 | public void setTitle(int titleId) { 103 | setTitle(getContext().getString(titleId)); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/view/pullrecyclerview/PullBaseView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.view.pullrecyclerview; 2 | 3 | import android.content.Context; 4 | import android.graphics.drawable.AnimationDrawable; 5 | import android.support.v7.widget.LinearLayoutManager; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.util.AttributeSet; 8 | import android.view.LayoutInflater; 9 | import android.view.MotionEvent; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.LinearLayout; 13 | import android.widget.ProgressBar; 14 | import android.widget.TextView; 15 | 16 | import com.byl.mvpdemo.R; 17 | 18 | 19 | /** 20 | * 基类:重写LinearLayout,在LinearLayout中依次添加headerview-RecyclerView-footerview, 21 | * 并对LinearLayout进行手势监听 22 | * http://blog.csdn.net/baiyuliang2013 23 | */ 24 | public abstract class PullBaseView extends LinearLayout { 25 | 26 | protected T mRecyclerView; 27 | private boolean isCanScrollAtRereshing = false;//刷新时是否可滑动 28 | private boolean isCanPullDown = true;//是否可下拉 29 | private boolean isCanPullUp = true;//是否可上拉 30 | 31 | // pull state 32 | private static final int PULL_DOWN_STATE = 0;//下拉 33 | private static final int PULL_UP_STATE = 1;//上拉 34 | // refresh states 35 | private static final int PULL_TO_REFRESH = 2;//未达到刷新条件 36 | private static final int RELEASE_TO_REFRESH = 3;//已达到刷新条件 37 | private static final int REFRESHING = 4;//正在刷新 38 | 39 | private int mLastMotionY;//last y 40 | private View mHeaderView;//HeaderView 41 | private View mFooterView;//FooterView 42 | private int mHeaderViewHeight;//HeaderView的高度 43 | private int mFooterViewHeight;//FooterView的高度 44 | private TextView mFooterTextView;//FooterView提示语 45 | private ProgressBar mFooterProgressBar;//FooterView ProgressBar 46 | 47 | private int mHeaderState;//HeaderView当前刷新状态 48 | private int mFooterState;//FooterView当前刷新状态 49 | private int mPullState;//刷新状态:下拉或上拉 50 | 51 | private OnHeaderRefreshListener mOnHeaderRefreshListener;//HeaderView刷新监听 52 | private OnFooterRefreshListener mOnFooterRefreshListener;//FooterView刷新监听 53 | private OnPullDownScrollListener onPullDownScrollListener; 54 | 55 | private float startY;//手指落点 56 | private float offsetY;//手指滑动的距离 57 | 58 | //headview中的动画实现 59 | private RefreshAnimView refreshAnimView; 60 | private RefreshLoadingView refreshLoadingView; 61 | private AnimationDrawable loadAnimation; 62 | 63 | private LayoutInflater mInflater; 64 | 65 | public PullBaseView(Context context) { 66 | super(context); 67 | } 68 | 69 | public PullBaseView(Context context, AttributeSet attrs) { 70 | super(context, attrs); 71 | init(context, attrs); 72 | } 73 | 74 | /** 75 | * init 76 | */ 77 | private void init(Context context, AttributeSet attrs) { 78 | mInflater = LayoutInflater.from(getContext()); 79 | addHeaderView();//首先在Linear中添加headview 80 | mRecyclerView = createRecyclerView(context, attrs); 81 | mRecyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER); 82 | addView(mRecyclerView);//添加RecyclerView 83 | } 84 | 85 | /** 86 | * header view 87 | */ 88 | private void addHeaderView() { 89 | mHeaderView = mInflater.inflate(R.layout.refresh_header, this, false); 90 | refreshAnimView = (RefreshAnimView) mHeaderView.findViewById(R.id.first_step_view); 91 | refreshLoadingView = (RefreshLoadingView) mHeaderView.findViewById(R.id.second_step_view); 92 | refreshLoadingView.setBackgroundResource(R.drawable.anim_refresh); 93 | loadAnimation = (AnimationDrawable) refreshLoadingView.getBackground(); 94 | measureView(mHeaderView);//测量高度 95 | mHeaderViewHeight = mHeaderView.getMeasuredHeight(); 96 | LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mHeaderViewHeight); 97 | params.topMargin = -(mHeaderViewHeight);// 设置topMargin的值为负的header View高度,即将其隐藏在最上方 98 | addView(mHeaderView, params); 99 | 100 | } 101 | 102 | /** 103 | * footer view 104 | */ 105 | private void addFooterView() { 106 | mFooterView = mInflater.inflate(R.layout.refresh_footer, this, false); 107 | mFooterTextView = (TextView) mFooterView.findViewById(R.id.pull_to_load_text); 108 | mFooterProgressBar = (ProgressBar) mFooterView.findViewById(R.id.pull_to_load_progress); 109 | measureView(mFooterView); 110 | mFooterViewHeight = mFooterView.getMeasuredHeight(); 111 | LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mFooterViewHeight); 112 | addView(mFooterView, params); 113 | } 114 | 115 | @Override 116 | protected void onFinishInflate() { 117 | super.onFinishInflate(); 118 | addFooterView();//最后添加footview 119 | } 120 | 121 | /** 122 | * dispatchTouchEvent 在最顶级也就是父布局(Linear)中拦截手势监听 123 | * 1.处理正在刷新时是否可以滑动 124 | * 2.处理头部动画 125 | * 126 | * @param ev 127 | * @return 128 | */ 129 | @Override 130 | public boolean dispatchTouchEvent(MotionEvent ev) { 131 | switch (ev.getAction()) { 132 | case MotionEvent.ACTION_DOWN: 133 | startY = ev.getY(); 134 | break; 135 | case MotionEvent.ACTION_MOVE: 136 | offsetY = ev.getY() - startY; 137 | if (!isCanScrollAtRereshing) { 138 | if (mHeaderState == REFRESHING || mFooterState == REFRESHING) { 139 | return true; 140 | } 141 | } 142 | if (isCanPullUp && offsetY > 0) { 143 | float headerViewShowHeight = offsetY * 0.3f;//headview露出的高度 144 | float currentProgress = headerViewShowHeight / mHeaderViewHeight;//根据此比例,在滑动时改变动图大小 145 | if (currentProgress >= 1) { 146 | currentProgress = 1; 147 | } 148 | if (mHeaderState == PULL_TO_REFRESH || mHeaderState == RELEASE_TO_REFRESH) { 149 | refreshAnimView.setCurrentProgress(currentProgress);//绘制headview中的动画 150 | refreshAnimView.postInvalidate(); 151 | } 152 | } 153 | break; 154 | } 155 | return super.dispatchTouchEvent(ev); 156 | } 157 | 158 | @Override 159 | public boolean onInterceptTouchEvent(MotionEvent e) { 160 | int y = (int) e.getRawY(); 161 | switch (e.getAction()) { 162 | case MotionEvent.ACTION_DOWN: 163 | mLastMotionY = y;// 首先拦截down事件,记录y坐标 164 | break; 165 | case MotionEvent.ACTION_MOVE: 166 | int deltaY = y - mLastMotionY; // deltaY > 0 是向下运动,< 0是向上运动 167 | if (isRefreshViewScroll(deltaY)) { 168 | return true; 169 | } 170 | break; 171 | } 172 | return false; 173 | } 174 | 175 | /** 176 | * 如果在onInterceptTouchEvent()方法中没有拦截(即onInterceptTouchEvent()方法中 return false), 177 | * 则由PullBaseView的子View来处理;否则由下面的方法来处理(即由PullBaseView自己来处理) 178 | */ 179 | @Override 180 | public boolean onTouchEvent(MotionEvent event) { 181 | int y = (int) event.getRawY(); 182 | switch (event.getAction()) { 183 | case MotionEvent.ACTION_MOVE: 184 | int deltaY = y - mLastMotionY; 185 | if (isCanPullDown && mPullState == PULL_DOWN_STATE) { 186 | if (onPullDownScrollListener != null) { 187 | onPullDownScrollListener.onPullDownScrolled(); 188 | } 189 | headerPrepareToRefresh(deltaY); 190 | } else if (isCanPullUp && mPullState == PULL_UP_STATE) { 191 | footerPrepareToRefresh(deltaY); 192 | } 193 | mLastMotionY = y; 194 | break; 195 | case MotionEvent.ACTION_UP: 196 | case MotionEvent.ACTION_CANCEL: 197 | int topMargin = getHeaderTopMargin(); 198 | if (isCanPullDown && mPullState == PULL_DOWN_STATE) { 199 | if (topMargin >= 0) { 200 | headerRefreshing(); // 开始刷新 201 | } else { 202 | if (onPullDownScrollListener != null) { 203 | onPullDownScrollListener.onPullDownFinished(); 204 | } 205 | setHeaderTopMargin(-mHeaderViewHeight); // 还没有执行刷新,重新隐藏 206 | } 207 | } else if (isCanPullUp && mPullState == PULL_UP_STATE) { 208 | if (Math.abs(topMargin) >= mHeaderViewHeight + mFooterViewHeight) { 209 | footerRefreshing();// 开始执行footer 刷新 210 | } else { 211 | setHeaderTopMargin(-mHeaderViewHeight);// 还没有执行刷新,重新隐藏 212 | } 213 | } 214 | break; 215 | } 216 | return super.onTouchEvent(event); 217 | } 218 | 219 | /** 220 | * 是否应该到了父View,即PullBaseView滑动 221 | * 222 | * @param deltaY , deltaY > 0 是向下运动,< 0是向上运动 223 | * @return 224 | */ 225 | private boolean isRefreshViewScroll(int deltaY) { 226 | if (mHeaderState == REFRESHING || mFooterState == REFRESHING) { 227 | return false; 228 | } 229 | if (deltaY >= -20 && deltaY <= 20) 230 | return false; 231 | 232 | if (mRecyclerView != null) { 233 | // 滑动到最顶端 234 | if (deltaY > 0) { 235 | View child = mRecyclerView.getChildAt(0); 236 | if (child == null) { 237 | // mRecyclerView,不拦截 238 | return false; 239 | } 240 | if (isScrollTop() && child.getTop() == 0) { 241 | mPullState = PULL_DOWN_STATE; 242 | return true; 243 | } 244 | int top = child.getTop(); 245 | int padding = mRecyclerView.getPaddingTop(); 246 | if (isScrollTop() && Math.abs(top - padding) <= 8) { 247 | mPullState = PULL_DOWN_STATE; 248 | return true; 249 | } 250 | 251 | } else if (deltaY < 0) { 252 | View lastChild = mRecyclerView.getChildAt(mRecyclerView.getChildCount() - 1); 253 | if (lastChild == null) { 254 | // mRecyclerView,不拦截 255 | return false; 256 | } 257 | // 最后一个子view的Bottom小于父View的高度说明mRecyclerView的数据没有填满父view, 258 | // 等于父View的高度说明mRecyclerView已经滑动到最后 259 | if (lastChild.getBottom() <= getHeight() && isScrollBottom()) { 260 | mPullState = PULL_UP_STATE; 261 | return true; 262 | } 263 | } 264 | } 265 | return false; 266 | } 267 | 268 | /** 269 | * 判断mRecyclerView是否滑动到顶部 270 | * 271 | * @return 272 | */ 273 | boolean isScrollTop() { 274 | LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager(); 275 | if (linearLayoutManager.findFirstVisibleItemPosition() == 0) { 276 | return true; 277 | } else { 278 | return false; 279 | } 280 | } 281 | 282 | /** 283 | * 判断mRecyclerView是否滑动到底部 284 | * 285 | * @return 286 | */ 287 | boolean isScrollBottom() { 288 | LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager(); 289 | if (linearLayoutManager.findLastVisibleItemPosition() == (mRecyclerView.getAdapter().getItemCount() - 1)) { 290 | return true; 291 | } else { 292 | return false; 293 | } 294 | } 295 | 296 | /** 297 | * header 准备刷新,手指移动过程,还没有释放 298 | * 299 | * @param deltaY ,手指滑动的距离 300 | */ 301 | private void headerPrepareToRefresh(int deltaY) { 302 | int newTopMargin = changingHeaderViewTopMargin(deltaY); 303 | // 当header view的topMargin>=0时,说明已经完全显示出来了,修改header view 的提示状态 304 | if (newTopMargin >= 0 && mHeaderState != RELEASE_TO_REFRESH) { 305 | mHeaderState = RELEASE_TO_REFRESH; 306 | } else if (newTopMargin < 0 && newTopMargin > -mHeaderViewHeight) {// 拖动时没有释放 307 | mHeaderState = PULL_TO_REFRESH; 308 | } 309 | } 310 | 311 | /** 312 | * footer 准备刷新,手指移动过程,还没有释放 移动footer view高度同样和移动header view 313 | * 高度是一样,都是通过修改header view的topmargin的值来达到 314 | * 315 | * @param deltaY ,手指滑动的距离 316 | */ 317 | private void footerPrepareToRefresh(int deltaY) { 318 | int newTopMargin = changingHeaderViewTopMargin(deltaY); 319 | // 如果header view topMargin 的绝对值大于或等于header + footer 的高度 320 | // 说明footer view 完全显示出来了,修改footer view 的提示状态 321 | if (Math.abs(newTopMargin) >= (mHeaderViewHeight + mFooterViewHeight) && mFooterState != RELEASE_TO_REFRESH) { 322 | mFooterTextView.setText(R.string.pull_to_refresh_footer_release_label); 323 | mFooterState = RELEASE_TO_REFRESH; 324 | } else if (Math.abs(newTopMargin) < (mHeaderViewHeight + mFooterViewHeight)) { 325 | mFooterTextView.setText(R.string.pull_to_refresh_footer_pull_label); 326 | mFooterState = PULL_TO_REFRESH; 327 | } 328 | } 329 | 330 | /** 331 | * 修改Header view top margin的值 332 | * 333 | * @param deltaY 334 | */ 335 | private int changingHeaderViewTopMargin(int deltaY) { 336 | LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams(); 337 | float newTopMargin = params.topMargin + deltaY * 0.3f; 338 | // 这里对上拉做一下限制,因为当前上拉后然后不释放手指直接下拉,会把下拉刷新给触发了 339 | // 表示如果是在上拉后一段距离,然后直接下拉 340 | if (deltaY > 0 && mPullState == PULL_UP_STATE && Math.abs(params.topMargin) <= mHeaderViewHeight) { 341 | return params.topMargin; 342 | } 343 | // 同样地,对下拉做一下限制,避免出现跟上拉操作时一样的bug 344 | if (deltaY < 0 && mPullState == PULL_DOWN_STATE && Math.abs(params.topMargin) >= mHeaderViewHeight) { 345 | return params.topMargin; 346 | } 347 | params.topMargin = (int) newTopMargin; 348 | mHeaderView.setLayoutParams(params); 349 | invalidate(); 350 | return params.topMargin; 351 | } 352 | 353 | /** 354 | * header refreshing 355 | */ 356 | public void headerRefreshing() { 357 | mHeaderState = REFRESHING; 358 | setHeaderTopMargin(0); 359 | refreshAnimView.setVisibility(View.GONE); 360 | refreshLoadingView.setVisibility(View.VISIBLE); 361 | loadAnimation.start(); 362 | if (mOnHeaderRefreshListener != null) { 363 | mOnHeaderRefreshListener.onHeaderRefresh(this); 364 | } 365 | } 366 | 367 | /** 368 | * footer refreshing 369 | */ 370 | private void footerRefreshing() { 371 | mFooterState = REFRESHING; 372 | int top = mHeaderViewHeight + mFooterViewHeight; 373 | setHeaderTopMargin(-top); 374 | mFooterTextView.setText(R.string.pull_to_refresh_footer_refreshing_label); 375 | mFooterProgressBar.setVisibility(View.VISIBLE); 376 | if (mOnFooterRefreshListener != null) { 377 | mOnFooterRefreshListener.onFooterRefresh(this); 378 | } 379 | } 380 | 381 | /** 382 | * 设置header view 的topMargin的值 383 | * 384 | * @param topMargin ,为0时,说明header view 刚好完全显示出来; 为-mHeaderViewHeight时,说明完全隐藏了 385 | */ 386 | private void setHeaderTopMargin(int topMargin) { 387 | LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams(); 388 | params.topMargin = topMargin; 389 | mHeaderView.setLayoutParams(params); 390 | invalidate(); 391 | } 392 | 393 | /** 394 | * header view 完成更新后恢复初始状态 395 | */ 396 | public void onHeaderRefreshComplete() { 397 | setHeaderTopMargin(-mHeaderViewHeight); 398 | refreshAnimView.setVisibility(View.VISIBLE); 399 | refreshLoadingView.setVisibility(View.GONE); 400 | loadAnimation.stop(); 401 | mHeaderState = PULL_TO_REFRESH; 402 | if (onPullDownScrollListener != null) { 403 | onPullDownScrollListener.onPullDownFinished(); 404 | } 405 | } 406 | 407 | 408 | /** 409 | * footer view 完成更新后恢复初始状态 410 | */ 411 | public void onFooterRefreshComplete() { 412 | setHeaderTopMargin(-mHeaderViewHeight); 413 | mFooterTextView.setText(R.string.pull_to_refresh_footer_pull_label); 414 | mFooterProgressBar.setVisibility(View.GONE); 415 | mFooterState = PULL_TO_REFRESH; 416 | if (mRecyclerView != null) { 417 | mRecyclerView.scrollToPosition(mRecyclerView.getAdapter().getItemCount() - 1); 418 | } 419 | 420 | } 421 | 422 | /** 423 | * 获取当前header view 的topMargin 424 | */ 425 | private int getHeaderTopMargin() { 426 | LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams(); 427 | return params.topMargin; 428 | } 429 | 430 | 431 | /** 432 | * 设置下拉监听接口 433 | */ 434 | public void setOnHeaderRefreshListener(OnHeaderRefreshListener headerRefreshListener) { 435 | mOnHeaderRefreshListener = headerRefreshListener; 436 | } 437 | 438 | /** 439 | * 设置上拉监听接口 440 | */ 441 | public void setOnFooterRefreshListener(OnFooterRefreshListener footerRefreshListener) { 442 | mOnFooterRefreshListener = footerRefreshListener; 443 | } 444 | 445 | /** 446 | * 上拉监听 447 | */ 448 | public interface OnFooterRefreshListener { 449 | void onFooterRefresh(PullBaseView view); 450 | } 451 | 452 | /** 453 | * 下拉监听 454 | */ 455 | public interface OnHeaderRefreshListener { 456 | void onHeaderRefresh(PullBaseView view); 457 | } 458 | 459 | /** 460 | * 下拉滑动动作监听 461 | */ 462 | public interface OnPullDownScrollListener { 463 | void onPullDownScrolled(); 464 | 465 | void onPullDownFinished(); 466 | } 467 | 468 | public void setOnPullDownScrollListener(OnPullDownScrollListener onPullDownScrollListener) { 469 | this.onPullDownScrollListener = onPullDownScrollListener; 470 | } 471 | 472 | /** 473 | * 设置是否可以在刷新时滑动 474 | * 475 | * @param canScrollAtRereshing 476 | */ 477 | public void setCanScrollAtRereshing(boolean canScrollAtRereshing) { 478 | isCanScrollAtRereshing = canScrollAtRereshing; 479 | } 480 | 481 | /** 482 | * 设置是否可上拉 483 | * 484 | * @param canPullUp 485 | */ 486 | public void setCanPullUp(boolean canPullUp) { 487 | isCanPullUp = canPullUp; 488 | } 489 | 490 | /** 491 | * 设置是否可下拉 492 | * 493 | * @param canPullDown 494 | */ 495 | public void setCanPullDown(boolean canPullDown) { 496 | isCanPullDown = canPullDown; 497 | } 498 | 499 | private void measureView(View child) { 500 | ViewGroup.LayoutParams p = child.getLayoutParams(); 501 | if (p == null) { 502 | p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); 503 | } 504 | int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width); 505 | int lpHeight = p.height; 506 | int childHeightSpec; 507 | if (lpHeight > 0) { 508 | childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); 509 | } else { 510 | childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 511 | } 512 | child.measure(childWidthSpec, childHeightSpec); 513 | } 514 | 515 | 516 | /** 517 | * 抽象方法,子类实现,传入View 518 | * 519 | * @param context 520 | * @param attrs 521 | * @return 522 | */ 523 | protected abstract T createRecyclerView(Context context, AttributeSet attrs); 524 | 525 | } 526 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/view/pullrecyclerview/PullRecyclerView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.view.pullrecyclerview; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.util.AttributeSet; 6 | 7 | /** 8 | * RecyclerView中的所有方法都可以在此类中设置,暴露出去以供调用 9 | */ 10 | public class PullRecyclerView extends PullBaseView { 11 | 12 | 13 | public PullRecyclerView(Context context) { 14 | this(context, null); 15 | } 16 | 17 | public PullRecyclerView(Context context, AttributeSet attrs) { 18 | super(context, attrs); 19 | } 20 | 21 | 22 | @Override 23 | protected RecyclerView createRecyclerView(Context context, AttributeSet attrs) { 24 | return new RecyclerView(context, attrs); 25 | } 26 | 27 | public void setAdapter(RecyclerView.Adapter adapter) { 28 | mRecyclerView.setAdapter(adapter); 29 | } 30 | 31 | public void setLayoutManager(RecyclerView.LayoutManager manager) { 32 | mRecyclerView.setLayoutManager(manager); 33 | } 34 | 35 | public void addOnScrollListener(RecyclerView.OnScrollListener onScrollListener) { 36 | mRecyclerView.addOnScrollListener(onScrollListener); 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/view/pullrecyclerview/RefreshAnimView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.view.pullrecyclerview; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.graphics.Canvas; 7 | import android.graphics.Paint; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | 11 | import com.byl.mvpdemo.R; 12 | 13 | 14 | public class RefreshAnimView extends View{ 15 | 16 | private Bitmap daishu; 17 | private int measuredWidth; 18 | private int measuredHeight; 19 | private float mCurrentProgress; 20 | private int mCurrentAlpha; 21 | private Paint mPaint; 22 | private Bitmap scaleDaishu; 23 | 24 | public RefreshAnimView(Context context, AttributeSet attrs, int defStyle) { 25 | super(context, attrs, defStyle); 26 | init(); 27 | } 28 | 29 | public RefreshAnimView(Context context, AttributeSet attrs) { 30 | super(context, attrs); 31 | init(); 32 | } 33 | 34 | public RefreshAnimView(Context context) { 35 | super(context); 36 | init(); 37 | } 38 | private void init(){ 39 | //袋鼠bitmap 40 | daishu = BitmapFactory.decodeResource(getResources(), R.mipmap.takeout_img_list_loading_pic1); 41 | //来个画笔,我们注意到袋鼠都有一个渐变效果的,我们用 42 | //mPaint.setAlpha来实现这个渐变的效果 43 | mPaint = new Paint(); 44 | //首先设置为完全透明 45 | mPaint.setAlpha(0); 46 | } 47 | 48 | /** 49 | * 测量方法 50 | * @param widthMeasureSpec 51 | * @param heightMeasureSpec 52 | */ 53 | @Override 54 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 55 | setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); 56 | } 57 | //测量宽度 58 | private int measureWidth(int widthMeasureSpec){ 59 | int result = 0; 60 | int size = MeasureSpec.getSize(widthMeasureSpec); 61 | int mode = MeasureSpec.getMode(widthMeasureSpec); 62 | if (MeasureSpec.EXACTLY == mode) { 63 | result = size; 64 | }else { 65 | result = daishu.getWidth(); 66 | if (MeasureSpec.AT_MOST == mode) { 67 | result = Math.min(result, size); 68 | } 69 | } 70 | return result; 71 | } 72 | //测量高度 73 | private int measureHeight(int heightMeasureSpec){ 74 | int result = 0; 75 | int size = MeasureSpec.getSize(heightMeasureSpec); 76 | int mode = MeasureSpec.getMode(heightMeasureSpec); 77 | if (MeasureSpec.EXACTLY == mode) { 78 | result = size; 79 | }else { 80 | result = daishu.getHeight(); 81 | if (MeasureSpec.AT_MOST == mode) { 82 | result = Math.min(result, size); 83 | } 84 | } 85 | return result; 86 | } 87 | //在这里面拿到测量后的宽和高,w就是测量后的宽,h是测量后的高 88 | @Override 89 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 90 | super.onSizeChanged(w, h, oldw, oldh); 91 | measuredWidth = w; 92 | measuredHeight = h; 93 | //根据测量后的宽高来对袋鼠做一个缩放 94 | scaleDaishu = Bitmap.createScaledBitmap(daishu,measuredWidth,measuredHeight,true); 95 | } 96 | 97 | /** 98 | * 绘制方法 99 | * @param canvas 100 | */ 101 | @Override 102 | protected void onDraw(Canvas canvas) { 103 | super.onDraw(canvas); 104 | canvas.scale(mCurrentProgress, mCurrentProgress, measuredWidth/2, measuredHeight); 105 | mPaint.setAlpha(mCurrentAlpha); 106 | canvas.drawBitmap(scaleDaishu, 0, 0, mPaint); 107 | } 108 | 109 | /** 110 | * 根据进度对袋鼠进行缩放 111 | * @param currentProgress 112 | */ 113 | public void setCurrentProgress(float currentProgress){ 114 | this.mCurrentProgress = currentProgress; 115 | this.mCurrentAlpha = (int) (currentProgress*255); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/view/pullrecyclerview/RefreshLoadingView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.view.pullrecyclerview; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.util.AttributeSet; 7 | import android.view.View; 8 | 9 | import com.byl.mvpdemo.R; 10 | 11 | 12 | public class RefreshLoadingView extends View { 13 | 14 | private Bitmap endBitmap; 15 | 16 | public RefreshLoadingView(Context context, AttributeSet attrs, int defStyle) { 17 | super(context, attrs, defStyle); 18 | init(); 19 | } 20 | 21 | public RefreshLoadingView(Context context, AttributeSet attrs) { 22 | super(context, attrs); 23 | init(); 24 | } 25 | 26 | public RefreshLoadingView(Context context) { 27 | super(context); 28 | init(); 29 | } 30 | 31 | private void init() { 32 | endBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.takeout_img_list_loading_pic1); 33 | } 34 | 35 | /** 36 | * 只需要测量方法 37 | * 38 | * @param widthMeasureSpec 39 | * @param heightMeasureSpec 40 | */ 41 | @Override 42 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 43 | setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); 44 | } 45 | 46 | private int measureWidth(int widthMeasureSpec) { 47 | int result = 0; 48 | int size = MeasureSpec.getSize(widthMeasureSpec); 49 | int mode = MeasureSpec.getMode(widthMeasureSpec); 50 | if (MeasureSpec.EXACTLY == mode) { 51 | result = size; 52 | } else { 53 | result = endBitmap.getWidth(); 54 | if (MeasureSpec.AT_MOST == mode) { 55 | result = Math.min(size, result); 56 | } 57 | } 58 | return result; 59 | } 60 | 61 | private int measureHeight(int heightMeasureSpec) { 62 | int result = 0; 63 | int size = MeasureSpec.getSize(heightMeasureSpec); 64 | int mode = MeasureSpec.getMode(heightMeasureSpec); 65 | if (MeasureSpec.EXACTLY == mode) { 66 | result = size; 67 | } else { 68 | result = endBitmap.getHeight(); 69 | if (MeasureSpec.AT_MOST == mode) { 70 | result = Math.min(size, result); 71 | } 72 | } 73 | return result; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/res/anim/alpha_in.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/color/main_tab_text_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 13 | 14 | 19 | 24 | 25 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/anim_refresh.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/common_back_arrow_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/common_btn_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/common_image_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/common_text_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_common.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_common_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_common_button_press.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_common_transparent.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_common_white.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tab1_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tab2_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tab3_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tab_text_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_login.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 17 | 18 | 28 | 29 | 38 | 39 | 40 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 12 | 13 | 17 | 18 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/layout/common_title_bar.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 19 | 20 | 27 | 28 | 37 | 38 | 50 | 51 | 61 | 62 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 15 | 20 | 21 | 35 | 36 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 23 | 24 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 15 | 16 | 20 | 21 | 28 | 29 | 34 | 35 | 42 | 43 | 44 | 45 | 53 | 54 | 60 | 61 | 62 | 63 | 71 | 72 | 78 | 79 | 80 | 81 | 89 | 90 | 96 | 97 | 98 | 99 | 100 | 108 | 109 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_images_tab1.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_images_tab2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_girls.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 22 | 23 | 34 | 35 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_home_head.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 19 | 20 | 26 | 27 | 36 | 37 | 41 | 42 | 49 | 50 | 51 | 52 | 58 | 59 | 68 | 69 | 73 | 74 | 81 | 82 | 83 | 84 | 90 | 91 | 100 | 101 | 105 | 106 | 113 | 114 | 115 | 116 | 122 | 123 | 132 | 133 | 137 | 138 | 145 | 146 | 147 | 148 | 149 | 150 | 154 | 155 | 160 | 161 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_img.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_main_tab.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_news.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 21 | 22 | 28 | 29 | 38 | 39 | 49 | 50 | 59 | 60 | 61 | 62 | 63 | 67 | -------------------------------------------------------------------------------- /app/src/main/res/layout/loading_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | 20 | 21 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/refresh_footer.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/refresh_header.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 10 | 11 | 18 | 19 | 27 | 28 | 29 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/banner.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/fop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/fop.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/head_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/head_default.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/home_icon_cg_glfriends.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/home_icon_cg_glfriends.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/home_icon_cg_glhouse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/home_icon_cg_glhouse.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/home_icon_cg_gllaw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/home_icon_cg_gllaw.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/home_icon_cg_gllife.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/home_icon_cg_gllife.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_common_back_arrow_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/ic_common_back_arrow_normal.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_common_back_arrow_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/ic_common_back_arrow_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_loading_dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/ic_loading_dialog.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_pulltorefresh_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/ic_pulltorefresh_arrow.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_pulltorefresh_arrow_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/ic_pulltorefresh_arrow_up.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/ic_search.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_tabbar_favorites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/icon_tabbar_favorites.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_tabbar_favorites_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/icon_tabbar_favorites_selected.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_tabbar_library.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/icon_tabbar_library.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_tabbar_library_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/icon_tabbar_library_selected.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_tabbar_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/icon_tabbar_settings.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_tabbar_settings_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/icon_tabbar_settings_selected.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/iv_qr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/iv_qr.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/takeout_img_list_loading_pic1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/takeout_img_list_loading_pic1.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/takeout_img_list_loading_pic2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/takeout_img_list_loading_pic2.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FF0000 4 | #FF0000 5 | #FF0000 6 | 7 | 8 | #FF0000 9 | #F00000 10 | #000000 11 | #F0F0F0 12 | 13 | 14 | #A2A2A2 15 | #2D6EFA 16 | 17 | #999999 18 | #50000000 19 | #FFFFFF 20 | #EEEEEE 21 | #cccccc 22 | #999999 23 | 24 | #30000000 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | MVPDemo 3 | 登录 4 | 5 | 6 | 请输入手机号 7 | 请输入密码 8 | 登录 9 | 10 | 下拉刷新 11 | 松开刷新 12 | 正在刷新\u2026 13 | 松开加载更多 14 | 上拉加载更多 15 | 加载中\u2026 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 16 | 17 | 18 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /appdemo.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/appdemo.apk -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.1.2' 9 | classpath 'me.tatarka:gradle-retrolambda:3.1.0' 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------
6 | * prov String 四川 省 7 | * city String test 市 8 | * name String test 运营商 9 | * num Number 1370011 号段 10 | * provCode Number 110000 省别编码 11 | * type Number 1 1为移动 2为电信 3为联通 12 | */ 13 | public class LoginModel{ 14 | 15 | private String ret_code; 16 | private String prov; 17 | private String city; 18 | private String name; 19 | private String num; 20 | private String provCode; 21 | private String type; 22 | 23 | public String getRet_code() { 24 | return ret_code; 25 | } 26 | 27 | public void setRet_code(String ret_code) { 28 | this.ret_code = ret_code; 29 | } 30 | 31 | public String getProv() { 32 | return prov; 33 | } 34 | 35 | public void setProv(String prov) { 36 | this.prov = prov; 37 | } 38 | 39 | public String getCity() { 40 | return city; 41 | } 42 | 43 | public void setCity(String city) { 44 | this.city = city; 45 | } 46 | 47 | public String getName() { 48 | return name; 49 | } 50 | 51 | public void setName(String name) { 52 | this.name = name; 53 | } 54 | 55 | public String getNum() { 56 | return num; 57 | } 58 | 59 | public void setNum(String num) { 60 | this.num = num; 61 | } 62 | 63 | public String getProvCode() { 64 | return provCode; 65 | } 66 | 67 | public void setProvCode(String provCode) { 68 | this.provCode = provCode; 69 | } 70 | 71 | public String getType() { 72 | return type; 73 | } 74 | 75 | public void setType(String type) { 76 | this.type = type; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/modelbean/News.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.modelbean; 2 | 3 | /** 4 | * 根据返回json类型,多级嵌套 5 | * Created by baiyuliang on 2016-7-14. 6 | */ 7 | public class News { 8 | private String title; 9 | private String picUrl; 10 | private String description; 11 | private String ctime; 12 | private String url; 13 | 14 | public String getTitle() { 15 | return title; 16 | } 17 | 18 | public void setTitle(String title) { 19 | this.title = title; 20 | } 21 | 22 | public String getPicUrl() { 23 | return picUrl; 24 | } 25 | 26 | public void setPicUrl(String picUrl) { 27 | this.picUrl = picUrl; 28 | } 29 | 30 | public String getDescription() { 31 | return description; 32 | } 33 | 34 | public void setDescription(String description) { 35 | this.description = description; 36 | } 37 | 38 | public String getCtime() { 39 | return ctime; 40 | } 41 | 42 | public void setCtime(String ctime) { 43 | this.ctime = ctime; 44 | } 45 | 46 | public String getUrl() { 47 | return url; 48 | } 49 | 50 | public void setUrl(String url) { 51 | this.url = url; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/modelbean/NewsBean.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.modelbean; 2 | 3 | /** 4 | * Created by baiyuliang on 2016-7-14. 5 | */ 6 | public class NewsBean extends BaseBean { 7 | 8 | private NewsModel showapi_res_body; 9 | 10 | public NewsModel getShowapi_res_body() { 11 | return showapi_res_body; 12 | } 13 | 14 | public void setShowapi_res_body(NewsModel showapi_res_body) { 15 | this.showapi_res_body = showapi_res_body; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/modelbean/NewsModel.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.modelbean; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 新聞 7 | * Created by baiyuliang on 2016-7-14. 8 | */ 9 | public class NewsModel { 10 | private String code; 11 | private String msg; 12 | private List newslist; 13 | 14 | public String getCode() { 15 | return code; 16 | } 17 | 18 | public void setCode(String code) { 19 | this.code = code; 20 | } 21 | 22 | public String getMsg() { 23 | return msg; 24 | } 25 | 26 | public void setMsg(String msg) { 27 | this.msg = msg; 28 | } 29 | 30 | public List getNewslist() { 31 | return newslist; 32 | } 33 | 34 | public void setNewslist(List newslist) { 35 | this.newslist = newslist; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/mvpview/ImagesMvpView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.mvpview; 2 | 3 | import com.byl.mvpdemo.model.modelbean.NewsBean; 4 | import com.byl.mvpdemo.model.mvpview.base.MvpView; 5 | 6 | /** 7 | * Created by baiyuliang on 2016-7-14. 8 | */ 9 | public interface ImagesMvpView extends MvpView { 10 | 11 | /** 12 | * 下拉刷新成功 13 | * 14 | * @param newsBean 15 | */ 16 | void refreshSuccess(NewsBean newsBean); 17 | 18 | /** 19 | * 上拉加载成功 20 | * 21 | * @param newsBean 22 | */ 23 | void loadMoreSuccess(NewsBean newsBean); 24 | 25 | /** 26 | * 失败 27 | * 28 | * @param message 29 | */ 30 | void fail(String message); 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/mvpview/LoginMvpView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.mvpview; 2 | 3 | import com.byl.mvpdemo.model.modelbean.LoginBean; 4 | import com.byl.mvpdemo.model.mvpview.base.MvpView; 5 | 6 | /** 7 | * Created by baiyuliang on 2016-7-14. 8 | */ 9 | public interface LoginMvpView extends MvpView { 10 | 11 | /** 12 | * 登录成功 13 | * @param loginBean 14 | */ 15 | void loginSuccess(LoginBean loginBean); 16 | 17 | /** 18 | * 登录失败 19 | * @param message 20 | */ 21 | void loginFail(String message); 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/mvpview/NewsMvpView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.mvpview; 2 | 3 | import com.byl.mvpdemo.model.modelbean.NewsBean; 4 | import com.byl.mvpdemo.model.mvpview.base.MvpView; 5 | 6 | /** 7 | * Created by baiyuliang on 2016-7-14. 8 | */ 9 | public interface NewsMvpView extends MvpView { 10 | 11 | /** 12 | * 下拉刷新成功 13 | * 14 | * @param newsBean 15 | */ 16 | void refreshSuccess(NewsBean newsBean); 17 | 18 | /** 19 | * 上拉加载成功 20 | * 21 | * @param newsBean 22 | */ 23 | void loadMoreSuccess(NewsBean newsBean); 24 | 25 | /** 26 | * 失败 27 | * 28 | * @param message 29 | */ 30 | void fail(String message); 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/model/mvpview/base/MvpView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.model.mvpview.base; 2 | 3 | 4 | /** 5 | * Base interface that any class that wants to act as a View in the MVP (Model View Presenter) 6 | * pattern must implement. Generally this interface will be extended by a more specific interface 7 | * that then usually will be implemented by an Activity or Fragment. 8 | */ 9 | public interface MvpView { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/presenter/ImagesPresenter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.presenter; 2 | 3 | import android.content.Context; 4 | import android.text.TextUtils; 5 | 6 | import com.byl.mvpdemo.model.modelbean.NewsBean; 7 | import com.byl.mvpdemo.model.mvpview.NewsMvpView; 8 | import com.byl.mvpdemo.presenter.base.BasePresenter; 9 | import com.byl.mvpdemo.util.LogUtil; 10 | 11 | import rx.Subscriber; 12 | import rx.Subscription; 13 | import rx.android.schedulers.AndroidSchedulers; 14 | import rx.schedulers.Schedulers; 15 | 16 | /** 17 | * Created by baiyuliang on 2016-7-14. 18 | */ 19 | public class ImagesPresenter extends BasePresenter { 20 | 21 | Subscription mSubscription; 22 | 23 | public ImagesPresenter(Context context) { 24 | this.context = context; 25 | } 26 | 27 | @Override 28 | public void attachView(NewsMvpView mvpView) { 29 | super.attachView(mvpView); 30 | } 31 | 32 | @Override 33 | public void detachView() { 34 | super.detachView(); 35 | if (mSubscription != null) mSubscription.unsubscribe(); 36 | } 37 | 38 | public void getImages(String num, String page, String rand) { 39 | checkViewAttached(); 40 | mSubscription = getApiService().girls(num, page, rand) 41 | .observeOn(AndroidSchedulers.mainThread()) 42 | .subscribeOn(Schedulers.io()) 43 | .subscribe(new Subscriber() { 44 | @Override 45 | public void onCompleted() { 46 | 47 | } 48 | 49 | @Override 50 | public void onError(Throwable e) { 51 | getMvpView().fail("获取图片失败"); 52 | LogUtil.e("获取图片失败>>" + e.getMessage()); 53 | } 54 | 55 | @Override 56 | public void onNext(NewsBean newsBean) { 57 | if (!newsBean.getShowapi_res_code().equals("0") 58 | || newsBean.getShowapi_res_body() == null 59 | || TextUtils.isEmpty(newsBean.getShowapi_res_body().getCode()) 60 | || !newsBean.getShowapi_res_body().getCode().equals("200")) { 61 | getMvpView().fail("获取图片失败"); 62 | } else { 63 | if (page.equals("1")) {//刷新 64 | if (newsBean.getShowapi_res_body().getNewslist() == null 65 | || newsBean.getShowapi_res_body().getNewslist().size() <= 0) { 66 | getMvpView().fail("当前无图片"); 67 | } else { 68 | getMvpView().refreshSuccess(newsBean); 69 | } 70 | } else {//加载更多 71 | if (newsBean.getShowapi_res_body().getNewslist() == null 72 | || newsBean.getShowapi_res_body().getNewslist().size() <= 0) { 73 | getMvpView().fail("没有更多数据啦"); 74 | } else { 75 | getMvpView().loadMoreSuccess(newsBean); 76 | } 77 | } 78 | 79 | } 80 | } 81 | }); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/presenter/LoginPresenter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.presenter; 2 | 3 | import android.content.Context; 4 | import android.text.TextUtils; 5 | 6 | import com.byl.mvpdemo.api.ApiService; 7 | import com.byl.mvpdemo.model.modelbean.LoginBean; 8 | import com.byl.mvpdemo.model.mvpview.LoginMvpView; 9 | import com.byl.mvpdemo.presenter.base.BasePresenter; 10 | import com.byl.mvpdemo.util.LogUtil; 11 | import com.byl.mvpdemo.view.MyProgressDialog; 12 | 13 | import rx.Subscriber; 14 | import rx.Subscription; 15 | import rx.android.schedulers.AndroidSchedulers; 16 | import rx.schedulers.Schedulers; 17 | 18 | /** 19 | * Created by baiyuliang on 2016-7-14. 20 | */ 21 | public class LoginPresenter extends BasePresenter { 22 | 23 | Subscription mSubscription; 24 | 25 | public LoginPresenter(Context context) { 26 | this.context = context; 27 | } 28 | 29 | @Override 30 | public void attachView(LoginMvpView mvpView) { 31 | super.attachView(mvpView); 32 | } 33 | 34 | @Override 35 | public void detachView() { 36 | super.detachView(); 37 | if (mSubscription != null) mSubscription.unsubscribe(); 38 | } 39 | 40 | public void login(String account) { 41 | checkViewAttached(); 42 | showProgressDialog(); 43 | mSubscription = getApiService().login(account) 44 | .observeOn(AndroidSchedulers.mainThread()) 45 | .subscribeOn(Schedulers.io()) 46 | .subscribe(new Subscriber() { 47 | @Override 48 | public void onCompleted() { 49 | 50 | } 51 | 52 | @Override 53 | public void onError(Throwable e) { 54 | dissmissProgressDialog(); 55 | getMvpView().loginFail("登录失败"); 56 | LogUtil.e("登录失败>>" + e.getMessage()); 57 | } 58 | 59 | @Override 60 | public void onNext(LoginBean loginBean) { 61 | dissmissProgressDialog(); 62 | if (!loginBean.getShowapi_res_code().equals("0") 63 | || loginBean.getShowapi_res_body() == null 64 | || TextUtils.isEmpty(loginBean.getShowapi_res_body().getRet_code()) 65 | || !loginBean.getShowapi_res_body().getRet_code().equals("0")) { 66 | getMvpView().loginFail("请检查您输入的手机号码是否正确"); 67 | } else { 68 | getMvpView().loginSuccess(loginBean); 69 | } 70 | } 71 | }); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/presenter/NewsPresenter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.presenter; 2 | 3 | import android.content.Context; 4 | import android.text.TextUtils; 5 | import android.util.Log; 6 | 7 | import com.byl.mvpdemo.model.modelbean.NewsBean; 8 | import com.byl.mvpdemo.model.mvpview.NewsMvpView; 9 | import com.byl.mvpdemo.presenter.base.BasePresenter; 10 | import com.byl.mvpdemo.util.LogUtil; 11 | 12 | import rx.Subscriber; 13 | import rx.Subscription; 14 | import rx.android.schedulers.AndroidSchedulers; 15 | import rx.schedulers.Schedulers; 16 | 17 | /** 18 | * Created by baiyuliang on 2016-7-14. 19 | */ 20 | public class NewsPresenter extends BasePresenter { 21 | 22 | boolean isFirstReq = true; 23 | Subscription mSubscription; 24 | 25 | public NewsPresenter(Context context) { 26 | this.context = context; 27 | } 28 | 29 | @Override 30 | public void attachView(NewsMvpView mvpView) { 31 | super.attachView(mvpView); 32 | } 33 | 34 | @Override 35 | public void detachView() { 36 | super.detachView(); 37 | if (mSubscription != null) mSubscription.unsubscribe(); 38 | } 39 | 40 | public void getNews(String num, String page) { 41 | checkViewAttached(); 42 | if (isFirstReq) {//只在第一次请求时显示dialog 43 | showProgressDialog(); 44 | isFirstReq = false; 45 | } 46 | mSubscription = getApiService().news(num, page) 47 | .observeOn(AndroidSchedulers.mainThread()) 48 | .subscribeOn(Schedulers.io()) 49 | .subscribe(new Subscriber() { 50 | @Override 51 | public void onCompleted() { 52 | 53 | } 54 | 55 | @Override 56 | public void onError(Throwable e) { 57 | dissmissProgressDialog(); 58 | getMvpView().fail("获取新闻失败"); 59 | LogUtil.e("获取新闻失败>>" + e.getMessage()); 60 | } 61 | 62 | @Override 63 | public void onNext(NewsBean newsBean) { 64 | dissmissProgressDialog(); 65 | if (!newsBean.getShowapi_res_code().equals("0") 66 | || newsBean.getShowapi_res_body() == null 67 | || TextUtils.isEmpty(newsBean.getShowapi_res_body().getCode()) 68 | || !newsBean.getShowapi_res_body().getCode().equals("200")) { 69 | getMvpView().fail("获取新闻失败"); 70 | } else { 71 | if (page.equals("1")) {//刷新 72 | if (newsBean.getShowapi_res_body().getNewslist() == null 73 | || newsBean.getShowapi_res_body().getNewslist().size() <= 0) { 74 | getMvpView().fail("当前无新闻"); 75 | } else { 76 | getMvpView().refreshSuccess(newsBean); 77 | } 78 | } else {//加载更多 79 | if (newsBean.getShowapi_res_body().getNewslist() == null 80 | || newsBean.getShowapi_res_body().getNewslist().size() <= 0) { 81 | getMvpView().fail("没有更多数据啦"); 82 | } else { 83 | getMvpView().loadMoreSuccess(newsBean); 84 | } 85 | } 86 | 87 | } 88 | } 89 | }); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/presenter/base/BasePresenter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.presenter.base; 2 | 3 | import android.content.Context; 4 | 5 | import com.byl.mvpdemo.api.ApiService; 6 | import com.byl.mvpdemo.api.ApiUtil; 7 | import com.byl.mvpdemo.model.mvpview.base.MvpView; 8 | import com.byl.mvpdemo.view.MyProgressDialog; 9 | 10 | /** 11 | * Base class that implements the Presenter interface and provides a base implementation for 12 | * attachView() and detachView(). It also handles keeping a reference to the mvpView that 13 | * can be accessed from the children classes by calling getMvpView(). 14 | */ 15 | public class BasePresenter implements Presenter { 16 | 17 | public Context context; 18 | private T mMvpView; 19 | private ApiService apiService; 20 | private MyProgressDialog myProgressDialog; 21 | 22 | 23 | @Override 24 | public void attachView(T mvpView) { 25 | mMvpView = mvpView; 26 | apiService = ApiUtil.createApiService(); 27 | } 28 | 29 | @Override 30 | public void detachView() { 31 | mMvpView = null; 32 | } 33 | 34 | public boolean isViewAttached() { 35 | return mMvpView != null; 36 | } 37 | 38 | public T getMvpView() { 39 | return mMvpView; 40 | } 41 | 42 | public ApiService getApiService() { 43 | return apiService; 44 | } 45 | 46 | public void showProgressDialog() { 47 | if (context != null) { 48 | if (myProgressDialog == null) { 49 | myProgressDialog = new MyProgressDialog(context); 50 | } 51 | myProgressDialog.show(); 52 | } 53 | } 54 | 55 | public void dissmissProgressDialog() { 56 | if (myProgressDialog != null) { 57 | myProgressDialog.dismiss(); 58 | } 59 | } 60 | 61 | public void checkViewAttached() { 62 | if (!isViewAttached()) throw new MvpViewNotAttachedException(); 63 | } 64 | 65 | public static class MvpViewNotAttachedException extends RuntimeException { 66 | public MvpViewNotAttachedException() { 67 | super("使用Presenter前,请先调用attachView"); 68 | } 69 | } 70 | } 71 | 72 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/presenter/base/Presenter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.presenter.base; 2 | 3 | import com.byl.mvpdemo.model.mvpview.base.MvpView; 4 | 5 | /** 6 | * Every presenter in the app must either implement this interface or extend BasePresenter 7 | * indicating the MvpView type that wants to be attached with. 8 | */ 9 | public interface Presenter { 10 | 11 | void attachView(V mvpView); 12 | 13 | void detachView(); 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/base/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.base; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.support.v4.app.FragmentActivity; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.text.TextUtils; 10 | import android.view.View; 11 | import android.widget.ImageView; 12 | import android.widget.ProgressBar; 13 | import android.widget.RelativeLayout; 14 | import android.widget.TextView; 15 | 16 | import com.byl.mvpdemo.R; 17 | import com.byl.mvpdemo.api.ApiService; 18 | import com.byl.mvpdemo.api.ApiUtil; 19 | 20 | /** 21 | * Created by baiyuliang on 2016-7-14. 22 | */ 23 | public abstract class BaseActivity extends FragmentActivity implements View.OnClickListener { 24 | 25 | public Activity context; 26 | 27 | public RelativeLayout title_bar; 28 | public TextView tv_left, tv_title, tv_right; 29 | public ImageView iv_right; 30 | public ProgressBar pb; 31 | 32 | @Override 33 | protected void onCreate(Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | setContentView(getContentView()); 36 | context = this; 37 | initView(); 38 | initClick(); 39 | initData(); 40 | } 41 | 42 | /** 43 | * 初始化titlebar,该方法只有在标题栏布局符合此规则时才能调用 44 | * 45 | * @param left titlebar左按钮 46 | * @param title titlebar标题 47 | * @param right titlebar 右按钮 48 | * @param res titlebar 右图片按钮 49 | * @param onClickListener 左右按钮点击事件 50 | */ 51 | public void initTitleBar(String left, String title, String right, int res, View.OnClickListener onClickListener) { 52 | title_bar = (RelativeLayout) $(R.id.title_bar); 53 | title_bar.setBackgroundColor(getResources().getColor(R.color.common_title_bg)); 54 | tv_left = (TextView) $(R.id.tv_left);//返回按钮 55 | tv_title = (TextView) $(R.id.tv_title);//标题 56 | tv_right = (TextView) $(R.id.tv_right);//(右侧)按钮 57 | iv_right = (ImageView) $(R.id.iv_right);//右侧图片按钮 58 | 59 | pb = (ProgressBar) $(R.id.pb);// 标题栏数据加载ProgressBar 60 | 61 | if (!TextUtils.isEmpty(left)) { 62 | tv_left.setText(left); 63 | tv_left.setVisibility(View.VISIBLE); 64 | tv_left.setOnClickListener(onClickListener); 65 | } else { 66 | tv_left.setVisibility(View.GONE); 67 | } 68 | 69 | if (!TextUtils.isEmpty(title)) { 70 | tv_title.setText(title); 71 | tv_title.setVisibility(View.VISIBLE); 72 | } else { 73 | tv_title.setVisibility(View.GONE); 74 | } 75 | 76 | if (!TextUtils.isEmpty(right)) { 77 | tv_right.setText(right); 78 | tv_right.setVisibility(View.VISIBLE); 79 | tv_right.setOnClickListener(onClickListener); 80 | } else { 81 | tv_right.setVisibility(View.GONE); 82 | } 83 | 84 | if (res != 0) { 85 | iv_right.setImageResource(res); 86 | iv_right.setVisibility(View.VISIBLE); 87 | iv_right.setOnClickListener(onClickListener); 88 | } else { 89 | iv_right.setVisibility(View.GONE); 90 | } 91 | 92 | } 93 | 94 | /** 95 | * 设置布局文件 96 | * 97 | * @return 98 | */ 99 | public abstract int getContentView(); 100 | 101 | /** 102 | * 初始化View 103 | */ 104 | public abstract void initView(); 105 | 106 | /** 107 | * 设置点击事件 108 | */ 109 | public abstract void initClick(); 110 | 111 | /** 112 | * 初始化数据 113 | */ 114 | public abstract void initData(); 115 | 116 | public View $(int id) { 117 | return findViewById(id); 118 | } 119 | 120 | @Override 121 | public void onClick(View v) { 122 | switch (v.getId()) { 123 | case R.id.tv_left: 124 | finish(); 125 | } 126 | } 127 | 128 | public void startActivity(Class cla) { 129 | startActivity(new Intent(this, cla)); 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/base/BaseFragment.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.base; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.text.TextUtils; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.ImageView; 12 | import android.widget.ProgressBar; 13 | import android.widget.RelativeLayout; 14 | import android.widget.TextView; 15 | 16 | import com.byl.mvpdemo.R; 17 | 18 | /** 19 | * Created by baiyuliang on 2016-7-14. 20 | */ 21 | public abstract class BaseFragment extends Fragment implements View.OnClickListener { 22 | 23 | public Activity context; 24 | public View view; 25 | 26 | public RelativeLayout title_bar; 27 | public TextView tv_left, tv_title, tv_right; 28 | public ImageView iv_right; 29 | public ProgressBar pb; 30 | 31 | @Override 32 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 33 | context = getActivity(); 34 | if (view == null) { 35 | view = inflater.inflate(getContentView(), null); 36 | initView(); 37 | initClick(); 38 | initData(); 39 | } 40 | return view; 41 | } 42 | 43 | /** 44 | * 初始化titlebar,该方法只有在标题栏布局符合此规则时才能调用 45 | * 46 | * @param left titlebar左按钮 47 | * @param title titlebar标题 48 | * @param right titlebar 右按钮 49 | * @param res titlebar 右图片按钮 50 | * @param onClickListener 左右按钮点击事件 51 | */ 52 | public void initTitleBar(String left, String title, String right, int res, View.OnClickListener onClickListener) { 53 | title_bar = (RelativeLayout) $(R.id.title_bar); 54 | title_bar.setBackgroundColor(getResources().getColor(R.color.common_title_bg)); 55 | tv_left = (TextView) $(R.id.tv_left);//返回按钮 56 | tv_title = (TextView) $(R.id.tv_title);//标题 57 | tv_right = (TextView) $(R.id.tv_right);//(右侧)按钮 58 | iv_right = (ImageView) $(R.id.iv_right);//右侧图片按钮 59 | 60 | pb = (ProgressBar) $(R.id.pb);// 标题栏数据加载ProgressBar 61 | 62 | if (!TextUtils.isEmpty(left)) { 63 | tv_left.setText(left); 64 | tv_left.setVisibility(View.VISIBLE); 65 | tv_left.setOnClickListener(onClickListener); 66 | } else { 67 | tv_left.setVisibility(View.GONE); 68 | } 69 | 70 | if (!TextUtils.isEmpty(title)) { 71 | tv_title.setText(title); 72 | tv_title.setVisibility(View.VISIBLE); 73 | } else { 74 | tv_title.setVisibility(View.GONE); 75 | } 76 | 77 | if (!TextUtils.isEmpty(right)) { 78 | tv_right.setText(right); 79 | tv_right.setVisibility(View.VISIBLE); 80 | tv_right.setOnClickListener(onClickListener); 81 | } else { 82 | tv_right.setVisibility(View.GONE); 83 | } 84 | 85 | if (res != 0) { 86 | iv_right.setImageResource(res); 87 | iv_right.setVisibility(View.VISIBLE); 88 | iv_right.setOnClickListener(onClickListener); 89 | } else { 90 | iv_right.setVisibility(View.GONE); 91 | } 92 | 93 | } 94 | 95 | /** 96 | * 设置布局文件 97 | * 98 | * @return 99 | */ 100 | public abstract int getContentView(); 101 | 102 | /** 103 | * 初始化View 104 | */ 105 | public abstract void initView(); 106 | 107 | /** 108 | * 设置点击事件 109 | */ 110 | public abstract void initClick(); 111 | 112 | /** 113 | * 初始化数据 114 | */ 115 | public abstract void initData(); 116 | 117 | public View $(int id) { 118 | return view.findViewById(id); 119 | } 120 | 121 | 122 | } 123 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/images/FragmentImageTab1.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.images; 2 | 3 | import android.support.v7.widget.GridLayoutManager; 4 | import android.view.View; 5 | import android.widget.Toast; 6 | 7 | import com.byl.mvpdemo.R; 8 | import com.byl.mvpdemo.adapter.BaseAdapter; 9 | import com.byl.mvpdemo.adapter.ImagesAdapter; 10 | import com.byl.mvpdemo.model.modelbean.News; 11 | import com.byl.mvpdemo.model.modelbean.NewsBean; 12 | import com.byl.mvpdemo.model.mvpview.NewsMvpView; 13 | import com.byl.mvpdemo.presenter.ImagesPresenter; 14 | import com.byl.mvpdemo.ui.base.BaseFragment; 15 | import com.byl.mvpdemo.view.pullrecyclerview.PullBaseView; 16 | import com.byl.mvpdemo.view.pullrecyclerview.PullRecyclerView; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | 22 | /** 23 | * 24 | */ 25 | public class FragmentImageTab1 extends BaseFragment implements NewsMvpView, 26 | PullBaseView.OnHeaderRefreshListener, 27 | PullBaseView.OnFooterRefreshListener, 28 | BaseAdapter.OnItemClickListener, 29 | BaseAdapter.OnViewClickListener { 30 | 31 | PullRecyclerView mPullRecyclerView; 32 | ImagesAdapter imagesAdapter; 33 | List objectList; 34 | 35 | ImagesPresenter imagesPresenter; 36 | int page; 37 | 38 | @Override 39 | public int getContentView() { 40 | return R.layout.fragment_images_tab1; 41 | } 42 | 43 | @Override 44 | public void initView() { 45 | mPullRecyclerView = (PullRecyclerView) $(R.id.mPullRecyclerView); 46 | mPullRecyclerView.setOnHeaderRefreshListener(this);//设置下拉监听 47 | mPullRecyclerView.setOnFooterRefreshListener(this);//设置上拉监听 48 | mPullRecyclerView.setCanScrollAtRereshing(false);//设置正在刷新时是否可以滑动,默认不可滑动 49 | mPullRecyclerView.setCanPullDown(true);//设置是否可下拉 50 | mPullRecyclerView.setCanPullUp(true);//设置是否可上拉 51 | } 52 | 53 | @Override 54 | public void initClick() { 55 | 56 | } 57 | 58 | @Override 59 | public void initData() { 60 | objectList = new ArrayList<>(); 61 | imagesPresenter = new ImagesPresenter(context); 62 | imagesPresenter.attachView(this); 63 | imagesPresenter.getImages("20", String.valueOf(++page), "0"); 64 | } 65 | 66 | @Override 67 | public void onClick(View v) { 68 | 69 | } 70 | 71 | 72 | @Override 73 | public void onFooterRefresh(PullBaseView view) { 74 | imagesPresenter.getImages("20", String.valueOf(++page), "0"); 75 | } 76 | 77 | @Override 78 | public void onHeaderRefresh(PullBaseView view) { 79 | page = 0; 80 | imagesPresenter.getImages("20", String.valueOf(++page), "0"); 81 | } 82 | 83 | @Override 84 | public void refreshSuccess(NewsBean newsBean) { 85 | mPullRecyclerView.onHeaderRefreshComplete(); 86 | objectList.clear(); 87 | List list = newsBean.getShowapi_res_body().getNewslist(); 88 | for (News news : list) { 89 | objectList.add(news); 90 | } 91 | imagesAdapter = new ImagesAdapter(context, objectList, this); 92 | mPullRecyclerView.setLayoutManager(new GridLayoutManager(context, 2)); 93 | imagesAdapter.setOnItemClickListener(this); 94 | mPullRecyclerView.setAdapter(imagesAdapter); 95 | } 96 | 97 | @Override 98 | public void loadMoreSuccess(NewsBean newsBean) { 99 | mPullRecyclerView.onFooterRefreshComplete(); 100 | List list = newsBean.getShowapi_res_body().getNewslist(); 101 | for (News news : list) { 102 | objectList.add(news); 103 | } 104 | imagesAdapter.notifyDataSetChanged(); 105 | } 106 | 107 | @Override 108 | public void fail(String message) { 109 | Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); 110 | } 111 | 112 | @Override 113 | public void onItemClick(int position) { 114 | Toast.makeText(context, "item>>" + position, Toast.LENGTH_SHORT).show(); 115 | } 116 | 117 | @Override 118 | public void onViewClick(int position, int viewtype) { 119 | switch (viewtype) { 120 | case 1: 121 | Toast.makeText(context, "赞>>" + position, Toast.LENGTH_SHORT).show(); 122 | break; 123 | } 124 | } 125 | 126 | @Override 127 | public void onDestroy() { 128 | super.onDestroy(); 129 | imagesPresenter.detachView(); 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/images/FragmentImageTab2.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.images; 2 | 3 | import android.support.v7.widget.GridLayoutManager; 4 | import android.view.View; 5 | import android.widget.Toast; 6 | 7 | import com.byl.mvpdemo.R; 8 | import com.byl.mvpdemo.adapter.BaseAdapter; 9 | import com.byl.mvpdemo.adapter.ImagesAdapter; 10 | import com.byl.mvpdemo.model.modelbean.News; 11 | import com.byl.mvpdemo.model.modelbean.NewsBean; 12 | import com.byl.mvpdemo.model.mvpview.NewsMvpView; 13 | import com.byl.mvpdemo.presenter.ImagesPresenter; 14 | import com.byl.mvpdemo.ui.base.BaseFragment; 15 | import com.byl.mvpdemo.view.pullrecyclerview.PullBaseView; 16 | import com.byl.mvpdemo.view.pullrecyclerview.PullRecyclerView; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | 22 | /** 23 | * 24 | */ 25 | public class FragmentImageTab2 extends BaseFragment implements NewsMvpView, 26 | PullBaseView.OnHeaderRefreshListener, 27 | PullBaseView.OnFooterRefreshListener, 28 | BaseAdapter.OnItemClickListener, 29 | BaseAdapter.OnViewClickListener { 30 | 31 | PullRecyclerView mPullRecyclerView; 32 | ImagesAdapter imagesAdapter; 33 | List objectList; 34 | 35 | ImagesPresenter imagesPresenter; 36 | int page; 37 | 38 | @Override 39 | public int getContentView() { 40 | return R.layout.fragment_images_tab2; 41 | } 42 | 43 | @Override 44 | public void initView() { 45 | mPullRecyclerView = (PullRecyclerView) $(R.id.mPullRecyclerView); 46 | mPullRecyclerView.setOnHeaderRefreshListener(this);//设置下拉监听 47 | mPullRecyclerView.setOnFooterRefreshListener(this);//设置上拉监听 48 | mPullRecyclerView.setCanScrollAtRereshing(false);//设置正在刷新时是否可以滑动,默认不可滑动 49 | mPullRecyclerView.setCanPullDown(true);//设置是否可下拉 50 | mPullRecyclerView.setCanPullUp(true);//设置是否可上拉 51 | } 52 | 53 | @Override 54 | public void initClick() { 55 | 56 | } 57 | 58 | @Override 59 | public void initData() { 60 | objectList = new ArrayList<>(); 61 | imagesPresenter = new ImagesPresenter(context); 62 | imagesPresenter.attachView(this); 63 | imagesPresenter.getImages("20", String.valueOf(++page), "1"); 64 | } 65 | 66 | @Override 67 | public void onClick(View v) { 68 | 69 | } 70 | 71 | 72 | @Override 73 | public void onFooterRefresh(PullBaseView view) { 74 | imagesPresenter.getImages("20", String.valueOf(++page), "1"); 75 | } 76 | 77 | @Override 78 | public void onHeaderRefresh(PullBaseView view) { 79 | page = 0; 80 | imagesPresenter.getImages("20", String.valueOf(++page), "1"); 81 | } 82 | 83 | @Override 84 | public void refreshSuccess(NewsBean newsBean) { 85 | mPullRecyclerView.onHeaderRefreshComplete(); 86 | objectList.clear(); 87 | List list = newsBean.getShowapi_res_body().getNewslist(); 88 | for (News news : list) { 89 | objectList.add(news); 90 | } 91 | imagesAdapter = new ImagesAdapter(context, objectList, this); 92 | mPullRecyclerView.setLayoutManager(new GridLayoutManager(context, 2)); 93 | imagesAdapter.setOnItemClickListener(this); 94 | mPullRecyclerView.setAdapter(imagesAdapter); 95 | } 96 | 97 | @Override 98 | public void loadMoreSuccess(NewsBean newsBean) { 99 | mPullRecyclerView.onFooterRefreshComplete(); 100 | List list = newsBean.getShowapi_res_body().getNewslist(); 101 | for (News news : list) { 102 | objectList.add(news); 103 | } 104 | imagesAdapter.notifyDataSetChanged(); 105 | } 106 | 107 | @Override 108 | public void fail(String message) { 109 | Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); 110 | } 111 | 112 | @Override 113 | public void onItemClick(int position) { 114 | Toast.makeText(context, "item>>" + position, Toast.LENGTH_SHORT).show(); 115 | } 116 | 117 | @Override 118 | public void onViewClick(int position, int viewtype) { 119 | switch (viewtype) { 120 | case 1: 121 | Toast.makeText(context, "赞>>" + position, Toast.LENGTH_SHORT).show(); 122 | break; 123 | } 124 | } 125 | 126 | @Override 127 | public void onDestroy() { 128 | super.onDestroy(); 129 | imagesPresenter.detachView(); 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/login/LoginActivity.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.login; 2 | 3 | import android.text.TextUtils; 4 | import android.view.View; 5 | import android.widget.Button; 6 | import android.widget.EditText; 7 | import android.widget.Toast; 8 | 9 | import com.byl.mvpdemo.R; 10 | import com.byl.mvpdemo.model.modelbean.LoginBean; 11 | import com.byl.mvpdemo.model.mvpview.LoginMvpView; 12 | import com.byl.mvpdemo.presenter.LoginPresenter; 13 | import com.byl.mvpdemo.ui.base.BaseActivity; 14 | import com.byl.mvpdemo.ui.main.MainActivity; 15 | 16 | public class LoginActivity extends BaseActivity implements LoginMvpView { 17 | 18 | EditText et_account, et_pwd; 19 | Button btn_login; 20 | LoginPresenter loginPresenter; 21 | 22 | @Override 23 | public int getContentView() { 24 | return R.layout.activity_login; 25 | } 26 | 27 | @Override 28 | public void initView() { 29 | initTitleBar("", "登录", "注册", 0, this); 30 | title_bar.setBackgroundColor(getResources().getColor(R.color.common_title_bg)); 31 | et_account = (EditText) $(R.id.account); 32 | et_pwd = (EditText) $(R.id.password); 33 | btn_login = (Button) $(R.id.login); 34 | } 35 | 36 | @Override 37 | public void initClick() { 38 | btn_login.setOnClickListener(this); 39 | } 40 | 41 | @Override 42 | public void initData() { 43 | loginPresenter = new LoginPresenter(this); 44 | loginPresenter.attachView(this); 45 | } 46 | 47 | @Override 48 | public void onClick(View v) { 49 | super.onClick(v); 50 | switch (v.getId()) { 51 | case R.id.tv_right: 52 | Toast.makeText(LoginActivity.this, "注册", Toast.LENGTH_SHORT).show(); 53 | break; 54 | case R.id.login: 55 | doLogin(); 56 | break; 57 | } 58 | } 59 | 60 | /** 61 | * 登录 62 | */ 63 | void doLogin() { 64 | String account = et_account.getText().toString(); 65 | if (TextUtils.isEmpty(account)) { 66 | Toast.makeText(LoginActivity.this, "请输入您的手机号", Toast.LENGTH_SHORT).show(); 67 | return; 68 | } 69 | String pwd = et_pwd.getText().toString(); 70 | if (TextUtils.isEmpty(pwd)) { 71 | Toast.makeText(LoginActivity.this, "请输入您的密码", Toast.LENGTH_SHORT).show(); 72 | return; 73 | } 74 | loginPresenter.login(account); 75 | } 76 | 77 | @Override 78 | public void loginSuccess(LoginBean loginBean) { 79 | startActivity(MainActivity.class); 80 | finish(); 81 | Toast.makeText(LoginActivity.this, "登录成功", Toast.LENGTH_SHORT).show(); 82 | } 83 | 84 | @Override 85 | public void loginFail(String message) { 86 | Toast.makeText(LoginActivity.this, message, Toast.LENGTH_SHORT).show(); 87 | } 88 | 89 | @Override 90 | protected void onDestroy() { 91 | super.onDestroy(); 92 | loginPresenter.detachView(); 93 | } 94 | } 95 | 96 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/main/FragmentTab1.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.main; 2 | 3 | import android.support.v7.widget.LinearLayoutManager; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.util.Log; 6 | import android.view.View; 7 | import android.widget.ImageView; 8 | import android.widget.RelativeLayout; 9 | import android.widget.TextView; 10 | import android.widget.Toast; 11 | 12 | import com.byl.mvpdemo.R; 13 | import com.byl.mvpdemo.adapter.BaseAdapter; 14 | import com.byl.mvpdemo.adapter.NewsAdapter; 15 | import com.byl.mvpdemo.model.modelbean.ImageModel; 16 | import com.byl.mvpdemo.model.modelbean.News; 17 | import com.byl.mvpdemo.model.modelbean.NewsBean; 18 | import com.byl.mvpdemo.model.mvpview.NewsMvpView; 19 | import com.byl.mvpdemo.presenter.NewsPresenter; 20 | import com.byl.mvpdemo.ui.base.BaseFragment; 21 | import com.byl.mvpdemo.util.SysUtil; 22 | import com.byl.mvpdemo.view.pullrecyclerview.PullBaseView; 23 | import com.byl.mvpdemo.view.pullrecyclerview.PullRecyclerView; 24 | 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | 29 | public class FragmentTab1 extends BaseFragment implements 30 | BaseAdapter.OnItemClickListener, 31 | PullBaseView.OnHeaderRefreshListener, 32 | PullBaseView.OnFooterRefreshListener, 33 | PullBaseView.OnPullDownScrollListener, 34 | View.OnClickListener, 35 | BaseAdapter.OnViewClickListener, 36 | NewsMvpView { 37 | 38 | RelativeLayout rl_title; 39 | TextView tv_search; 40 | ImageView iv_qr;//二维码 41 | PullRecyclerView mRecyclerView; 42 | NewsAdapter newsAdapter; 43 | List listbanner, listnews; 44 | 45 | int y, //滑动距离 46 | bannerH;//banner高度 47 | boolean isPullDown = false;//是否是下拉状态 48 | 49 | NewsPresenter newsPresenter; 50 | int page; 51 | 52 | @Override 53 | public int getContentView() { 54 | return R.layout.fragment_1; 55 | } 56 | 57 | /** 58 | * 注意:rl_title.getBackground().setAlpha(0),设置标题栏背景透明度,会影响其它界面的背景, 59 | * 如果加上这个效果,那么其他界面的背景色在xml中设置将失效,需代码中动态设置, 60 | * 这个问题很奇葩,未找到原因, 61 | * 现在要么不要这个滑动改变透明度的效果,要么其他界面中的背景色就动态设置 62 | */ 63 | @Override 64 | public void initView() { 65 | rl_title = (RelativeLayout) $(R.id.rl_title);//标题栏 66 | rl_title.getBackground().setAlpha(0); 67 | tv_search = (TextView) $(R.id.tv_search); 68 | iv_qr = (ImageView) $(R.id.iv_qr); 69 | 70 | mRecyclerView = (PullRecyclerView) $(R.id.mRecyclerView); 71 | mRecyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER); 72 | mRecyclerView.setOnHeaderRefreshListener(this);//设置下拉监听 73 | mRecyclerView.setOnFooterRefreshListener(this);//设置上拉监听 74 | mRecyclerView.setOnPullDownScrollListener(this);//设置下拉滑动监听 75 | mRecyclerView.setCanScrollAtRereshing(false);//设置正在刷新时是否可以滑动,默认不可滑动 76 | mRecyclerView.setCanPullDown(true);//设置是否可下拉 77 | mRecyclerView.setCanPullUp(true);//设置是否可上拉 78 | mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { 79 | @Override 80 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 81 | super.onScrollStateChanged(recyclerView, newState); 82 | } 83 | 84 | @Override 85 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) {//监听滑动距离以改变标题栏透明度 86 | super.onScrolled(recyclerView, dx, dy); 87 | y += dy; 88 | if (y >= bannerH) { 89 | rl_title.getBackground().setAlpha(255); 90 | rl_title.setVisibility(View.VISIBLE); 91 | } else if (y >= 0 && y < bannerH) { 92 | if (isPullDown) { 93 | rl_title.setVisibility(View.GONE); 94 | } else { 95 | rl_title.getBackground().setAlpha((int) (255 * ((double) y / bannerH))); 96 | rl_title.setVisibility(View.VISIBLE); 97 | } 98 | } else { 99 | rl_title.getBackground().setAlpha(0); 100 | rl_title.setVisibility(View.GONE); 101 | } 102 | } 103 | }); 104 | } 105 | 106 | @Override 107 | public void initClick() { 108 | tv_search.setOnClickListener(this); 109 | iv_qr.setOnClickListener(this); 110 | } 111 | 112 | @Override 113 | public void initData() { 114 | bannerH = SysUtil.dip2px(context, 200);//将banner高度转为px 115 | listbanner = new ArrayList<>(); 116 | listnews = new ArrayList<>(); 117 | 118 | newsPresenter = new NewsPresenter(context); 119 | newsPresenter.attachView(this); 120 | newsPresenter.getNews("10", String.valueOf(++page)); 121 | 122 | initRecyclerView(); 123 | } 124 | 125 | void initRecyclerView() { 126 | newsAdapter = new NewsAdapter(context, listbanner, listnews, this); 127 | mRecyclerView.setLayoutManager(new LinearLayoutManager(context)); 128 | newsAdapter.setOnItemClickListener(this); 129 | mRecyclerView.setAdapter(newsAdapter); 130 | } 131 | 132 | @Override 133 | public void onClick(View v) { 134 | switch (v.getId()) { 135 | case R.id.tv_search: 136 | Toast.makeText(context, "搜索", Toast.LENGTH_SHORT).show(); 137 | break; 138 | case R.id.iv_qr: 139 | Toast.makeText(context, "二维码", Toast.LENGTH_SHORT).show(); 140 | break; 141 | } 142 | } 143 | 144 | /** 145 | * 上拉加载 146 | * 147 | * @param view 148 | */ 149 | @Override 150 | public void onFooterRefresh(PullBaseView view) { 151 | newsPresenter.getNews("10", String.valueOf(++page)); 152 | } 153 | 154 | /** 155 | * 下拉刷新 156 | * 157 | * @param view 158 | */ 159 | @Override 160 | public void onHeaderRefresh(PullBaseView view) { 161 | page = 0; 162 | newsPresenter.getNews("10", String.valueOf(++page)); 163 | } 164 | 165 | @Override 166 | public void onPullDownScrolled() { 167 | isPullDown = true; 168 | rl_title.setVisibility(View.GONE); 169 | } 170 | 171 | @Override 172 | public void onPullDownFinished() { 173 | isPullDown = false; 174 | rl_title.setVisibility(View.VISIBLE); 175 | } 176 | 177 | 178 | /** 179 | * item点击监听 180 | * 181 | * @param position 182 | */ 183 | @Override 184 | public void onItemClick(int position) { 185 | Toast.makeText(context, ((News) listnews.get(position)).getTitle(), Toast.LENGTH_SHORT).show(); 186 | } 187 | 188 | /** 189 | * @param position item position 190 | * @param viewtype 点击的view的类型,调用时根据不同的view传入不同的值加以区分 191 | */ 192 | @Override 193 | public void onViewClick(int position, int viewtype) { 194 | switch (viewtype) { 195 | case 1: 196 | Toast.makeText(context, "新闻1", Toast.LENGTH_SHORT).show(); 197 | break; 198 | case 2: 199 | Toast.makeText(context, "新闻2", Toast.LENGTH_SHORT).show(); 200 | break; 201 | case 3: 202 | Toast.makeText(context, "新闻3", Toast.LENGTH_SHORT).show(); 203 | break; 204 | case 4: 205 | Toast.makeText(context, "新闻4", Toast.LENGTH_SHORT).show(); 206 | break; 207 | } 208 | 209 | } 210 | 211 | /** 212 | * 下拉请求成功 213 | * 214 | * @param newsBean 215 | */ 216 | @Override 217 | public void refreshSuccess(NewsBean newsBean) { 218 | mRecyclerView.onHeaderRefreshComplete(); 219 | //banner 模拟数据 220 | listbanner.clear(); 221 | ImageModel imageModel = new ImageModel(); 222 | imageModel.setUrl("https://ss2.baidu.com/-vo3dSag_xI4khGko9WTAnF6hhy/image/h%3D200/sign=650d5402a318972bbc3a07cad6cd7b9d/9f2f070828381f305c3fe5bfa1014c086e06f086.jpg"); 223 | listbanner.add(imageModel); 224 | imageModel = new ImageModel(); 225 | imageModel.setUrl("https://ss0.baidu.com/7Po3dSag_xI4khGko9WTAnF6hhy/image/h%3D200/sign=a219dde79125bc31345d06986ede8de7/a5c27d1ed21b0ef494399077d5c451da80cb3ec1.jpg"); 226 | listbanner.add(imageModel); 227 | imageModel = new ImageModel(); 228 | imageModel.setUrl("https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2040796625,1810502195&fm=111&gp=0.jpg"); 229 | listbanner.add(imageModel); 230 | //news 真实数据 231 | listnews.clear(); 232 | List list = newsBean.getShowapi_res_body().getNewslist(); 233 | for (News news : list) { 234 | listnews.add(news); 235 | } 236 | initRecyclerView(); 237 | } 238 | 239 | @Override 240 | public void loadMoreSuccess(NewsBean newsBean) { 241 | mRecyclerView.onFooterRefreshComplete(); 242 | List list = newsBean.getShowapi_res_body().getNewslist(); 243 | for (News news : list) { 244 | listnews.add(news); 245 | } 246 | newsAdapter.notifyDataSetChanged(); 247 | } 248 | 249 | /** 250 | * 请求失败 251 | * 252 | * @param message 253 | */ 254 | @Override 255 | public void fail(String message) { 256 | mRecyclerView.onHeaderRefreshComplete(); 257 | mRecyclerView.onFooterRefreshComplete(); 258 | Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); 259 | } 260 | 261 | @Override 262 | public void onDestroy() { 263 | super.onDestroy(); 264 | newsPresenter.detachView(); 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/main/FragmentTab2.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.main; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.app.FragmentActivity; 5 | import android.support.v4.view.ViewPager; 6 | import android.view.View; 7 | import android.support.design.widget.TabLayout; 8 | import android.widget.Toast; 9 | 10 | import com.byl.mvpdemo.R; 11 | import com.byl.mvpdemo.ui.base.BaseFragment; 12 | import com.byl.mvpdemo.ui.main.adapter.FragmentVedioAdapter; 13 | import com.byl.mvpdemo.ui.images.FragmentImageTab1; 14 | import com.byl.mvpdemo.ui.images.FragmentImageTab2; 15 | import com.byl.mvpdemo.util.LogUtil; 16 | 17 | 18 | public class FragmentTab2 extends BaseFragment { 19 | 20 | TabLayout mTabLayout; 21 | ViewPager mViewPager; 22 | 23 | Fragment[] mFragments; 24 | String[] mTitles; 25 | FragmentVedioAdapter fragmentVedioAdapter; 26 | 27 | @Override 28 | public int getContentView() { 29 | return R.layout.fragment_2; 30 | } 31 | 32 | @Override 33 | public void initView() { 34 | initTitleBar("", "图片", "", R.mipmap.ic_search, this); 35 | mTabLayout = (TabLayout) $(R.id.mTabLayout); 36 | mTabLayout.setBackgroundColor(getResources().getColor(R.color.common_title_bg)); 37 | mViewPager = (ViewPager) $(R.id.mViewPager); 38 | } 39 | 40 | @Override 41 | public void initClick() { 42 | 43 | } 44 | 45 | @Override 46 | public void initData() { 47 | mFragments = new Fragment[]{new FragmentImageTab1(), new FragmentImageTab2()}; 48 | mTitles = new String[]{"美女1", "美女2"}; 49 | fragmentVedioAdapter = new FragmentVedioAdapter(context, ((FragmentActivity) context).getSupportFragmentManager(), mFragments, mTitles); 50 | mViewPager.setAdapter(fragmentVedioAdapter); 51 | mTabLayout.setupWithViewPager(mViewPager); 52 | mTabLayout.getTabAt(0).select(); 53 | } 54 | 55 | @Override 56 | public void onClick(View v) { 57 | switch (v.getId()) { 58 | case R.id.iv_right://标题栏右侧图标 59 | Toast.makeText(context, "搜索", Toast.LENGTH_SHORT).show(); 60 | break; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/main/FragmentTab3.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.main; 2 | 3 | import android.view.View; 4 | import android.widget.LinearLayout; 5 | import android.widget.RelativeLayout; 6 | 7 | import com.byl.mvpdemo.R; 8 | import com.byl.mvpdemo.ui.base.BaseFragment; 9 | import com.byl.mvpdemo.util.LogUtil; 10 | 11 | 12 | /** 13 | */ 14 | public class FragmentTab3 extends BaseFragment { 15 | 16 | LinearLayout ll_head; 17 | 18 | @Override 19 | public int getContentView() { 20 | return R.layout.fragment_3; 21 | } 22 | 23 | @Override 24 | public void initView() { 25 | initTitleBar("", "我的", "", 0, this); 26 | ll_head = (LinearLayout) $(R.id.ll_head); 27 | ll_head.setBackgroundColor(getResources().getColor(R.color.common_title_bg)); 28 | } 29 | 30 | @Override 31 | public void initClick() { 32 | 33 | } 34 | 35 | @Override 36 | public void initData() { 37 | LogUtil.e("FragmentTab3"); 38 | } 39 | 40 | @Override 41 | public void onClick(View v) { 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/main/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.main; 2 | 3 | import android.support.design.widget.TabLayout; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v4.view.ViewPager; 6 | 7 | import com.byl.mvpdemo.R; 8 | import com.byl.mvpdemo.ui.base.BaseActivity; 9 | import com.byl.mvpdemo.ui.main.adapter.FragmentMainTabAdapter; 10 | 11 | 12 | /** 13 | * 主页 14 | */ 15 | public class MainActivity extends BaseActivity { 16 | 17 | ViewPager viewPager; 18 | TabLayout tabLayout; 19 | 20 | private String[] mTabTitles; 21 | private Integer[] mTabIcons; 22 | private Fragment[] mFragments; 23 | private FragmentMainTabAdapter fragmentMainTabAdapter; 24 | 25 | @Override 26 | public int getContentView() { 27 | return R.layout.activity_main; 28 | } 29 | 30 | @Override 31 | public void initView() { 32 | viewPager = (ViewPager) $(R.id.vp_content); 33 | tabLayout = (TabLayout) $(R.id.tabl_navigation); 34 | } 35 | 36 | @Override 37 | public void initClick() { 38 | 39 | } 40 | 41 | @Override 42 | public void initData() { 43 | mTabTitles = new String[]{"新闻", "图片", "我的"}; 44 | mTabIcons = new Integer[]{R.drawable.tab1_selector, R.drawable.tab2_selector, R.drawable.tab3_selector}; 45 | mFragments = new Fragment[]{new FragmentTab1(), new FragmentTab2(), new FragmentTab3()}; 46 | setupViewPager(); 47 | setupTabLayout(); 48 | tabLayout.getTabAt(0).select(); 49 | } 50 | 51 | private void setupTabLayout() { 52 | tabLayout.setTabMode(TabLayout.MODE_FIXED); 53 | tabLayout.setTabGravity(TabLayout.GRAVITY_FILL); 54 | tabLayout.setupWithViewPager(viewPager); 55 | for (int i = 0; i < tabLayout.getTabCount(); i++) { 56 | TabLayout.Tab tab = tabLayout.getTabAt(i); 57 | tab.setCustomView(fragmentMainTabAdapter.getTabView(i)); 58 | } 59 | tabLayout.requestFocus(); 60 | } 61 | 62 | private void setupViewPager() { 63 | fragmentMainTabAdapter = new FragmentMainTabAdapter(context, getSupportFragmentManager(), mFragments, mTabTitles, mTabIcons); 64 | viewPager.setAdapter(fragmentMainTabAdapter); 65 | viewPager.setOffscreenPageLimit(2); 66 | } 67 | 68 | 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/main/adapter/FragmentMainTabAdapter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.main.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v4.app.FragmentManager; 6 | import android.support.v4.app.FragmentStatePagerAdapter; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.widget.ImageView; 10 | import android.widget.TextView; 11 | 12 | import com.byl.mvpdemo.R; 13 | 14 | public class FragmentMainTabAdapter extends FragmentStatePagerAdapter { 15 | private Context mContext; 16 | 17 | private Fragment[] mFragments = null; 18 | private String[] mFragmentTitles =null; 19 | private Integer[] mFragmentIcons = null; 20 | 21 | public FragmentMainTabAdapter(Context context, FragmentManager fm, Fragment[] fragments, String[] titles, Integer[] icons) { 22 | super(fm); 23 | this.mContext = context; 24 | mFragments = fragments; 25 | mFragmentTitles = titles; 26 | mFragmentIcons = icons; 27 | } 28 | 29 | @Override 30 | public Fragment getItem(int position) { 31 | return mFragments[position]; 32 | } 33 | 34 | @Override 35 | public int getCount() { 36 | return mFragments.length; 37 | } 38 | 39 | @Override 40 | public CharSequence getPageTitle(int position) { 41 | return mFragmentTitles[position]; 42 | } 43 | 44 | public View getTabView(int position) { 45 | View tab = LayoutInflater.from(mContext).inflate(R.layout.item_main_tab, null); 46 | TextView tabText = (TextView) tab.findViewById(R.id.tv_title); 47 | ImageView tabImage = (ImageView) tab.findViewById(R.id.iv_icon); 48 | tabText.setText(mFragmentTitles[position]); 49 | tabImage.setBackgroundResource(mFragmentIcons[position]); 50 | if (position == 0) { 51 | tab.setSelected(true); 52 | } 53 | return tab; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/ui/main/adapter/FragmentVedioAdapter.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.ui.main.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v4.app.FragmentManager; 6 | import android.support.v4.app.FragmentStatePagerAdapter; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.widget.ImageView; 10 | import android.widget.TextView; 11 | 12 | import com.byl.mvpdemo.R; 13 | 14 | public class FragmentVedioAdapter extends FragmentStatePagerAdapter { 15 | private Context mContext; 16 | 17 | private Fragment[] mFragments = null; 18 | private String[] mFragmentTitles = null; 19 | 20 | public FragmentVedioAdapter(Context context, FragmentManager fm, Fragment[] fragments, String[] titles) { 21 | super(fm); 22 | this.mContext = context; 23 | mFragments = fragments; 24 | mFragmentTitles = titles; 25 | } 26 | 27 | @Override 28 | public Fragment getItem(int position) { 29 | return mFragments[position]; 30 | } 31 | 32 | @Override 33 | public int getCount() { 34 | return mFragments.length; 35 | } 36 | 37 | //此方法用来显示tab上的名字 38 | @Override 39 | public CharSequence getPageTitle(int position) { 40 | return mFragmentTitles[position]; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/util/LogUtil.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.util; 2 | 3 | import android.util.Log; 4 | 5 | public class LogUtil { 6 | 7 | public static final String LOG = "mvp"; 8 | 9 | public static boolean isShowLog = false;//true:打印log,false:不打印log 10 | 11 | public static void e(String message) { 12 | if (!isShowLog) return; 13 | Log.e(LOG, message); 14 | } 15 | 16 | public static void i(String message) { 17 | if (!isShowLog) return; 18 | Log.i(LOG, message); 19 | } 20 | 21 | public static void v(String message) { 22 | if (!isShowLog) return; 23 | Log.v(LOG, message); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/util/SysUtil.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.util; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * Created by baiyuliang on 2016-7-19. 7 | */ 8 | public class SysUtil { 9 | 10 | /** 11 | * 将dp转px 12 | * 13 | * @param context 14 | * @param dpValue 15 | * @return 16 | */ 17 | public static int dip2px(Context context, float dpValue) { 18 | final float scale = context.getResources().getDisplayMetrics().density; 19 | return (int) (dpValue * scale + 0.5f); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/view/MyLinearLayoutManager.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.view; 2 | 3 | /** 4 | * Created by baiyuliang on 2016-7-19. 5 | */ 6 | 7 | import android.content.Context; 8 | import android.support.v7.widget.LinearLayoutManager; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | 13 | public class MyLinearLayoutManager extends LinearLayoutManager { 14 | 15 | 16 | public MyLinearLayoutManager(Context context) { 17 | super(context); 18 | } 19 | 20 | public MyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { 21 | super(context, orientation, reverseLayout); 22 | } 23 | 24 | private int[] mMeasuredDimension = new int[2]; 25 | 26 | @Override 27 | public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, 28 | int widthSpec, int heightSpec) { 29 | 30 | final int widthMode = View.MeasureSpec.getMode(widthSpec); 31 | final int heightMode = View.MeasureSpec.getMode(heightSpec); 32 | final int widthSize = View.MeasureSpec.getSize(widthSpec); 33 | final int heightSize = View.MeasureSpec.getSize(heightSpec); 34 | 35 | int width = 0; 36 | int height = 0; 37 | for (int i = 0; i < getItemCount(); i++) { 38 | measureScrapChild(recycler, i, 39 | View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), 40 | View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), 41 | mMeasuredDimension); 42 | 43 | if (getOrientation() == HORIZONTAL) { 44 | width = width + mMeasuredDimension[0]; 45 | if (i == 0) { 46 | height = mMeasuredDimension[1]; 47 | } 48 | } else { 49 | height = height + mMeasuredDimension[1]; 50 | if (i == 0) { 51 | width = mMeasuredDimension[0]; 52 | } 53 | } 54 | } 55 | switch (widthMode) { 56 | case View.MeasureSpec.EXACTLY: 57 | width = widthSize; 58 | case View.MeasureSpec.AT_MOST: 59 | case View.MeasureSpec.UNSPECIFIED: 60 | } 61 | 62 | switch (heightMode) { 63 | case View.MeasureSpec.EXACTLY: 64 | height = heightSize; 65 | case View.MeasureSpec.AT_MOST: 66 | case View.MeasureSpec.UNSPECIFIED: 67 | } 68 | 69 | setMeasuredDimension(width, height); 70 | } 71 | 72 | private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, 73 | int heightSpec, int[] measuredDimension) { 74 | try { 75 | View view = recycler.getViewForPosition(0);//fix 动态添加时报IndexOutOfBoundsException 76 | 77 | if (view != null) { 78 | RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams(); 79 | 80 | int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, 81 | getPaddingLeft() + getPaddingRight(), p.width); 82 | 83 | int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, 84 | getPaddingTop() + getPaddingBottom(), p.height); 85 | 86 | view.measure(childWidthSpec, childHeightSpec); 87 | measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin; 88 | measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin; 89 | recycler.recycleView(view); 90 | } 91 | } catch (Exception e) { 92 | e.printStackTrace(); 93 | } finally { 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/view/MyProgressDialog.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.view; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Dialog; 5 | import android.content.Context; 6 | import android.os.Build; 7 | import android.view.View; 8 | import android.view.Window; 9 | import android.view.WindowManager; 10 | import android.view.animation.Animation; 11 | import android.view.animation.LinearInterpolator; 12 | import android.view.animation.RotateAnimation; 13 | import android.widget.ImageView; 14 | import android.widget.TextView; 15 | 16 | import com.byl.mvpdemo.R; 17 | 18 | 19 | /** 20 | * 21 | * Date: 2014-06-19 22 | * 23 | * @author byl 24 | */ 25 | public class MyProgressDialog extends Dialog { 26 | 27 | private ImageView iv_route; 28 | private TextView tv; 29 | private RotateAnimation mAnim; 30 | private boolean cancelable = true; 31 | 32 | 33 | public MyProgressDialog(Context context) { 34 | super(context, R.style.Dialog_bocop); 35 | init(); 36 | } 37 | 38 | @SuppressWarnings("ResourceType") 39 | private void init() { 40 | View contentView = View.inflate(getContext(), R.layout.loading_dialog, null); 41 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 42 | Window win = getWindow(); 43 | WindowManager.LayoutParams winParams = win.getAttributes(); 44 | winParams.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; 45 | win.setAttributes(winParams); 46 | } 47 | setContentView(contentView); 48 | 49 | contentView.setOnClickListener(new View.OnClickListener() { 50 | @Override 51 | public void onClick(View v) { 52 | if (cancelable) { 53 | dismiss(); 54 | } 55 | } 56 | }); 57 | iv_route = (ImageView) findViewById(R.id.iv_route); 58 | tv = (TextView) findViewById(R.id.tv); 59 | initAnim(); 60 | getWindow().setWindowAnimations(R.anim.alpha_in); 61 | } 62 | 63 | 64 | private void initAnim() { 65 | mAnim=new RotateAnimation(0, 359, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); 66 | mAnim.setDuration(1500); 67 | mAnim.setInterpolator(new LinearInterpolator()); 68 | mAnim.setFillAfter(true); 69 | mAnim.setRepeatCount(-1); 70 | } 71 | 72 | @Override 73 | public void show() { 74 | iv_route.startAnimation(mAnim); 75 | super.show(); 76 | } 77 | 78 | @SuppressLint("NewApi") 79 | @Override 80 | public void dismiss() { 81 | mAnim.cancel(); 82 | super.dismiss(); 83 | } 84 | 85 | 86 | @Override 87 | public void setCancelable(boolean flag) { 88 | cancelable = flag; 89 | super.setCancelable(flag); 90 | } 91 | 92 | @Override 93 | public void setTitle(CharSequence title) { 94 | tv.setText(title); 95 | } 96 | 97 | public void setMessage(String title) { 98 | tv.setText(title); 99 | } 100 | 101 | @Override 102 | public void setTitle(int titleId) { 103 | setTitle(getContext().getString(titleId)); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/view/pullrecyclerview/PullBaseView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.view.pullrecyclerview; 2 | 3 | import android.content.Context; 4 | import android.graphics.drawable.AnimationDrawable; 5 | import android.support.v7.widget.LinearLayoutManager; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.util.AttributeSet; 8 | import android.view.LayoutInflater; 9 | import android.view.MotionEvent; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.LinearLayout; 13 | import android.widget.ProgressBar; 14 | import android.widget.TextView; 15 | 16 | import com.byl.mvpdemo.R; 17 | 18 | 19 | /** 20 | * 基类:重写LinearLayout,在LinearLayout中依次添加headerview-RecyclerView-footerview, 21 | * 并对LinearLayout进行手势监听 22 | * http://blog.csdn.net/baiyuliang2013 23 | */ 24 | public abstract class PullBaseView extends LinearLayout { 25 | 26 | protected T mRecyclerView; 27 | private boolean isCanScrollAtRereshing = false;//刷新时是否可滑动 28 | private boolean isCanPullDown = true;//是否可下拉 29 | private boolean isCanPullUp = true;//是否可上拉 30 | 31 | // pull state 32 | private static final int PULL_DOWN_STATE = 0;//下拉 33 | private static final int PULL_UP_STATE = 1;//上拉 34 | // refresh states 35 | private static final int PULL_TO_REFRESH = 2;//未达到刷新条件 36 | private static final int RELEASE_TO_REFRESH = 3;//已达到刷新条件 37 | private static final int REFRESHING = 4;//正在刷新 38 | 39 | private int mLastMotionY;//last y 40 | private View mHeaderView;//HeaderView 41 | private View mFooterView;//FooterView 42 | private int mHeaderViewHeight;//HeaderView的高度 43 | private int mFooterViewHeight;//FooterView的高度 44 | private TextView mFooterTextView;//FooterView提示语 45 | private ProgressBar mFooterProgressBar;//FooterView ProgressBar 46 | 47 | private int mHeaderState;//HeaderView当前刷新状态 48 | private int mFooterState;//FooterView当前刷新状态 49 | private int mPullState;//刷新状态:下拉或上拉 50 | 51 | private OnHeaderRefreshListener mOnHeaderRefreshListener;//HeaderView刷新监听 52 | private OnFooterRefreshListener mOnFooterRefreshListener;//FooterView刷新监听 53 | private OnPullDownScrollListener onPullDownScrollListener; 54 | 55 | private float startY;//手指落点 56 | private float offsetY;//手指滑动的距离 57 | 58 | //headview中的动画实现 59 | private RefreshAnimView refreshAnimView; 60 | private RefreshLoadingView refreshLoadingView; 61 | private AnimationDrawable loadAnimation; 62 | 63 | private LayoutInflater mInflater; 64 | 65 | public PullBaseView(Context context) { 66 | super(context); 67 | } 68 | 69 | public PullBaseView(Context context, AttributeSet attrs) { 70 | super(context, attrs); 71 | init(context, attrs); 72 | } 73 | 74 | /** 75 | * init 76 | */ 77 | private void init(Context context, AttributeSet attrs) { 78 | mInflater = LayoutInflater.from(getContext()); 79 | addHeaderView();//首先在Linear中添加headview 80 | mRecyclerView = createRecyclerView(context, attrs); 81 | mRecyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER); 82 | addView(mRecyclerView);//添加RecyclerView 83 | } 84 | 85 | /** 86 | * header view 87 | */ 88 | private void addHeaderView() { 89 | mHeaderView = mInflater.inflate(R.layout.refresh_header, this, false); 90 | refreshAnimView = (RefreshAnimView) mHeaderView.findViewById(R.id.first_step_view); 91 | refreshLoadingView = (RefreshLoadingView) mHeaderView.findViewById(R.id.second_step_view); 92 | refreshLoadingView.setBackgroundResource(R.drawable.anim_refresh); 93 | loadAnimation = (AnimationDrawable) refreshLoadingView.getBackground(); 94 | measureView(mHeaderView);//测量高度 95 | mHeaderViewHeight = mHeaderView.getMeasuredHeight(); 96 | LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mHeaderViewHeight); 97 | params.topMargin = -(mHeaderViewHeight);// 设置topMargin的值为负的header View高度,即将其隐藏在最上方 98 | addView(mHeaderView, params); 99 | 100 | } 101 | 102 | /** 103 | * footer view 104 | */ 105 | private void addFooterView() { 106 | mFooterView = mInflater.inflate(R.layout.refresh_footer, this, false); 107 | mFooterTextView = (TextView) mFooterView.findViewById(R.id.pull_to_load_text); 108 | mFooterProgressBar = (ProgressBar) mFooterView.findViewById(R.id.pull_to_load_progress); 109 | measureView(mFooterView); 110 | mFooterViewHeight = mFooterView.getMeasuredHeight(); 111 | LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mFooterViewHeight); 112 | addView(mFooterView, params); 113 | } 114 | 115 | @Override 116 | protected void onFinishInflate() { 117 | super.onFinishInflate(); 118 | addFooterView();//最后添加footview 119 | } 120 | 121 | /** 122 | * dispatchTouchEvent 在最顶级也就是父布局(Linear)中拦截手势监听 123 | * 1.处理正在刷新时是否可以滑动 124 | * 2.处理头部动画 125 | * 126 | * @param ev 127 | * @return 128 | */ 129 | @Override 130 | public boolean dispatchTouchEvent(MotionEvent ev) { 131 | switch (ev.getAction()) { 132 | case MotionEvent.ACTION_DOWN: 133 | startY = ev.getY(); 134 | break; 135 | case MotionEvent.ACTION_MOVE: 136 | offsetY = ev.getY() - startY; 137 | if (!isCanScrollAtRereshing) { 138 | if (mHeaderState == REFRESHING || mFooterState == REFRESHING) { 139 | return true; 140 | } 141 | } 142 | if (isCanPullUp && offsetY > 0) { 143 | float headerViewShowHeight = offsetY * 0.3f;//headview露出的高度 144 | float currentProgress = headerViewShowHeight / mHeaderViewHeight;//根据此比例,在滑动时改变动图大小 145 | if (currentProgress >= 1) { 146 | currentProgress = 1; 147 | } 148 | if (mHeaderState == PULL_TO_REFRESH || mHeaderState == RELEASE_TO_REFRESH) { 149 | refreshAnimView.setCurrentProgress(currentProgress);//绘制headview中的动画 150 | refreshAnimView.postInvalidate(); 151 | } 152 | } 153 | break; 154 | } 155 | return super.dispatchTouchEvent(ev); 156 | } 157 | 158 | @Override 159 | public boolean onInterceptTouchEvent(MotionEvent e) { 160 | int y = (int) e.getRawY(); 161 | switch (e.getAction()) { 162 | case MotionEvent.ACTION_DOWN: 163 | mLastMotionY = y;// 首先拦截down事件,记录y坐标 164 | break; 165 | case MotionEvent.ACTION_MOVE: 166 | int deltaY = y - mLastMotionY; // deltaY > 0 是向下运动,< 0是向上运动 167 | if (isRefreshViewScroll(deltaY)) { 168 | return true; 169 | } 170 | break; 171 | } 172 | return false; 173 | } 174 | 175 | /** 176 | * 如果在onInterceptTouchEvent()方法中没有拦截(即onInterceptTouchEvent()方法中 return false), 177 | * 则由PullBaseView的子View来处理;否则由下面的方法来处理(即由PullBaseView自己来处理) 178 | */ 179 | @Override 180 | public boolean onTouchEvent(MotionEvent event) { 181 | int y = (int) event.getRawY(); 182 | switch (event.getAction()) { 183 | case MotionEvent.ACTION_MOVE: 184 | int deltaY = y - mLastMotionY; 185 | if (isCanPullDown && mPullState == PULL_DOWN_STATE) { 186 | if (onPullDownScrollListener != null) { 187 | onPullDownScrollListener.onPullDownScrolled(); 188 | } 189 | headerPrepareToRefresh(deltaY); 190 | } else if (isCanPullUp && mPullState == PULL_UP_STATE) { 191 | footerPrepareToRefresh(deltaY); 192 | } 193 | mLastMotionY = y; 194 | break; 195 | case MotionEvent.ACTION_UP: 196 | case MotionEvent.ACTION_CANCEL: 197 | int topMargin = getHeaderTopMargin(); 198 | if (isCanPullDown && mPullState == PULL_DOWN_STATE) { 199 | if (topMargin >= 0) { 200 | headerRefreshing(); // 开始刷新 201 | } else { 202 | if (onPullDownScrollListener != null) { 203 | onPullDownScrollListener.onPullDownFinished(); 204 | } 205 | setHeaderTopMargin(-mHeaderViewHeight); // 还没有执行刷新,重新隐藏 206 | } 207 | } else if (isCanPullUp && mPullState == PULL_UP_STATE) { 208 | if (Math.abs(topMargin) >= mHeaderViewHeight + mFooterViewHeight) { 209 | footerRefreshing();// 开始执行footer 刷新 210 | } else { 211 | setHeaderTopMargin(-mHeaderViewHeight);// 还没有执行刷新,重新隐藏 212 | } 213 | } 214 | break; 215 | } 216 | return super.onTouchEvent(event); 217 | } 218 | 219 | /** 220 | * 是否应该到了父View,即PullBaseView滑动 221 | * 222 | * @param deltaY , deltaY > 0 是向下运动,< 0是向上运动 223 | * @return 224 | */ 225 | private boolean isRefreshViewScroll(int deltaY) { 226 | if (mHeaderState == REFRESHING || mFooterState == REFRESHING) { 227 | return false; 228 | } 229 | if (deltaY >= -20 && deltaY <= 20) 230 | return false; 231 | 232 | if (mRecyclerView != null) { 233 | // 滑动到最顶端 234 | if (deltaY > 0) { 235 | View child = mRecyclerView.getChildAt(0); 236 | if (child == null) { 237 | // mRecyclerView,不拦截 238 | return false; 239 | } 240 | if (isScrollTop() && child.getTop() == 0) { 241 | mPullState = PULL_DOWN_STATE; 242 | return true; 243 | } 244 | int top = child.getTop(); 245 | int padding = mRecyclerView.getPaddingTop(); 246 | if (isScrollTop() && Math.abs(top - padding) <= 8) { 247 | mPullState = PULL_DOWN_STATE; 248 | return true; 249 | } 250 | 251 | } else if (deltaY < 0) { 252 | View lastChild = mRecyclerView.getChildAt(mRecyclerView.getChildCount() - 1); 253 | if (lastChild == null) { 254 | // mRecyclerView,不拦截 255 | return false; 256 | } 257 | // 最后一个子view的Bottom小于父View的高度说明mRecyclerView的数据没有填满父view, 258 | // 等于父View的高度说明mRecyclerView已经滑动到最后 259 | if (lastChild.getBottom() <= getHeight() && isScrollBottom()) { 260 | mPullState = PULL_UP_STATE; 261 | return true; 262 | } 263 | } 264 | } 265 | return false; 266 | } 267 | 268 | /** 269 | * 判断mRecyclerView是否滑动到顶部 270 | * 271 | * @return 272 | */ 273 | boolean isScrollTop() { 274 | LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager(); 275 | if (linearLayoutManager.findFirstVisibleItemPosition() == 0) { 276 | return true; 277 | } else { 278 | return false; 279 | } 280 | } 281 | 282 | /** 283 | * 判断mRecyclerView是否滑动到底部 284 | * 285 | * @return 286 | */ 287 | boolean isScrollBottom() { 288 | LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager(); 289 | if (linearLayoutManager.findLastVisibleItemPosition() == (mRecyclerView.getAdapter().getItemCount() - 1)) { 290 | return true; 291 | } else { 292 | return false; 293 | } 294 | } 295 | 296 | /** 297 | * header 准备刷新,手指移动过程,还没有释放 298 | * 299 | * @param deltaY ,手指滑动的距离 300 | */ 301 | private void headerPrepareToRefresh(int deltaY) { 302 | int newTopMargin = changingHeaderViewTopMargin(deltaY); 303 | // 当header view的topMargin>=0时,说明已经完全显示出来了,修改header view 的提示状态 304 | if (newTopMargin >= 0 && mHeaderState != RELEASE_TO_REFRESH) { 305 | mHeaderState = RELEASE_TO_REFRESH; 306 | } else if (newTopMargin < 0 && newTopMargin > -mHeaderViewHeight) {// 拖动时没有释放 307 | mHeaderState = PULL_TO_REFRESH; 308 | } 309 | } 310 | 311 | /** 312 | * footer 准备刷新,手指移动过程,还没有释放 移动footer view高度同样和移动header view 313 | * 高度是一样,都是通过修改header view的topmargin的值来达到 314 | * 315 | * @param deltaY ,手指滑动的距离 316 | */ 317 | private void footerPrepareToRefresh(int deltaY) { 318 | int newTopMargin = changingHeaderViewTopMargin(deltaY); 319 | // 如果header view topMargin 的绝对值大于或等于header + footer 的高度 320 | // 说明footer view 完全显示出来了,修改footer view 的提示状态 321 | if (Math.abs(newTopMargin) >= (mHeaderViewHeight + mFooterViewHeight) && mFooterState != RELEASE_TO_REFRESH) { 322 | mFooterTextView.setText(R.string.pull_to_refresh_footer_release_label); 323 | mFooterState = RELEASE_TO_REFRESH; 324 | } else if (Math.abs(newTopMargin) < (mHeaderViewHeight + mFooterViewHeight)) { 325 | mFooterTextView.setText(R.string.pull_to_refresh_footer_pull_label); 326 | mFooterState = PULL_TO_REFRESH; 327 | } 328 | } 329 | 330 | /** 331 | * 修改Header view top margin的值 332 | * 333 | * @param deltaY 334 | */ 335 | private int changingHeaderViewTopMargin(int deltaY) { 336 | LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams(); 337 | float newTopMargin = params.topMargin + deltaY * 0.3f; 338 | // 这里对上拉做一下限制,因为当前上拉后然后不释放手指直接下拉,会把下拉刷新给触发了 339 | // 表示如果是在上拉后一段距离,然后直接下拉 340 | if (deltaY > 0 && mPullState == PULL_UP_STATE && Math.abs(params.topMargin) <= mHeaderViewHeight) { 341 | return params.topMargin; 342 | } 343 | // 同样地,对下拉做一下限制,避免出现跟上拉操作时一样的bug 344 | if (deltaY < 0 && mPullState == PULL_DOWN_STATE && Math.abs(params.topMargin) >= mHeaderViewHeight) { 345 | return params.topMargin; 346 | } 347 | params.topMargin = (int) newTopMargin; 348 | mHeaderView.setLayoutParams(params); 349 | invalidate(); 350 | return params.topMargin; 351 | } 352 | 353 | /** 354 | * header refreshing 355 | */ 356 | public void headerRefreshing() { 357 | mHeaderState = REFRESHING; 358 | setHeaderTopMargin(0); 359 | refreshAnimView.setVisibility(View.GONE); 360 | refreshLoadingView.setVisibility(View.VISIBLE); 361 | loadAnimation.start(); 362 | if (mOnHeaderRefreshListener != null) { 363 | mOnHeaderRefreshListener.onHeaderRefresh(this); 364 | } 365 | } 366 | 367 | /** 368 | * footer refreshing 369 | */ 370 | private void footerRefreshing() { 371 | mFooterState = REFRESHING; 372 | int top = mHeaderViewHeight + mFooterViewHeight; 373 | setHeaderTopMargin(-top); 374 | mFooterTextView.setText(R.string.pull_to_refresh_footer_refreshing_label); 375 | mFooterProgressBar.setVisibility(View.VISIBLE); 376 | if (mOnFooterRefreshListener != null) { 377 | mOnFooterRefreshListener.onFooterRefresh(this); 378 | } 379 | } 380 | 381 | /** 382 | * 设置header view 的topMargin的值 383 | * 384 | * @param topMargin ,为0时,说明header view 刚好完全显示出来; 为-mHeaderViewHeight时,说明完全隐藏了 385 | */ 386 | private void setHeaderTopMargin(int topMargin) { 387 | LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams(); 388 | params.topMargin = topMargin; 389 | mHeaderView.setLayoutParams(params); 390 | invalidate(); 391 | } 392 | 393 | /** 394 | * header view 完成更新后恢复初始状态 395 | */ 396 | public void onHeaderRefreshComplete() { 397 | setHeaderTopMargin(-mHeaderViewHeight); 398 | refreshAnimView.setVisibility(View.VISIBLE); 399 | refreshLoadingView.setVisibility(View.GONE); 400 | loadAnimation.stop(); 401 | mHeaderState = PULL_TO_REFRESH; 402 | if (onPullDownScrollListener != null) { 403 | onPullDownScrollListener.onPullDownFinished(); 404 | } 405 | } 406 | 407 | 408 | /** 409 | * footer view 完成更新后恢复初始状态 410 | */ 411 | public void onFooterRefreshComplete() { 412 | setHeaderTopMargin(-mHeaderViewHeight); 413 | mFooterTextView.setText(R.string.pull_to_refresh_footer_pull_label); 414 | mFooterProgressBar.setVisibility(View.GONE); 415 | mFooterState = PULL_TO_REFRESH; 416 | if (mRecyclerView != null) { 417 | mRecyclerView.scrollToPosition(mRecyclerView.getAdapter().getItemCount() - 1); 418 | } 419 | 420 | } 421 | 422 | /** 423 | * 获取当前header view 的topMargin 424 | */ 425 | private int getHeaderTopMargin() { 426 | LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams(); 427 | return params.topMargin; 428 | } 429 | 430 | 431 | /** 432 | * 设置下拉监听接口 433 | */ 434 | public void setOnHeaderRefreshListener(OnHeaderRefreshListener headerRefreshListener) { 435 | mOnHeaderRefreshListener = headerRefreshListener; 436 | } 437 | 438 | /** 439 | * 设置上拉监听接口 440 | */ 441 | public void setOnFooterRefreshListener(OnFooterRefreshListener footerRefreshListener) { 442 | mOnFooterRefreshListener = footerRefreshListener; 443 | } 444 | 445 | /** 446 | * 上拉监听 447 | */ 448 | public interface OnFooterRefreshListener { 449 | void onFooterRefresh(PullBaseView view); 450 | } 451 | 452 | /** 453 | * 下拉监听 454 | */ 455 | public interface OnHeaderRefreshListener { 456 | void onHeaderRefresh(PullBaseView view); 457 | } 458 | 459 | /** 460 | * 下拉滑动动作监听 461 | */ 462 | public interface OnPullDownScrollListener { 463 | void onPullDownScrolled(); 464 | 465 | void onPullDownFinished(); 466 | } 467 | 468 | public void setOnPullDownScrollListener(OnPullDownScrollListener onPullDownScrollListener) { 469 | this.onPullDownScrollListener = onPullDownScrollListener; 470 | } 471 | 472 | /** 473 | * 设置是否可以在刷新时滑动 474 | * 475 | * @param canScrollAtRereshing 476 | */ 477 | public void setCanScrollAtRereshing(boolean canScrollAtRereshing) { 478 | isCanScrollAtRereshing = canScrollAtRereshing; 479 | } 480 | 481 | /** 482 | * 设置是否可上拉 483 | * 484 | * @param canPullUp 485 | */ 486 | public void setCanPullUp(boolean canPullUp) { 487 | isCanPullUp = canPullUp; 488 | } 489 | 490 | /** 491 | * 设置是否可下拉 492 | * 493 | * @param canPullDown 494 | */ 495 | public void setCanPullDown(boolean canPullDown) { 496 | isCanPullDown = canPullDown; 497 | } 498 | 499 | private void measureView(View child) { 500 | ViewGroup.LayoutParams p = child.getLayoutParams(); 501 | if (p == null) { 502 | p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); 503 | } 504 | int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width); 505 | int lpHeight = p.height; 506 | int childHeightSpec; 507 | if (lpHeight > 0) { 508 | childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); 509 | } else { 510 | childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 511 | } 512 | child.measure(childWidthSpec, childHeightSpec); 513 | } 514 | 515 | 516 | /** 517 | * 抽象方法,子类实现,传入View 518 | * 519 | * @param context 520 | * @param attrs 521 | * @return 522 | */ 523 | protected abstract T createRecyclerView(Context context, AttributeSet attrs); 524 | 525 | } 526 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/view/pullrecyclerview/PullRecyclerView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.view.pullrecyclerview; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.util.AttributeSet; 6 | 7 | /** 8 | * RecyclerView中的所有方法都可以在此类中设置,暴露出去以供调用 9 | */ 10 | public class PullRecyclerView extends PullBaseView { 11 | 12 | 13 | public PullRecyclerView(Context context) { 14 | this(context, null); 15 | } 16 | 17 | public PullRecyclerView(Context context, AttributeSet attrs) { 18 | super(context, attrs); 19 | } 20 | 21 | 22 | @Override 23 | protected RecyclerView createRecyclerView(Context context, AttributeSet attrs) { 24 | return new RecyclerView(context, attrs); 25 | } 26 | 27 | public void setAdapter(RecyclerView.Adapter adapter) { 28 | mRecyclerView.setAdapter(adapter); 29 | } 30 | 31 | public void setLayoutManager(RecyclerView.LayoutManager manager) { 32 | mRecyclerView.setLayoutManager(manager); 33 | } 34 | 35 | public void addOnScrollListener(RecyclerView.OnScrollListener onScrollListener) { 36 | mRecyclerView.addOnScrollListener(onScrollListener); 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/view/pullrecyclerview/RefreshAnimView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.view.pullrecyclerview; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.graphics.Canvas; 7 | import android.graphics.Paint; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | 11 | import com.byl.mvpdemo.R; 12 | 13 | 14 | public class RefreshAnimView extends View{ 15 | 16 | private Bitmap daishu; 17 | private int measuredWidth; 18 | private int measuredHeight; 19 | private float mCurrentProgress; 20 | private int mCurrentAlpha; 21 | private Paint mPaint; 22 | private Bitmap scaleDaishu; 23 | 24 | public RefreshAnimView(Context context, AttributeSet attrs, int defStyle) { 25 | super(context, attrs, defStyle); 26 | init(); 27 | } 28 | 29 | public RefreshAnimView(Context context, AttributeSet attrs) { 30 | super(context, attrs); 31 | init(); 32 | } 33 | 34 | public RefreshAnimView(Context context) { 35 | super(context); 36 | init(); 37 | } 38 | private void init(){ 39 | //袋鼠bitmap 40 | daishu = BitmapFactory.decodeResource(getResources(), R.mipmap.takeout_img_list_loading_pic1); 41 | //来个画笔,我们注意到袋鼠都有一个渐变效果的,我们用 42 | //mPaint.setAlpha来实现这个渐变的效果 43 | mPaint = new Paint(); 44 | //首先设置为完全透明 45 | mPaint.setAlpha(0); 46 | } 47 | 48 | /** 49 | * 测量方法 50 | * @param widthMeasureSpec 51 | * @param heightMeasureSpec 52 | */ 53 | @Override 54 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 55 | setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); 56 | } 57 | //测量宽度 58 | private int measureWidth(int widthMeasureSpec){ 59 | int result = 0; 60 | int size = MeasureSpec.getSize(widthMeasureSpec); 61 | int mode = MeasureSpec.getMode(widthMeasureSpec); 62 | if (MeasureSpec.EXACTLY == mode) { 63 | result = size; 64 | }else { 65 | result = daishu.getWidth(); 66 | if (MeasureSpec.AT_MOST == mode) { 67 | result = Math.min(result, size); 68 | } 69 | } 70 | return result; 71 | } 72 | //测量高度 73 | private int measureHeight(int heightMeasureSpec){ 74 | int result = 0; 75 | int size = MeasureSpec.getSize(heightMeasureSpec); 76 | int mode = MeasureSpec.getMode(heightMeasureSpec); 77 | if (MeasureSpec.EXACTLY == mode) { 78 | result = size; 79 | }else { 80 | result = daishu.getHeight(); 81 | if (MeasureSpec.AT_MOST == mode) { 82 | result = Math.min(result, size); 83 | } 84 | } 85 | return result; 86 | } 87 | //在这里面拿到测量后的宽和高,w就是测量后的宽,h是测量后的高 88 | @Override 89 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 90 | super.onSizeChanged(w, h, oldw, oldh); 91 | measuredWidth = w; 92 | measuredHeight = h; 93 | //根据测量后的宽高来对袋鼠做一个缩放 94 | scaleDaishu = Bitmap.createScaledBitmap(daishu,measuredWidth,measuredHeight,true); 95 | } 96 | 97 | /** 98 | * 绘制方法 99 | * @param canvas 100 | */ 101 | @Override 102 | protected void onDraw(Canvas canvas) { 103 | super.onDraw(canvas); 104 | canvas.scale(mCurrentProgress, mCurrentProgress, measuredWidth/2, measuredHeight); 105 | mPaint.setAlpha(mCurrentAlpha); 106 | canvas.drawBitmap(scaleDaishu, 0, 0, mPaint); 107 | } 108 | 109 | /** 110 | * 根据进度对袋鼠进行缩放 111 | * @param currentProgress 112 | */ 113 | public void setCurrentProgress(float currentProgress){ 114 | this.mCurrentProgress = currentProgress; 115 | this.mCurrentAlpha = (int) (currentProgress*255); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /app/src/main/java/com/byl/mvpdemo/view/pullrecyclerview/RefreshLoadingView.java: -------------------------------------------------------------------------------- 1 | package com.byl.mvpdemo.view.pullrecyclerview; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.util.AttributeSet; 7 | import android.view.View; 8 | 9 | import com.byl.mvpdemo.R; 10 | 11 | 12 | public class RefreshLoadingView extends View { 13 | 14 | private Bitmap endBitmap; 15 | 16 | public RefreshLoadingView(Context context, AttributeSet attrs, int defStyle) { 17 | super(context, attrs, defStyle); 18 | init(); 19 | } 20 | 21 | public RefreshLoadingView(Context context, AttributeSet attrs) { 22 | super(context, attrs); 23 | init(); 24 | } 25 | 26 | public RefreshLoadingView(Context context) { 27 | super(context); 28 | init(); 29 | } 30 | 31 | private void init() { 32 | endBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.takeout_img_list_loading_pic1); 33 | } 34 | 35 | /** 36 | * 只需要测量方法 37 | * 38 | * @param widthMeasureSpec 39 | * @param heightMeasureSpec 40 | */ 41 | @Override 42 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 43 | setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); 44 | } 45 | 46 | private int measureWidth(int widthMeasureSpec) { 47 | int result = 0; 48 | int size = MeasureSpec.getSize(widthMeasureSpec); 49 | int mode = MeasureSpec.getMode(widthMeasureSpec); 50 | if (MeasureSpec.EXACTLY == mode) { 51 | result = size; 52 | } else { 53 | result = endBitmap.getWidth(); 54 | if (MeasureSpec.AT_MOST == mode) { 55 | result = Math.min(size, result); 56 | } 57 | } 58 | return result; 59 | } 60 | 61 | private int measureHeight(int heightMeasureSpec) { 62 | int result = 0; 63 | int size = MeasureSpec.getSize(heightMeasureSpec); 64 | int mode = MeasureSpec.getMode(heightMeasureSpec); 65 | if (MeasureSpec.EXACTLY == mode) { 66 | result = size; 67 | } else { 68 | result = endBitmap.getHeight(); 69 | if (MeasureSpec.AT_MOST == mode) { 70 | result = Math.min(size, result); 71 | } 72 | } 73 | return result; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/res/anim/alpha_in.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/color/main_tab_text_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 13 | 14 | 19 | 24 | 25 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/anim_refresh.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/common_back_arrow_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/common_btn_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/common_image_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/common_text_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_common.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_common_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_common_button_press.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_common_transparent.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_common_white.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tab1_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tab2_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tab3_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tab_text_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_login.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 17 | 18 | 28 | 29 | 38 | 39 | 40 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 12 | 13 | 17 | 18 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/layout/common_title_bar.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 19 | 20 | 27 | 28 | 37 | 38 | 50 | 51 | 61 | 62 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 15 | 20 | 21 | 35 | 36 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 23 | 24 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 15 | 16 | 20 | 21 | 28 | 29 | 34 | 35 | 42 | 43 | 44 | 45 | 53 | 54 | 60 | 61 | 62 | 63 | 71 | 72 | 78 | 79 | 80 | 81 | 89 | 90 | 96 | 97 | 98 | 99 | 100 | 108 | 109 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_images_tab1.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_images_tab2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_girls.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 22 | 23 | 34 | 35 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_home_head.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 19 | 20 | 26 | 27 | 36 | 37 | 41 | 42 | 49 | 50 | 51 | 52 | 58 | 59 | 68 | 69 | 73 | 74 | 81 | 82 | 83 | 84 | 90 | 91 | 100 | 101 | 105 | 106 | 113 | 114 | 115 | 116 | 122 | 123 | 132 | 133 | 137 | 138 | 145 | 146 | 147 | 148 | 149 | 150 | 154 | 155 | 160 | 161 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_img.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_main_tab.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_news.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 21 | 22 | 28 | 29 | 38 | 39 | 49 | 50 | 59 | 60 | 61 | 62 | 63 | 67 | -------------------------------------------------------------------------------- /app/src/main/res/layout/loading_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | 20 | 21 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/refresh_footer.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/refresh_header.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 10 | 11 | 18 | 19 | 27 | 28 | 29 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/banner.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/fop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/fop.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/head_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/head_default.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/home_icon_cg_glfriends.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/home_icon_cg_glfriends.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/home_icon_cg_glhouse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/home_icon_cg_glhouse.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/home_icon_cg_gllaw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/home_icon_cg_gllaw.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/home_icon_cg_gllife.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/home_icon_cg_gllife.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_common_back_arrow_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/ic_common_back_arrow_normal.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_common_back_arrow_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/ic_common_back_arrow_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_loading_dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/ic_loading_dialog.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_pulltorefresh_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/ic_pulltorefresh_arrow.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_pulltorefresh_arrow_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/ic_pulltorefresh_arrow_up.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/ic_search.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_tabbar_favorites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/icon_tabbar_favorites.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_tabbar_favorites_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/icon_tabbar_favorites_selected.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_tabbar_library.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/icon_tabbar_library.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_tabbar_library_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/icon_tabbar_library_selected.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_tabbar_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/icon_tabbar_settings.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/icon_tabbar_settings_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/icon_tabbar_settings_selected.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/iv_qr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/iv_qr.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/takeout_img_list_loading_pic1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/takeout_img_list_loading_pic1.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/takeout_img_list_loading_pic2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxhdpi/takeout_img_list_loading_pic2.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FF0000 4 | #FF0000 5 | #FF0000 6 | 7 | 8 | #FF0000 9 | #F00000 10 | #000000 11 | #F0F0F0 12 | 13 | 14 | #A2A2A2 15 | #2D6EFA 16 | 17 | #999999 18 | #50000000 19 | #FFFFFF 20 | #EEEEEE 21 | #cccccc 22 | #999999 23 | 24 | #30000000 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | MVPDemo 3 | 登录 4 | 5 | 6 | 请输入手机号 7 | 请输入密码 8 | 登录 9 | 10 | 下拉刷新 11 | 松开刷新 12 | 正在刷新\u2026 13 | 松开加载更多 14 | 上拉加载更多 15 | 加载中\u2026 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 16 | 17 | 18 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /appdemo.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/appdemo.apk -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.1.2' 9 | classpath 'me.tatarka:gradle-retrolambda:3.1.0' 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyuliang/MVP-Retrofit-RxJava/732a02e971dfffd7eb61e00394b94bd24a77e730/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------