├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml └── runConfigurations.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── qyh │ │ └── androidprojecthelper │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── qyh │ │ │ └── androidprojecthelper │ │ │ ├── LuncherActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── adapter │ │ │ └── FirstTabAdapter.java │ │ │ ├── api │ │ │ ├── Api.java │ │ │ └── ApiService.java │ │ │ ├── base │ │ │ ├── AppManager.java │ │ │ ├── BaseActivity.java │ │ │ ├── BaseApplication.java │ │ │ ├── BaseFragment.java │ │ │ ├── BaseFragmentAdapter.java │ │ │ ├── BaseFragmentStateAdapter.java │ │ │ ├── BaseModel.java │ │ │ ├── BasePresenter.java │ │ │ ├── BaseView.java │ │ │ └── baseadapter │ │ │ │ ├── AlphaInAnimation.java │ │ │ │ ├── BaseAnimation.java │ │ │ │ ├── BaseQuickAdapter.java │ │ │ │ ├── BaseViewHolder.java │ │ │ │ ├── OnItemClickListener.java │ │ │ │ ├── ScaleInAnimation.java │ │ │ │ ├── SimpleClickListener.java │ │ │ │ ├── SlideInBottomAnimation.java │ │ │ │ ├── SlideInLeftAnimation.java │ │ │ │ └── SlideInRightAnimation.java │ │ │ ├── baserx │ │ │ ├── RxBus.java │ │ │ ├── RxCache.java │ │ │ ├── RxManager.java │ │ │ ├── RxSchedulers.java │ │ │ ├── RxSubscriber.java │ │ │ └── ServerException.java │ │ │ ├── bean │ │ │ ├── FirstBean.java │ │ │ ├── GirlData.java │ │ │ ├── SecondChannelTabBean.java │ │ │ └── TabEntity.java │ │ │ ├── contract │ │ │ └── FirstContract.java │ │ │ ├── db │ │ │ └── SecondChannelManager.java │ │ │ ├── fragment │ │ │ ├── FirstTabFragment.java │ │ │ ├── SecondListFragment.java │ │ │ ├── SecondTabFragment.java │ │ │ ├── TestFragment.java │ │ │ └── ThirdTabFragment.java │ │ │ ├── launcher │ │ │ ├── LauncherView.java │ │ │ ├── Utils.java │ │ │ ├── ViewPath.java │ │ │ ├── ViewPathEvaluator.java │ │ │ └── ViewPoint.java │ │ │ ├── model │ │ │ └── FirstModel.java │ │ │ ├── presenter │ │ │ └── firstPresenter.java │ │ │ ├── utils │ │ │ ├── ACache.java │ │ │ ├── CollectionUtils.java │ │ │ ├── GlideRoundTransformUtil.java │ │ │ ├── ImageLoaderUtils.java │ │ │ ├── NetWorkUtils.java │ │ │ ├── TUtil.java │ │ │ ├── ToastUitl.java │ │ │ └── Utils.java │ │ │ └── view │ │ │ ├── CustomViewPager.java │ │ │ ├── LoadingDialog.java │ │ │ ├── bottombar │ │ │ ├── BottomBar.java │ │ │ └── BottomBarTab.java │ │ │ ├── launcher │ │ │ ├── LauncherView.java │ │ │ ├── ViewPath.java │ │ │ ├── ViewPathEvaluator.java │ │ │ └── ViewPoint.java │ │ │ └── refresh │ │ │ ├── NormalRefreshViewHolder.java │ │ │ ├── RefreshLayout.java │ │ │ ├── RefreshScrollingUtil.java │ │ │ ├── RefreshViewHolder.java │ │ │ └── StickyNavLayout.java │ └── res │ │ ├── drawable │ │ ├── bg_msg_bubble.xml │ │ ├── loading.xml │ │ ├── loading_dialog_progressbar.xml │ │ ├── shape_circle_blue.xml │ │ ├── shape_circle_purple.xml │ │ ├── shape_circle_red.xml │ │ ├── shape_circle_yellow.xml │ │ └── shape_loading_dialog.xml │ │ ├── layout │ │ ├── activity_luncher.xml │ │ ├── activity_main.xml │ │ ├── appbar.xml │ │ ├── def_load_more_failed.xml │ │ ├── dialog_loading.xml │ │ ├── fragment_firtst.xml │ │ ├── fragment_main.xml │ │ ├── fragment_second.xml │ │ ├── fragment_second_list.xml │ │ ├── fragment_test.xml │ │ ├── item_first.xml │ │ ├── not_loading.xml │ │ ├── view_normal_refresh_footer.xml │ │ ├── view_refresh_header_normal.xml │ │ └── widget_load_view.xml │ │ ├── mipmap-hdpi │ │ ├── bga_refresh_loading01.png │ │ ├── bga_refresh_loading02.png │ │ ├── bga_refresh_loading03.png │ │ ├── bga_refresh_loading04.png │ │ ├── bga_refresh_loading05.png │ │ ├── bga_refresh_loading06.png │ │ ├── bga_refresh_loading07.png │ │ ├── bga_refresh_loading08.png │ │ ├── bga_refresh_loading09.png │ │ ├── bga_refresh_loading10.png │ │ ├── bga_refresh_loading11.png │ │ ├── bga_refresh_loading12.png │ │ ├── ic_launcher.png │ │ ├── refresh_head_arrow.png │ │ └── wx_scan_line.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ ├── actionbar_shadow_up.9.png │ │ ├── ic_empty_picture.png │ │ ├── ic_image_loading.png │ │ ├── ic_launcher.png │ │ ├── loading_progress.png │ │ ├── logo.jpg │ │ ├── n_faxian.png │ │ ├── n_geren.png │ │ ├── n_shouye.png │ │ ├── slogan.png │ │ ├── toux2.png │ │ ├── y_faxian.png │ │ ├── y_geren.png │ │ └── y_shouye.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── array.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── qyh │ └── androidprojecthelper │ └── ExampleUnitTest.java ├── 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 | AndroidProjectHelper -------------------------------------------------------------------------------- /.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 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | 1.8 51 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 安卓项目快速开发框架 2 | 3 | 终结目标:不重复造轮子,基于此框架可以快速开发出一款APP 4 | 5 | 功能在慢慢完善中。。 6 | 7 | ## 特性 8 | * 1、当前主流框架 MVP + Retrofit + RxJava。 9 | * 2、Activity和Fragment结合MVP模式的完整封装,大大减少代码量。 10 | * 3、酷炫的APP启动动画。 11 | * 4、沉浸式状态栏使用与屏幕适配。 12 | * 5、RxBus进行组件之间通讯,降低耦合度。 13 | * 6、``ToolBar``,``Glide``,多层级Viewpager的使用。 14 | * 7、自定义下拉刷新,上拉加载。 15 | 16 | # 闲话少唠,代码先读为快(核心代码) 17 | **1. View 中代码,泛型中传入P 和m,并绑定彼此之间的关系** 18 | ````java 19 | public class FirstTabFragment extends BaseFragment 20 | 21 | @Override 22 | public void initPresenter() { 23 | mPresenter.setVM(this,mModel); 24 | } 25 | ```` 26 | **2. Presenter中代码,观察者模式,model中请求数据后,会回调到presenterz中** 27 | ````java 28 | @Override 29 | public void getFirstListDataRequest(int size, int page) { 30 | 31 | mRxManage.add(mModel.getListData(size,page).subscribe(new RxSubscriber>(mContext,false) { 32 | @Override 33 | public void onStart() { 34 | super.onStart(); 35 | mView.showLoading(mContext.getString(R.string.loading)); 36 | } 37 | @Override 38 | protected void _onNext(List firstBeen) { 39 | mView.showListData(firstBeen); 40 | mView.stopLoading(); 41 | } 42 | @Override 43 | protected void _onError(String message) { 44 | mView.showErrorTip(message); 45 | } 46 | })); 47 | } 48 | ```` 49 | **3. Model中代码,主要是就是请求网络,将结果发送到presenterz中** 50 | ````java 51 | @Override 52 | public Observable> getListData(int size, int page) { 53 | 54 | return Api.getInstance().service.getListData(size,page) 55 | .map(new Func1>() { 56 | @Override 57 | public List call(GirlData girlData) { 58 | return girlData.getResults(); 59 | } 60 | }).compose(RxSchedulers.>io_main()); 61 | } 62 | 63 | 64 | # 主要核心代码就是以上这些,完美的实现请求网络这个过程,通过rxJava观察者机制减少接口的使用,大大减少代码中无用的类! -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | //butterknife 3 | apply plugin: 'android-apt' 4 | 5 | android { 6 | compileSdkVersion 25 7 | buildToolsVersion "25.0.0" 8 | 9 | defaultConfig { 10 | applicationId "qyh.androidprojecthelper" 11 | minSdkVersion 15 12 | targetSdkVersion 25 13 | versionCode 1 14 | versionName "1.0" 15 | //开启分包模式 16 | multiDexEnabled=true 17 | } 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | } 25 | 26 | dependencies { 27 | compile fileTree(include: ['*.jar'], dir: 'libs') 28 | testCompile 'junit:junit:4.12' 29 | compile 'com.android.support:appcompat-v7:25.0.0' 30 | compile 'com.android.support:multidex:1.0.0' 31 | compile 'com.jakewharton:butterknife:5.1.1' 32 | //屏幕适配 33 | compile 'com.zhy:autolayout:1.4.5' 34 | //retrofit和rxjava 35 | compile 'com.squareup.retrofit2:retrofit:2.0.0-beta3' 36 | compile 'com.squareup.okhttp3:logging-interceptor:3.1.2' 37 | compile 'io.reactivex:rxjava:1.0.1' 38 | compile 'io.reactivex:rxandroid:1.0.1' 39 | compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4' 40 | compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4' 41 | compile 'com.android.support:recyclerview-v7:25.0.0' 42 | compile 'cn.yipianfengye.android:zxing-library:2.1' 43 | //view注解 44 | compile 'com.jakewharton:butterknife:8.4.0' 45 | apt 'com.jakewharton:butterknife-compiler:8.4.0' 46 | compile 'com.github.bumptech.glide:glide:3.7.0' 47 | //菜单栏 48 | compile 'com.flyco.tablayout:FlycoTabLayout_Lib:2.1.0@aar' 49 | compile 'com.android.support:design:25.0.0' 50 | } 51 | -------------------------------------------------------------------------------- /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 D:\StudioSDK/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/androidTest/java/qyh/androidprojecthelper/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 14 | android:supportsRtl="true" 15 | android:theme="@style/AppTheme"> 16 | 17 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/LuncherActivity.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.os.Handler; 6 | import android.support.annotation.Nullable; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.view.View; 9 | import android.widget.Button; 10 | 11 | 12 | /** 13 | * 描述:APP启动页 14 | * Created by qyh on 2016/12/10. 15 | */ 16 | public class LuncherActivity extends AppCompatActivity { 17 | @Override 18 | protected void onCreate(@Nullable Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.activity_luncher); 21 | 22 | Button bu_intoapp = (Button) findViewById(R.id.bu_intoapp); 23 | bu_intoapp.setOnClickListener(new View.OnClickListener() { 24 | @Override 25 | public void onClick(View view) { 26 | toMainActivity(); 27 | } 28 | }); 29 | 30 | new Handler().postDelayed(new Runnable() { 31 | @Override 32 | public void run() { 33 | toMainActivity(); 34 | } 35 | }, 4000); 36 | } 37 | private void toMainActivity(){ 38 | Intent intent=new Intent(LuncherActivity.this,MainActivity.class); 39 | startActivity(intent); 40 | finish(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/MainActivity.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.FragmentTransaction; 5 | 6 | import com.flyco.tablayout.CommonTabLayout; 7 | import com.flyco.tablayout.listener.CustomTabEntity; 8 | import com.flyco.tablayout.listener.OnTabSelectListener; 9 | 10 | import java.util.ArrayList; 11 | 12 | import butterknife.BindView; 13 | 14 | import qyh.androidprojecthelper.base.BaseActivity; 15 | import qyh.androidprojecthelper.bean.TabEntity; 16 | import qyh.androidprojecthelper.fragment.FirstTabFragment; 17 | 18 | import qyh.androidprojecthelper.fragment.SecondTabFragment; 19 | import qyh.androidprojecthelper.fragment.ThirdTabFragment; 20 | 21 | /** 22 | * ************************************************************************ 23 | * ** _oo0oo_ ** 24 | * ** o8888888o ** 25 | * ** 88" . "88 ** 26 | * ** (| -_- |) ** 27 | * ** 0\ = /0 ** 28 | * ** ___/'---'\___ ** 29 | * ** .' \\\| |// '. ** 30 | * ** / \\\||| : |||// \\ ** 31 | * ** / _ ||||| -:- |||||- \\ ** 32 | * ** | | \\\\ - /// | | ** 33 | * ** | \_| ''\---/'' |_/ | ** 34 | * ** \ .-\__ '-' __/-. / ** 35 | * ** ___'. .' /--.--\ '. .'___ ** 36 | * ** ."" '< '.___\_<|>_/___.' >' "". ** 37 | * ** | | : '- \'.;'\ _ /';.'/ - ' : | | ** 38 | * ** \ \ '_. \_ __\ /__ _/ .-' / / ** 39 | * ** ====='-.____'.___ \_____/___.-'____.-'===== ** 40 | * ** '=---=' ** 41 | * ************************************************************************ 42 | * ** 佛祖保佑 镇类之宝 ** 43 | * ************************************************************************ 44 | * 45 | */ 46 | public class MainActivity extends BaseActivity { 47 | @BindView(R.id.tab_layout) 48 | CommonTabLayout tabLayout; 49 | private String[] mTitles={"页面1","页面2","页面3"}; 50 | private int[] mIconUnselectIds={R.mipmap.n_shouye, R.mipmap.n_faxian,R.mipmap.n_geren}; 51 | private int[] mIconSelectIds={R.mipmap.y_shouye, R.mipmap.y_faxian, R.mipmap.y_geren}; 52 | 53 | private ArrayList mTabEntities = new ArrayList<>(); 54 | private FirstTabFragment firstTabFragment; 55 | private SecondTabFragment secondTabFragment; 56 | private ThirdTabFragment thirdTabFragment; 57 | 58 | @Override 59 | public int getLayoutId() { 60 | return R.layout.activity_main; 61 | } 62 | 63 | @Override 64 | public void initPresenter() { 65 | } 66 | 67 | @Override 68 | public void initView() { 69 | initTab(); 70 | } 71 | @Override 72 | public void onCreate(Bundle savedInstanceState) { 73 | super.onCreate(savedInstanceState); 74 | initFragment(savedInstanceState); 75 | } 76 | private void initTab() { 77 | for (int i = 0; i < mTitles.length; i++) { 78 | mTabEntities.add(new TabEntity(mTitles[i], mIconSelectIds[i], mIconUnselectIds[i])); 79 | } 80 | 81 | tabLayout.setTabData(mTabEntities); 82 | //点击监听 83 | tabLayout.setOnTabSelectListener(new OnTabSelectListener() { 84 | @Override 85 | public void onTabSelect(int position) { 86 | SwitchTo(position); 87 | } 88 | @Override 89 | public void onTabReselect(int position) { 90 | } 91 | }); 92 | } 93 | //初始化碎片 94 | private void initFragment(Bundle savedInstanceState) { 95 | FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); 96 | int currentTabPosition=0; 97 | if(null==savedInstanceState){ 98 | firstTabFragment = new FirstTabFragment(); 99 | secondTabFragment = new SecondTabFragment(); 100 | thirdTabFragment = new ThirdTabFragment(); 101 | 102 | fragmentTransaction.add(R.id.fl_body,firstTabFragment,"firstTabFragment"); 103 | fragmentTransaction.add(R.id.fl_body,secondTabFragment,"secondTabFragment"); 104 | fragmentTransaction.add(R.id.fl_body,thirdTabFragment,"thirdTabFragment"); 105 | }else{ 106 | firstTabFragment= (FirstTabFragment) getSupportFragmentManager().findFragmentByTag("firstTabFragment"); 107 | secondTabFragment= (SecondTabFragment) getSupportFragmentManager().findFragmentByTag("secondTabFragment"); 108 | thirdTabFragment= (ThirdTabFragment) getSupportFragmentManager().findFragmentByTag("thirdTabFragment"); 109 | } 110 | fragmentTransaction.commit(); 111 | SwitchTo(currentTabPosition); 112 | tabLayout.setCurrentTab(currentTabPosition); 113 | } 114 | private void SwitchTo(int position) { 115 | FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); 116 | 117 | switch (position){ 118 | case 0: 119 | transaction.show(firstTabFragment); 120 | transaction.hide(secondTabFragment); 121 | transaction.hide(thirdTabFragment); 122 | transaction.commitAllowingStateLoss(); 123 | break; 124 | case 1: 125 | transaction.show(secondTabFragment); 126 | transaction.hide(firstTabFragment); 127 | transaction.hide(thirdTabFragment); 128 | transaction.commitAllowingStateLoss(); 129 | break; 130 | case 2: 131 | transaction.show(thirdTabFragment); 132 | transaction.hide(secondTabFragment); 133 | transaction.hide(firstTabFragment); 134 | transaction.commitAllowingStateLoss(); 135 | break; 136 | } 137 | } 138 | 139 | @Override 140 | protected void onResume() { 141 | super.onResume(); 142 | //1 显示tabLayout的角标 显示未读数 143 | tabLayout.showMsg(1,88); 144 | tabLayout.setMsgMargin(3,0,10); 145 | //隐藏消息 146 | //tabLayout.hideMsg(1); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/adapter/FirstTabAdapter.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.adapter; 2 | 3 | 4 | 5 | import android.widget.ImageView; 6 | 7 | import java.util.List; 8 | 9 | import qyh.androidprojecthelper.R; 10 | import qyh.androidprojecthelper.base.baseadapter.BaseQuickAdapter; 11 | import qyh.androidprojecthelper.base.baseadapter.BaseViewHolder; 12 | import qyh.androidprojecthelper.bean.FirstBean; 13 | import qyh.androidprojecthelper.utils.ImageLoaderUtils; 14 | 15 | /** 16 | * 描述: 17 | * Created by qyh on 2016/12/30. 18 | */ 19 | public class FirstTabAdapter extends BaseQuickAdapter { 20 | 21 | public FirstTabAdapter(int layoutResId, List listData) { 22 | super(layoutResId, listData); 23 | } 24 | 25 | @Override 26 | protected void convert(BaseViewHolder helper, Object item, int position) { 27 | FirstBean data=(FirstBean)item; 28 | ImageLoaderUtils.display(mContext,(ImageView) helper.getView(R.id.iv_item_picture) 29 | ,data.getUrl()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/api/Api.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.api; 2 | 3 | 4 | import android.util.Log; 5 | 6 | import com.google.gson.Gson; 7 | import com.google.gson.GsonBuilder; 8 | 9 | import java.io.File; 10 | import java.io.IOException; 11 | import java.util.concurrent.TimeUnit; 12 | 13 | import okhttp3.Cache; 14 | import okhttp3.CacheControl; 15 | import okhttp3.Interceptor; 16 | import okhttp3.OkHttpClient; 17 | import okhttp3.Request; 18 | import okhttp3.Response; 19 | import okhttp3.logging.HttpLoggingInterceptor; 20 | import qyh.androidprojecthelper.base.BaseApplication; 21 | import qyh.androidprojecthelper.utils.NetWorkUtils; 22 | import retrofit2.Retrofit; 23 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; 24 | import retrofit2.converter.gson.GsonConverterFactory; 25 | 26 | /** 27 | * 描述: 28 | * Created by qyh on 2016/12/28. 29 | */ 30 | public class Api { 31 | public Retrofit retrofit; 32 | public ApiService service; 33 | 34 | private static class SingletonHolder { 35 | private static final Api INSTANCE = new Api(); 36 | } 37 | 38 | public static Api getInstance() { 39 | return SingletonHolder.INSTANCE; 40 | } 41 | 42 | //增加头部信息 43 | Interceptor headerInterceptor =new Interceptor() { 44 | @Override 45 | public Response intercept(Chain chain) throws IOException { 46 | Request build = chain.request().newBuilder() 47 | .addHeader("Content-Type", "application/json") 48 | .build(); 49 | return chain.proceed(build); 50 | } 51 | }; 52 | 53 | //构造方法私有 54 | private Api() { 55 | HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); 56 | interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); 57 | 58 | File cacheFile = new File(BaseApplication.getAppContext().getCacheDir(), "cache"); 59 | Cache cache = new Cache(cacheFile, 1024 * 1024 * 100); //100Mb 60 | 61 | OkHttpClient okHttpClient = new OkHttpClient.Builder() 62 | .readTimeout(7676, TimeUnit.MILLISECONDS) 63 | .connectTimeout(7676, TimeUnit.MILLISECONDS) 64 | .addInterceptor(headerInterceptor) 65 | .addInterceptor(interceptor) 66 | .addNetworkInterceptor(new HttpCacheInterceptor()) 67 | .cache(cache) 68 | .build(); 69 | 70 | Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").serializeNulls().create(); 71 | 72 | retrofit = new Retrofit.Builder() 73 | .client(okHttpClient) 74 | .addConverterFactory(GsonConverterFactory.create(gson)) 75 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 76 | .baseUrl("http://gank.io/api/") 77 | .build(); 78 | service = retrofit.create(ApiService.class); 79 | } 80 | 81 | class HttpCacheInterceptor implements Interceptor { 82 | 83 | @Override 84 | public Response intercept(Chain chain) throws IOException { 85 | Request request = chain.request(); 86 | if (!NetWorkUtils.isNetConnected(BaseApplication.getAppContext())) { 87 | request = request.newBuilder() 88 | .cacheControl(CacheControl.FORCE_CACHE) 89 | .build(); 90 | Log.d("Okhttp", "no network"); 91 | } 92 | 93 | Response originalResponse = chain.proceed(request); 94 | if (NetWorkUtils.isNetConnected(BaseApplication.getAppContext())) { 95 | //有网的时候读接口上的@Headers里的配置,你可以在这里进行统一的设置 96 | String cacheControl = request.cacheControl().toString(); 97 | return originalResponse.newBuilder() 98 | .header("Cache-Control", cacheControl) 99 | .removeHeader("Pragma") 100 | .build(); 101 | } else { 102 | return originalResponse.newBuilder() 103 | .header("Cache-Control", "public, only-if-cached, max-stale=2419200") 104 | .removeHeader("Pragma") 105 | .build(); 106 | } 107 | } 108 | } 109 | } -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/api/ApiService.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.api; 2 | 3 | import qyh.androidprojecthelper.bean.GirlData; 4 | 5 | import retrofit2.http.GET; 6 | 7 | import retrofit2.http.Path; 8 | import rx.Observable; 9 | 10 | /** 11 | * 描述: 12 | * Created by qyh on 2016/12/28. 13 | */ 14 | public interface ApiService { 15 | /** 16 | * 图片URL http://gank.io/api/data/福利/20/1 17 | * @param size 18 | * @param page 19 | * @return 20 | */ 21 | @GET("data/福利/{size}/{page}") 22 | Observable getListData( 23 | // @Header("Cache-Control") String cacheControl, 24 | @Path("size") int size, 25 | @Path("page") int page); 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/base/AppManager.java: -------------------------------------------------------------------------------- 1 | 2 | package qyh.androidprojecthelper.base; 3 | 4 | import android.app.Activity; 5 | import android.app.ActivityManager; 6 | import android.content.Context; 7 | 8 | import java.util.Stack; 9 | 10 | /** 11 | * activity管理 12 | * Created by qyh on 2016/12/7. 13 | */ 14 | public class AppManager { 15 | private static Stack activityStack; 16 | private volatile static AppManager instance; 17 | 18 | private AppManager() { 19 | 20 | } 21 | /** 22 | * 单一实例 23 | */ 24 | public static AppManager getAppManager() { 25 | if (instance == null) { 26 | synchronized (AppManager.class){ 27 | if(instance==null){ 28 | instance = new AppManager(); 29 | instance.activityStack = new Stack(); 30 | } 31 | } 32 | 33 | } 34 | return instance; 35 | } 36 | 37 | /** 38 | * 添加Activity到堆栈 39 | */ 40 | public void addActivity(Activity activity) { 41 | if (activityStack == null) { 42 | activityStack = new Stack(); 43 | } 44 | activityStack.add(activity); 45 | } 46 | 47 | /** 48 | * 获取当前Activity(堆栈中最后一个压入的) 49 | */ 50 | public Activity currentActivity() { 51 | try { 52 | Activity activity = activityStack.lastElement(); 53 | return activity; 54 | } catch (Exception e) { 55 | // e.printStackTrace(); 56 | return null; 57 | } 58 | } 59 | 60 | /** 61 | * 获取当前Activity的前一个Activity 62 | */ 63 | public Activity preActivity() { 64 | int index = activityStack.size() - 2; 65 | if (index < 0) { 66 | return null; 67 | } 68 | Activity activity = activityStack.get(index); 69 | return activity; 70 | } 71 | 72 | /** 73 | * 结束当前Activity(堆栈中最后一个压入的) 74 | */ 75 | public void finishActivity() { 76 | Activity activity = activityStack.lastElement(); 77 | finishActivity(activity); 78 | } 79 | 80 | /** 81 | * 结束指定的Activity 82 | */ 83 | public void finishActivity(Activity activity) { 84 | if (activity != null) { 85 | activityStack.remove(activity); 86 | activity.finish(); 87 | activity = null; 88 | } 89 | } 90 | 91 | /** 92 | * 移除指定的Activity 93 | */ 94 | public void removeActivity(Activity activity) { 95 | if (activity != null) { 96 | activityStack.remove(activity); 97 | activity = null; 98 | } 99 | } 100 | 101 | /** 102 | * 结束指定类名的Activity 103 | */ 104 | public void finishActivity(Class cls) { 105 | try { 106 | for (Activity activity : activityStack) { 107 | if (activity.getClass().equals(cls)) { 108 | finishActivity(activity); 109 | } 110 | } 111 | } catch (Exception e) { 112 | e.printStackTrace(); 113 | } 114 | 115 | } 116 | 117 | /** 118 | * 结束所有Activity 119 | */ 120 | public void finishAllActivity() { 121 | for (int i = 0, size = activityStack.size(); i < size; i++) { 122 | if (null != activityStack.get(i)) { 123 | activityStack.get(i).finish(); 124 | } 125 | } 126 | activityStack.clear(); 127 | } 128 | 129 | /** 130 | * 返回到指定的activity 131 | * 132 | * @param cls 133 | */ 134 | public void returnToActivity(Class cls) { 135 | while (activityStack.size() != 0) 136 | if (activityStack.peek().getClass() == cls) { 137 | break; 138 | } else { 139 | finishActivity(activityStack.peek()); 140 | } 141 | } 142 | 143 | 144 | /** 145 | * 是否已经打开指定的activity 146 | * @param cls 147 | * @return 148 | */ 149 | public boolean isOpenActivity(Class cls) { 150 | if (activityStack!=null){ 151 | for (int i = 0, size = activityStack.size(); i < size; i++) { 152 | if (cls == activityStack.peek().getClass()) { 153 | return true; 154 | } 155 | } 156 | } 157 | return false; 158 | } 159 | 160 | /** 161 | * 退出应用程序 162 | * 163 | * @param context 上下文 164 | * @param isBackground 是否开开启后台运行 165 | */ 166 | public void AppExit(Context context, Boolean isBackground) { 167 | try { 168 | finishAllActivity(); 169 | ActivityManager activityMgr = (ActivityManager) context 170 | .getSystemService(Context.ACTIVITY_SERVICE); 171 | activityMgr.restartPackage(context.getPackageName()); 172 | } catch (Exception e) { 173 | 174 | } finally { 175 | // 注意,如果您有后台程序运行,请不要支持此句子 176 | if (!isBackground) { 177 | System.exit(0); 178 | } 179 | } 180 | } 181 | } -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/base/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.base; 2 | 3 | 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.content.pm.ActivityInfo; 7 | import android.os.Bundle; 8 | import android.view.Window; 9 | 10 | 11 | import com.zhy.autolayout.AutoLayoutActivity; 12 | 13 | import butterknife.ButterKnife; 14 | 15 | import qyh.androidprojecthelper.baserx.RxManager; 16 | import qyh.androidprojecthelper.utils.TUtil; 17 | import qyh.androidprojecthelper.utils.ToastUitl; 18 | import qyh.androidprojecthelper.view.LoadingDialog; 19 | 20 | /** 21 | * 基类 22 | * AutoLayoutActivity 屏幕适配 详细用法请看https://github.com/hongyangAndroid/AndroidAutoLayout 23 | * Created by qyh on 2016/12/7. 24 | */ 25 | 26 | /***************使用例子*********************/ 27 | //1.mvp模式 28 | //public class SampleActivity extends BaseActivityimplements NewsChannelContract.View { 29 | // @Override 30 | // public int getLayoutId() { 31 | // return R.layout.activity_news_channel; 32 | // } 33 | // 34 | // @Override 35 | // public void initPresenter() { 36 | // mPresenter.setVM(this, mModel); 37 | // } 38 | // 39 | // @Override 40 | // public void initView() { 41 | // } 42 | //} 43 | //2.普通模式 44 | //public class SampleActivity extends BaseActivity { 45 | // @Override 46 | // public int getLayoutId() { 47 | // return R.layout.activity_news_channel; 48 | // } 49 | // 50 | // @Override 51 | // public void initPresenter() { 52 | // } 53 | // 54 | // @Override 55 | // public void initView() { 56 | // } 57 | //} 58 | public abstract class BaseActivity extends AutoLayoutActivity { 59 | public T mPresenter; 60 | public E mModel; 61 | public Context mContext; 62 | public RxManager mRxManager; 63 | 64 | @Override 65 | public void onCreate(Bundle savedInstanceState) { 66 | super.onCreate(savedInstanceState); 67 | mRxManager=new RxManager(); 68 | doBeforeSetcontentView(); 69 | setContentView(getLayoutId()); 70 | ButterKnife.bind(this); 71 | mContext = this; 72 | mPresenter = TUtil.getT(this, 0); 73 | mModel= TUtil.getT(this,1); 74 | if(mPresenter!=null){ 75 | mPresenter.mContext=this; 76 | } 77 | this.initPresenter(); 78 | this.initView(); 79 | } 80 | 81 | /** 82 | * 设置layout前配置 83 | */ 84 | private void doBeforeSetcontentView() { 85 | 86 | // 把actvity放到application栈中管理 87 | AppManager.getAppManager().addActivity(this); 88 | // 无标题 89 | requestWindowFeature(Window.FEATURE_NO_TITLE); 90 | // 设置竖屏 91 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 92 | } 93 | /*********************子类实现*****************************/ 94 | //获取布局文件 95 | public abstract int getLayoutId(); 96 | //简单页面无需mvp就不用管此方法即可,完美兼容各种实际场景的变通 97 | public abstract void initPresenter(); 98 | //初始化view 99 | public abstract void initView(); 100 | 101 | /** 102 | * 通过Class跳转界面 103 | **/ 104 | public void startActivity(Class cls) { 105 | startActivity(cls, null); 106 | } 107 | 108 | /** 109 | * 通过Class跳转界面 110 | **/ 111 | public void startActivityForResult(Class cls, int requestCode) { 112 | startActivityForResult(cls, null, requestCode); 113 | } 114 | 115 | /** 116 | * 含有Bundle通过Class跳转界面 117 | **/ 118 | public void startActivityForResult(Class cls, Bundle bundle, 119 | int requestCode) { 120 | Intent intent = new Intent(); 121 | intent.setClass(this, cls); 122 | if (bundle != null) { 123 | intent.putExtras(bundle); 124 | } 125 | startActivityForResult(intent, requestCode); 126 | } 127 | 128 | /** 129 | * 含有Bundle通过Class跳转界面 130 | **/ 131 | public void startActivity(Class cls, Bundle bundle) { 132 | Intent intent = new Intent(); 133 | intent.setClass(this, cls); 134 | if (bundle != null) { 135 | intent.putExtras(bundle); 136 | } 137 | startActivity(intent); 138 | } 139 | 140 | /** 141 | * 开启浮动加载进度条 142 | */ 143 | public void startProgressDialog() { 144 | LoadingDialog.showDialogForLoading(this); 145 | } 146 | 147 | /** 148 | * 开启浮动加载进度条 149 | * 150 | * @param msg 151 | */ 152 | public void startProgressDialog(String msg) { 153 | LoadingDialog.showDialogForLoading(this, msg, true); 154 | } 155 | 156 | /** 157 | * 停止浮动加载进度条 158 | */ 159 | public void stopProgressDialog() { 160 | LoadingDialog.cancelDialogForLoading(); 161 | } 162 | 163 | /** 164 | * 短暂显示Toast提示(来自String) 165 | **/ 166 | public void showShortToast(String text) { 167 | ToastUitl.showShort(text); 168 | } 169 | 170 | /** 171 | * 短暂显示Toast提示(id) 172 | **/ 173 | public void showShortToast(int resId) { 174 | ToastUitl.showShort(resId); 175 | } 176 | 177 | /** 178 | * 长时间显示Toast提示(来自res) 179 | **/ 180 | public void showLongToast(int resId) { 181 | ToastUitl.showLong(resId); 182 | } 183 | 184 | /** 185 | * 长时间显示Toast提示(来自String) 186 | **/ 187 | public void showLongToast(String text) { 188 | ToastUitl.showLong(text); 189 | } 190 | /** 191 | // * 网络访问错误提醒 192 | // */ 193 | // public void showNetErrorTip() { 194 | // ToastUitl.showToastWithImg(getText(R.string.net_error).toString(),R.drawable.ic_wifi_off); 195 | // } 196 | // public void showNetErrorTip(String error) { 197 | // ToastUitl.showToastWithImg(error,R.drawable.ic_wifi_off); 198 | // } 199 | @Override 200 | protected void onResume() { 201 | super.onResume(); 202 | //防统计之类的 203 | } 204 | 205 | @Override 206 | protected void onPause() { 207 | super.onPause(); 208 | 209 | } 210 | 211 | 212 | @Override 213 | protected void onDestroy() { 214 | super.onDestroy(); 215 | if (mPresenter != null) 216 | mPresenter.onDestroy(); 217 | mRxManager.clear(); 218 | // ButterKnife.unbind(this); 219 | AppManager.getAppManager().finishActivity(this); 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/base/BaseApplication.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.base; 2 | 3 | 4 | import android.content.Context; 5 | import android.support.multidex.MultiDexApplication; 6 | 7 | import com.uuzuche.lib_zxing.activity.ZXingLibrary; 8 | import com.zhy.autolayout.config.AutoLayoutConifg; 9 | 10 | /** 11 | * 描述:MultiDexApplication防止方法数过多 12 | * Created by qyh on 2016/12/6. 13 | */ 14 | public class BaseApplication extends MultiDexApplication { 15 | private static BaseApplication baseApplication; 16 | @Override 17 | public void onCreate() { 18 | super.onCreate(); 19 | baseApplication = this; 20 | //屏幕适配 21 | AutoLayoutConifg.getInstance().useDeviceSize(); 22 | ZXingLibrary.initDisplayOpinion(this); 23 | } 24 | public static Context getAppContext() { 25 | return baseApplication; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/base/BaseFragment.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.base; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | 11 | 12 | 13 | import butterknife.ButterKnife; 14 | import qyh.androidprojecthelper.baserx.RxManager; 15 | import qyh.androidprojecthelper.utils.TUtil; 16 | import qyh.androidprojecthelper.utils.ToastUitl; 17 | import qyh.androidprojecthelper.view.LoadingDialog; 18 | 19 | /** 20 | * des:基类fragment 21 | * Created by qyh on 2016/12/7. 22 | */ 23 | 24 | /***************使用例子*********************/ 25 | //1.mvp模式 26 | //public class SampleFragment extends BaseFragmentimplements NewsChannelContract.View { 27 | // @Override 28 | // public int getLayoutId() { 29 | // return R.layout.activity_news_channel; 30 | // } 31 | // 32 | // @Override 33 | // public void initPresenter() { 34 | // mPresenter.setVM(this, mModel); 35 | // } 36 | // 37 | // @Override 38 | // public void initView() { 39 | // } 40 | //} 41 | //2.普通模式 42 | //public class SampleFragment extends BaseFragment { 43 | // @Override 44 | // public int getLayoutResource() { 45 | // return R.layout.activity_news_channel; 46 | // } 47 | // 48 | // @Override 49 | // public void initPresenter() { 50 | // } 51 | // 52 | // @Override 53 | // public void initView() { 54 | // } 55 | //} 56 | public abstract class BaseFragment extends Fragment { 57 | protected View rootView; 58 | public T mPresenter; 59 | public E mModel; 60 | public RxManager mRxManager; 61 | 62 | @Nullable 63 | @Override 64 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 65 | if (rootView == null) 66 | rootView = inflater.inflate(getLayoutResource(), container, false); 67 | mRxManager=new RxManager(); 68 | ButterKnife.bind(this, rootView); 69 | mPresenter = TUtil.getT(this, 0); 70 | mModel= TUtil.getT(this,1); 71 | if(mPresenter!=null){ 72 | mPresenter.mContext=this.getActivity(); 73 | } 74 | initPresenter(); 75 | initView(); 76 | return rootView; 77 | } 78 | //获取布局文件 79 | protected abstract int getLayoutResource(); 80 | //简单页面无需mvp就不用管此方法即可,完美兼容各种实际场景的变通 81 | public abstract void initPresenter(); 82 | //初始化view 83 | protected abstract void initView(); 84 | 85 | 86 | /** 87 | * 通过Class跳转界面 88 | **/ 89 | public void startActivity(Class cls) { 90 | startActivity(cls, null); 91 | } 92 | 93 | /** 94 | * 通过Class跳转界面 95 | **/ 96 | public void startActivityForResult(Class cls, int requestCode) { 97 | startActivityForResult(cls, null, requestCode); 98 | } 99 | 100 | /** 101 | * 含有Bundle通过Class跳转界面 102 | **/ 103 | public void startActivityForResult(Class cls, Bundle bundle, 104 | int requestCode) { 105 | Intent intent = new Intent(); 106 | intent.setClass(getActivity(), cls); 107 | if (bundle != null) { 108 | intent.putExtras(bundle); 109 | } 110 | startActivityForResult(intent, requestCode); 111 | } 112 | 113 | /** 114 | * 含有Bundle通过Class跳转界面 115 | **/ 116 | public void startActivity(Class cls, Bundle bundle) { 117 | Intent intent = new Intent(); 118 | intent.setClass(getActivity(), cls); 119 | if (bundle != null) { 120 | intent.putExtras(bundle); 121 | } 122 | startActivity(intent); 123 | } 124 | 125 | 126 | 127 | /** 128 | * 开启加载进度条 129 | */ 130 | public void startProgressDialog() { 131 | LoadingDialog.showDialogForLoading(getActivity()); 132 | } 133 | 134 | /** 135 | * 开启加载进度条 136 | * 137 | * @param msg 138 | */ 139 | public void startProgressDialog(String msg) { 140 | LoadingDialog.showDialogForLoading(getActivity(), msg, true); 141 | } 142 | 143 | /** 144 | * 停止加载进度条 145 | */ 146 | public void stopProgressDialog() { 147 | LoadingDialog.cancelDialogForLoading(); 148 | } 149 | 150 | 151 | /** 152 | * 短暂显示Toast提示(来自String) 153 | **/ 154 | public void showShortToast(String text) { 155 | ToastUitl.showShort(text); 156 | } 157 | 158 | /** 159 | * 短暂显示Toast提示(id) 160 | **/ 161 | public void showShortToast(int resId) { 162 | ToastUitl.showShort(resId); 163 | } 164 | 165 | /** 166 | * 长时间显示Toast提示(来自res) 167 | **/ 168 | public void showLongToast(int resId) { 169 | ToastUitl.showLong(resId); 170 | } 171 | 172 | /** 173 | * 长时间显示Toast提示(来自String) 174 | **/ 175 | public void showLongToast(String text) { 176 | ToastUitl.showLong(text); 177 | } 178 | 179 | 180 | 181 | // /** 182 | // * 网络访问错误提醒 183 | // */ 184 | // public void showNetErrorTip() { 185 | // ToastUitl.showToastWithImg(getText(R.string.net_error).toString(),R.drawable.ic_wifi_off); 186 | // } 187 | // 188 | // public void showNetErrorTip(String error) { 189 | // ToastUitl.showToastWithImg(error,R.drawable.ic_wifi_off); 190 | // } 191 | 192 | @Override 193 | public void onDestroyView() { 194 | super.onDestroyView(); 195 | // ButterKnife.unbind(this); 196 | if (mPresenter != null) 197 | mPresenter.onDestroy(); 198 | mRxManager.clear(); 199 | } 200 | 201 | } 202 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/base/BaseFragmentAdapter.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.base; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.app.FragmentManager; 5 | import android.support.v4.app.FragmentPagerAdapter; 6 | import android.support.v4.app.FragmentTransaction; 7 | 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | import qyh.androidprojecthelper.utils.CollectionUtils; 13 | 14 | /** 15 | * 该类内的每一个生成的 Fragment 都将保存在内存之中, 16 | * 因此适用于那些相对静态的页,数量也比较少的那种; 17 | * 如果需要处理有很多页,并且数据动态性较大、占用内存较多的情况, 18 | * 应该使用FragmentStatePagerAdapter。 19 | */ 20 | public class BaseFragmentAdapter extends FragmentPagerAdapter { 21 | 22 | List fragmentList = new ArrayList(); 23 | private List mTitles; 24 | 25 | public BaseFragmentAdapter(FragmentManager fm, List fragmentList) { 26 | super(fm); 27 | this.fragmentList = fragmentList; 28 | } 29 | 30 | public BaseFragmentAdapter(FragmentManager fm, List fragmentList, List mTitles) { 31 | super(fm); 32 | this.mTitles = mTitles; 33 | setFragments(fm,fragmentList,mTitles); 34 | } 35 | //刷新fragment 36 | public void setFragments(FragmentManager fm, List fragments, List mTitles) { 37 | this.mTitles = mTitles; 38 | if (this.fragmentList != null) { 39 | FragmentTransaction ft = fm.beginTransaction(); 40 | for (Fragment f : this.fragmentList) { 41 | ft.remove(f); 42 | } 43 | ft.commitAllowingStateLoss(); 44 | ft = null; 45 | fm.executePendingTransactions(); 46 | } 47 | this.fragmentList = fragments; 48 | notifyDataSetChanged(); 49 | } 50 | 51 | @Override 52 | public CharSequence getPageTitle(int position) { 53 | return !CollectionUtils.isNullOrEmpty(mTitles) ? mTitles.get(position) : ""; 54 | } 55 | 56 | @Override 57 | public Fragment getItem(int position) { 58 | return fragmentList.get(position); 59 | } 60 | 61 | @Override 62 | public int getCount() { 63 | return fragmentList.size(); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/base/BaseFragmentStateAdapter.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.base; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.app.FragmentManager; 5 | import android.support.v4.app.FragmentStatePagerAdapter; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import qyh.androidprojecthelper.utils.CollectionUtils; 11 | 12 | /** 13 | * FragmentStatePagerAdapter 和前面的 FragmentPagerAdapter 一样,是继承子 PagerAdapter。 14 | * 但和 FragmentPagerAdapter 不一样的是, 15 | * 正如其类名中的 'State' 所表明的含义一样, 16 | * 该 PagerAdapter 的实现将只保留当前页面, 17 | * 当页面离开视线后,就会被消除,释放其资源; 18 | * 而在页面需要显示时,生成新的页面(就像 ListView 的实现一样)。 19 | * 这么实现的好处就是当拥有大量的页面时,不必在内存中占用大量的内存。 20 | */ 21 | public class BaseFragmentStateAdapter extends FragmentStatePagerAdapter { 22 | 23 | List fragmentList = new ArrayList(); 24 | private List mTitles; 25 | 26 | public BaseFragmentStateAdapter(FragmentManager fm, List fragmentList) { 27 | super(fm); 28 | this.fragmentList = fragmentList; 29 | } 30 | 31 | public BaseFragmentStateAdapter(FragmentManager fm, List fragmentList, List mTitles) { 32 | super(fm); 33 | this.mTitles = mTitles; 34 | this.fragmentList = fragmentList; 35 | } 36 | @Override 37 | public CharSequence getPageTitle(int position) { 38 | return !CollectionUtils.isNullOrEmpty(mTitles) ? mTitles.get(position) : ""; 39 | } 40 | 41 | @Override 42 | public Fragment getItem(int position) { 43 | return fragmentList.get(position); 44 | } 45 | 46 | @Override 47 | public int getCount() { 48 | return fragmentList.size(); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/base/BaseModel.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.base; 2 | 3 | public interface BaseModel { 4 | } 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/base/BasePresenter.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.base; 2 | 3 | import android.content.Context; 4 | 5 | import qyh.androidprojecthelper.baserx.RxManager; 6 | 7 | 8 | /** 9 | * 描述:基类presenter 10 | * Created by qyh on 2016/12/6. 11 | */ 12 | public abstract class BasePresenter{ 13 | public Context mContext; 14 | public E mModel; 15 | public T mView; 16 | public RxManager mRxManage = new RxManager(); 17 | 18 | public void setVM(T v, E m) { 19 | this.mView = v; 20 | this.mModel = m; 21 | this.onStart(); 22 | } 23 | public void onStart(){ 24 | }; 25 | public void onDestroy() { 26 | mRxManage.clear(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/base/BaseView.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.base; 2 | /** 3 | * 描述: 4 | * Created by qyh on 2016/12/28. 5 | */ 6 | public interface BaseView { 7 | /*******内嵌加载*******/ 8 | void showLoading(String title); 9 | void stopLoading(); 10 | void showErrorTip(String msg); 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/base/baseadapter/AlphaInAnimation.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.base.baseadapter; 2 | 3 | import android.animation.Animator; 4 | import android.animation.ObjectAnimator; 5 | import android.view.View; 6 | 7 | 8 | public class AlphaInAnimation implements BaseAnimation { 9 | 10 | private static final float DEFAULT_ALPHA_FROM = 0f; 11 | private final float mFrom; 12 | 13 | public AlphaInAnimation() { 14 | this(DEFAULT_ALPHA_FROM); 15 | } 16 | 17 | public AlphaInAnimation(float from) { 18 | mFrom = from; 19 | } 20 | 21 | @Override 22 | public Animator[] getAnimators(View view) { 23 | return new Animator[]{ObjectAnimator.ofFloat(view, "alpha", mFrom, 1f)}; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/base/baseadapter/BaseAnimation.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.base.baseadapter; 2 | 3 | import android.animation.Animator; 4 | import android.view.View; 5 | 6 | 7 | public interface BaseAnimation { 8 | 9 | Animator[] getAnimators(View view); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/base/baseadapter/OnItemClickListener.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.base.baseadapter; 2 | 3 | import android.view.View; 4 | 5 | 6 | public abstract class OnItemClickListener extends SimpleClickListener { 7 | 8 | 9 | @Override 10 | public void onItemClick(BaseQuickAdapter adapter, View view, int position) { 11 | SimpleOnItemClick(adapter,view,position); 12 | } 13 | 14 | @Override 15 | public void onItemLongClick(BaseQuickAdapter adapter, View view, int position) { 16 | 17 | } 18 | 19 | @Override 20 | public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) { 21 | 22 | } 23 | 24 | @Override 25 | public void onItemChildLongClick(BaseQuickAdapter adapter, View view, int position) { 26 | 27 | } 28 | public abstract void SimpleOnItemClick(BaseQuickAdapter adapter, View view, int position); 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/base/baseadapter/ScaleInAnimation.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.base.baseadapter; 2 | 3 | import android.animation.Animator; 4 | import android.animation.ObjectAnimator; 5 | import android.view.View; 6 | 7 | import qyh.androidprojecthelper.base.baseadapter.BaseAnimation; 8 | 9 | 10 | public class ScaleInAnimation implements BaseAnimation { 11 | 12 | private static final float DEFAULT_SCALE_FROM = .5f; 13 | private final float mFrom; 14 | 15 | public ScaleInAnimation() { 16 | this(DEFAULT_SCALE_FROM); 17 | } 18 | 19 | public ScaleInAnimation(float from) { 20 | mFrom = from; 21 | } 22 | 23 | @Override 24 | public Animator[] getAnimators(View view) { 25 | ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", mFrom, 1f); 26 | ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", mFrom, 1f); 27 | return new ObjectAnimator[] { scaleX, scaleY }; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/base/baseadapter/SimpleClickListener.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.base.baseadapter; 2 | 3 | import android.support.v4.view.GestureDetectorCompat; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.util.Log; 6 | import android.view.GestureDetector; 7 | import android.view.MotionEvent; 8 | import android.view.View; 9 | 10 | import java.util.Iterator; 11 | import java.util.Set; 12 | 13 | 14 | 15 | public abstract class SimpleClickListener implements RecyclerView.OnItemTouchListener { 16 | private GestureDetectorCompat mGestureDetector; 17 | private RecyclerView recyclerView; 18 | private Set childClickViewIds; 19 | private Set longClickViewIds; 20 | protected BaseQuickAdapter baseQuickAdapter; 21 | public static String TAG = "SimpleClickListener"; 22 | private boolean mIsPrepressed = false; 23 | private boolean mIsShowPress = false; 24 | private View mPressedView = null; 25 | 26 | @Override 27 | public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { 28 | 29 | if (recyclerView == null) { 30 | this.recyclerView = rv; 31 | this.baseQuickAdapter = (BaseQuickAdapter) recyclerView.getAdapter(); 32 | mGestureDetector = new GestureDetectorCompat(recyclerView.getContext(), new ItemTouchHelperGestureListener(recyclerView)); 33 | } 34 | if (!mGestureDetector.onTouchEvent(e) && e.getActionMasked() == MotionEvent.ACTION_UP && mIsShowPress) { 35 | if (mPressedView!=null){ 36 | mPressedView.setPressed(false); 37 | mPressedView = null; 38 | } 39 | mIsShowPress = false; 40 | mIsPrepressed = false; 41 | 42 | 43 | } 44 | return false; 45 | } 46 | 47 | @Override 48 | public void onTouchEvent(RecyclerView rv, MotionEvent e) { 49 | Log.e(TAG, "onTouchEvent: "); 50 | mGestureDetector.onTouchEvent(e); 51 | } 52 | 53 | @Override 54 | public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { 55 | } 56 | 57 | private class ItemTouchHelperGestureListener extends GestureDetector.SimpleOnGestureListener { 58 | 59 | private RecyclerView recyclerView; 60 | 61 | @Override 62 | public boolean onDown(MotionEvent e) { 63 | mIsPrepressed = true; 64 | mPressedView = recyclerView.findChildViewUnder(e.getX(), e.getY()); 65 | super.onDown(e); 66 | return false; 67 | } 68 | 69 | @Override 70 | public void onShowPress(MotionEvent e) { 71 | if (mIsPrepressed && mPressedView != null) { 72 | mPressedView.setPressed(true); 73 | mIsShowPress = true; 74 | } 75 | super.onShowPress(e); 76 | } 77 | 78 | public ItemTouchHelperGestureListener(RecyclerView recyclerView) { 79 | this.recyclerView = recyclerView; 80 | } 81 | 82 | @Override 83 | public boolean onSingleTapUp(MotionEvent e) { 84 | if (mIsPrepressed && mPressedView != null) { 85 | mPressedView.setPressed(true); 86 | final View pressedView = mPressedView; 87 | BaseViewHolder vh = (BaseViewHolder) recyclerView.getChildViewHolder(pressedView); 88 | 89 | if (isHeaderOrFooterPosition(vh.getLayoutPosition())) { 90 | return false; 91 | } 92 | childClickViewIds = vh.getChildClickViewIds(); 93 | 94 | if (childClickViewIds != null && childClickViewIds.size() > 0) { 95 | for (Iterator it = childClickViewIds.iterator(); it.hasNext(); ) { 96 | View childView = pressedView.findViewById((Integer) it.next()); 97 | if (inRangeOfView(childView, e)&&childView.isEnabled()) { 98 | onItemChildClick(baseQuickAdapter, childView, vh.getLayoutPosition() - baseQuickAdapter.getHeaderLayoutCount()); 99 | resetPressedView(pressedView); 100 | return true; 101 | } 102 | } 103 | 104 | 105 | onItemClick(baseQuickAdapter, pressedView, vh.getLayoutPosition() - baseQuickAdapter.getHeaderLayoutCount()); 106 | } else { 107 | onItemClick(baseQuickAdapter, pressedView, vh.getLayoutPosition() - baseQuickAdapter.getHeaderLayoutCount()); 108 | } 109 | resetPressedView(pressedView); 110 | 111 | } 112 | return true; 113 | } 114 | 115 | private void resetPressedView(final View pressedView) { 116 | if (pressedView!=null){ 117 | pressedView.postDelayed(new Runnable() { 118 | @Override 119 | public void run() { 120 | if (pressedView!=null){ 121 | pressedView.setPressed(false); 122 | } 123 | 124 | } 125 | }, 100); 126 | } 127 | 128 | mIsPrepressed = false; 129 | mPressedView = null; 130 | } 131 | 132 | @Override 133 | public void onLongPress(MotionEvent e) { 134 | boolean isChildLongClick =false; 135 | if (mIsPrepressed && mPressedView != null) { 136 | BaseViewHolder vh = (BaseViewHolder) recyclerView.getChildViewHolder(mPressedView); 137 | if (!isHeaderOrFooterPosition(vh.getLayoutPosition())) { 138 | longClickViewIds = vh.getItemChildLongClickViewIds(); 139 | if (longClickViewIds != null && longClickViewIds.size() > 0) { 140 | for (Iterator it = longClickViewIds.iterator(); it.hasNext(); ) { 141 | View childView = mPressedView.findViewById((Integer) it.next()); 142 | if (inRangeOfView(childView, e)&&childView.isEnabled()) { 143 | onItemChildLongClick(baseQuickAdapter, childView, vh.getLayoutPosition() - baseQuickAdapter.getHeaderLayoutCount()); 144 | mPressedView.setPressed(true); 145 | mIsShowPress = true; 146 | isChildLongClick =true; 147 | break; 148 | } 149 | } 150 | } 151 | if (!isChildLongClick){ 152 | onItemLongClick(baseQuickAdapter, mPressedView, vh.getLayoutPosition() - baseQuickAdapter.getHeaderLayoutCount()); 153 | mPressedView.setPressed(true); 154 | mIsShowPress = true; 155 | } 156 | 157 | } 158 | 159 | } 160 | } 161 | 162 | 163 | } 164 | 165 | /** 166 | * Callback method to be invoked when an item in this AdapterView has 167 | * been clicked. 168 | * 169 | * @param view The view within the AdapterView that was clicked (this 170 | * will be a view provided by the adapter) 171 | * @param position The position of the view in the adapter. 172 | */ 173 | public abstract void onItemClick(BaseQuickAdapter adapter, View view, int position); 174 | 175 | /** 176 | * callback method to be invoked when an item in this view has been 177 | * click and held 178 | * 179 | * @param view The view whihin the AbsListView that was clicked 180 | * @param position The position of the view int the adapter 181 | * @return true if the callback consumed the long click ,false otherwise 182 | */ 183 | public abstract void onItemLongClick(BaseQuickAdapter adapter, View view, int position); 184 | 185 | public abstract void onItemChildClick(BaseQuickAdapter adapter, View view, int position); 186 | 187 | public abstract void onItemChildLongClick(BaseQuickAdapter adapter, View view, int position); 188 | 189 | public boolean inRangeOfView(View view, MotionEvent ev) { 190 | int[] location = new int[2]; 191 | if (view.getVisibility()!= View.VISIBLE){ 192 | return false; 193 | } 194 | view.getLocationOnScreen(location); 195 | int x = location[0]; 196 | int y = location[1]; 197 | if (ev.getRawX() < x 198 | || ev.getRawX() > (x + view.getWidth()) 199 | || ev.getRawY() < y 200 | || ev.getRawY() > (y + view.getHeight())) { 201 | return false; 202 | } 203 | return true; 204 | } 205 | 206 | private boolean isHeaderOrFooterPosition(int position) { 207 | /** 208 | * have a headview and EMPTY_VIEW FOOTER_VIEW LOADING_VIEW 209 | */ 210 | int type = baseQuickAdapter.getItemViewType(position); 211 | return (type == BaseQuickAdapter.EMPTY_VIEW || type == BaseQuickAdapter.HEADER_VIEW || type == BaseQuickAdapter.FOOTER_VIEW || type == BaseQuickAdapter.LOADING_VIEW); 212 | } 213 | 214 | } 215 | 216 | 217 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/base/baseadapter/SlideInBottomAnimation.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.base.baseadapter; 2 | 3 | import android.animation.Animator; 4 | import android.animation.ObjectAnimator; 5 | import android.view.View; 6 | 7 | 8 | public class SlideInBottomAnimation implements BaseAnimation { 9 | 10 | 11 | 12 | @Override 13 | public Animator[] getAnimators(View view) { 14 | return new Animator[]{ 15 | ObjectAnimator.ofFloat(view, "translationY", view.getMeasuredHeight(), 0) 16 | }; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/base/baseadapter/SlideInLeftAnimation.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.base.baseadapter; 2 | 3 | import android.animation.Animator; 4 | import android.animation.ObjectAnimator; 5 | import android.view.View; 6 | 7 | 8 | public class SlideInLeftAnimation implements BaseAnimation { 9 | 10 | 11 | @Override 12 | public Animator[] getAnimators(View view) { 13 | return new Animator[] { 14 | ObjectAnimator.ofFloat(view, "translationX", -view.getRootView().getWidth(), 0) 15 | }; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/base/baseadapter/SlideInRightAnimation.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.base.baseadapter; 2 | 3 | import android.animation.Animator; 4 | import android.animation.ObjectAnimator; 5 | import android.view.View; 6 | 7 | 8 | public class SlideInRightAnimation implements BaseAnimation { 9 | 10 | 11 | @Override 12 | public Animator[] getAnimators(View view) { 13 | return new Animator[]{ 14 | ObjectAnimator.ofFloat(view, "translationX", view.getRootView().getWidth(), 0) 15 | }; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/baserx/RxBus.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.baserx; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | 6 | 7 | import java.util.ArrayList; 8 | import java.util.Collection; 9 | import java.util.List; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | 12 | import rx.Observable; 13 | import rx.android.schedulers.AndroidSchedulers; 14 | import rx.functions.Action1; 15 | import rx.subjects.PublishSubject; 16 | import rx.subjects.Subject; 17 | 18 | /** 19 | * 用RxJava实现的EventBus 20 | * Created by qyh on 2016/8/6. 21 | */ 22 | public class RxBus { 23 | private static RxBus instance; 24 | 25 | public static synchronized RxBus getInstance() { 26 | if (null == instance) { 27 | instance = new RxBus(); 28 | } 29 | return instance; 30 | } 31 | 32 | private RxBus() { 33 | } 34 | 35 | @SuppressWarnings("rawtypes") 36 | private ConcurrentHashMap> subjectMapper = new ConcurrentHashMap>(); 37 | 38 | /** 39 | * 订阅事件源 40 | * 41 | * @param mObservable 42 | * @param mAction1 43 | * @return 44 | */ 45 | public RxBus OnEvent(Observable mObservable, Action1 mAction1) { 46 | mObservable.observeOn(AndroidSchedulers.mainThread()).subscribe(mAction1, new Action1() { 47 | @Override 48 | public void call(Throwable throwable) { 49 | throwable.printStackTrace(); 50 | } 51 | }); 52 | return getInstance(); 53 | } 54 | 55 | /** 56 | * 注册事件源 57 | * 58 | * @param tag 59 | * @return 60 | */ 61 | @SuppressWarnings({"rawtypes"}) 62 | public Observable register(@NonNull Object tag) { 63 | List subjectList = subjectMapper.get(tag); 64 | if (null == subjectList) { 65 | subjectList = new ArrayList(); 66 | subjectMapper.put(tag, subjectList); 67 | } 68 | Subject subject; 69 | subjectList.add(subject = PublishSubject.create()); 70 | //LogUtils.logd("register"+tag + " size:" + subjectList.size()); 71 | return subject; 72 | } 73 | 74 | @SuppressWarnings("rawtypes") 75 | public void unregister(@NonNull Object tag) { 76 | List subjects = subjectMapper.get(tag); 77 | if (null != subjects) { 78 | subjectMapper.remove(tag); 79 | } 80 | } 81 | 82 | /** 83 | * 取消监听 84 | * 85 | * @param tag 86 | * @param observable 87 | * @return 88 | */ 89 | @SuppressWarnings("rawtypes") 90 | public RxBus unregister(@NonNull Object tag, 91 | @NonNull Observable observable) { 92 | if (null == observable) 93 | return getInstance(); 94 | List subjects = subjectMapper.get(tag); 95 | if (null != subjects) { 96 | subjects.remove((Subject) observable); 97 | if (isEmpty(subjects)) { 98 | subjectMapper.remove(tag); 99 | } 100 | } 101 | return getInstance(); 102 | } 103 | 104 | public void post(@NonNull Object content) { 105 | post(content.getClass().getName(), content); 106 | } 107 | 108 | /** 109 | * 触发事件 110 | * 111 | * @param content 112 | */ 113 | @SuppressWarnings({"unchecked", "rawtypes"}) 114 | public void post(@NonNull Object tag, @NonNull Object content) { 115 | //LogUtils.logd("post"+ "eventName: " + tag); 116 | List subjectList = subjectMapper.get(tag); 117 | if (!isEmpty(subjectList)) { 118 | for (Subject subject : subjectList) { 119 | subject.onNext(content); 120 | // LogUtils.logd("onEvent"+ "eventName: " + tag); 121 | } 122 | } 123 | } 124 | 125 | @SuppressWarnings("rawtypes") 126 | public static boolean isEmpty(Collection collection) { 127 | return null == collection || collection.isEmpty(); 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/baserx/RxCache.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.baserx; 2 | 3 | import android.content.Context; 4 | 5 | 6 | 7 | import java.io.Serializable; 8 | 9 | import qyh.androidprojecthelper.utils.ACache; 10 | import rx.Observable; 11 | import rx.Subscriber; 12 | import rx.android.schedulers.AndroidSchedulers; 13 | import rx.functions.Func1; 14 | import rx.schedulers.Schedulers; 15 | 16 | /** 17 | * des:处理服务器数据的缓存 18 | Created by qyh on 2016/12/28. 19 | */ 20 | //################################使用例子############################# 21 | /* 22 | Observable fromNetwork = Api.getDefault() 23 | .login(phone, password) 24 | .compose(RxHelper.handleResult()); 25 | 26 | RxCache.load(context,cacheKey,1000*60*30,fromNetwork,false) 27 | .subscribe(new RxSubscribe(context, "登录中...") { 28 | @Override 29 | protected void _onNext(LoginData data) { 30 | showToast(R.string.login_success); 31 | //TODO login success 32 | } 33 | 34 | @Override 35 | protected void _onError(String message) { 36 | showToast(message); 37 | } 38 | }); 39 | */ 40 | 41 | 42 | public class RxCache { 43 | /** 44 | * 45 | * @param context 46 | * @param cacheKey 47 | * @param expireTime 48 | * @param fromNetwork 49 | * @param forceRefresh 50 | * @param 51 | * @return 52 | */ 53 | public static Observable load(final Context context, 54 | final String cacheKey, 55 | final int expireTime, 56 | Observable fromNetwork, 57 | boolean forceRefresh) { 58 | Observable fromCache = Observable.create(new Observable.OnSubscribe() { 59 | @Override 60 | public void call(Subscriber subscriber) { 61 | //获取缓存 62 | T cache = (T) ACache.get(context).getAsObject(cacheKey); 63 | if (cache != null) { 64 | subscriber.onNext(cache); 65 | } else { 66 | subscriber.onCompleted(); 67 | } 68 | } 69 | }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()); 70 | 71 | /** 72 | * 这里的fromNetwork 不需要指定Schedule,在handleRequest中已经变换了 73 | */ 74 | fromNetwork = fromNetwork.map(new Func1() { 75 | @Override 76 | public T call(T result) { 77 | //保存缓存 78 | ACache.get(context).put(cacheKey, (Serializable) result, expireTime); 79 | return result; 80 | } 81 | }); 82 | //强制刷新则返回接口数据 83 | if (forceRefresh) { 84 | return fromNetwork; 85 | } else { 86 | //优先返回缓存 87 | return Observable.concat(fromCache, fromNetwork).first(); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/baserx/RxManager.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.baserx; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import rx.Observable; 7 | import rx.Subscription; 8 | import rx.android.schedulers.AndroidSchedulers; 9 | import rx.functions.Action1; 10 | import rx.subscriptions.CompositeSubscription; 11 | 12 | /** 13 | * 用于管理单个presenter的RxBus的事件和Rxjava相关代码的生命周期处理 14 | * Created by qyh on 2016/12/6. 15 | */ 16 | public class RxManager { 17 | public RxBus mRxBus = RxBus.getInstance(); 18 | //管理rxbus订阅 19 | private Map> mObservables = new HashMap<>(); 20 | /*管理Observables 和 Subscribers订阅*/ 21 | private CompositeSubscription mCompositeSubscription = new CompositeSubscription(); 22 | 23 | /** 24 | * RxBus注入监听 25 | * @param eventName 26 | * @param action1 27 | */ 28 | public void on(String eventName, Action1 action1) { 29 | Observable mObservable = mRxBus.register(eventName); 30 | mObservables.put(eventName, mObservable); 31 | /*订阅管理*/ 32 | mCompositeSubscription.add(mObservable.observeOn(AndroidSchedulers.mainThread()) 33 | .subscribe(action1, new Action1() { 34 | @Override 35 | public void call(Throwable throwable) { 36 | throwable.printStackTrace(); 37 | } 38 | })); 39 | } 40 | 41 | /** 42 | * 单纯的Observables 和 Subscribers管理 43 | * @param m 44 | */ 45 | public void add(Subscription m) { 46 | /*订阅管理*/ 47 | mCompositeSubscription.add(m); 48 | } 49 | /** 50 | * 单个presenter生命周期结束,取消订阅和所有rxbus观察 51 | */ 52 | public void clear() { 53 | mCompositeSubscription.unsubscribe();// 取消所有订阅 54 | for (Map.Entry> entry : mObservables.entrySet()) { 55 | mRxBus.unregister(entry.getKey(), entry.getValue());// 移除rxbus观察 56 | } 57 | } 58 | //发送rxbus 59 | public void post(Object tag, Object content) { 60 | mRxBus.post(tag, content); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/baserx/RxSchedulers.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.baserx; 2 | 3 | import rx.Observable; 4 | import rx.android.schedulers.AndroidSchedulers; 5 | import rx.schedulers.Schedulers; 6 | 7 | /** 8 | * RxJava调度管理 9 | * Created by qyh on 2016/12/6. 10 | */ 11 | public class RxSchedulers { 12 | public static Observable.Transformer io_main() { 13 | return new Observable.Transformer() { 14 | @Override 15 | public Observable call(Observable observable) { 16 | return observable.subscribeOn(Schedulers.io()) 17 | .observeOn(AndroidSchedulers.mainThread()); 18 | } 19 | }; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/baserx/RxSubscriber.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.baserx; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | 6 | import qyh.androidprojecthelper.R; 7 | import qyh.androidprojecthelper.base.BaseApplication; 8 | import qyh.androidprojecthelper.utils.NetWorkUtils; 9 | import qyh.androidprojecthelper.view.LoadingDialog; 10 | import rx.Subscriber; 11 | 12 | /** 13 | * des:订阅封装 14 | Created by qyh on 2016/12/28. 15 | */ 16 | 17 | /********************使用例子********************/ 18 | /*_apiService.login(mobile, verifyCode) 19 | .//省略 20 | .subscribe(new RxSubscriber(mContext,false) { 21 | @Override 22 | public void _onNext(User user) { 23 | // 处理user 24 | } 25 | 26 | @Override 27 | public void _onError(String msg) { 28 | ToastUtil.showShort(mActivity, msg); 29 | });*/ 30 | public abstract class RxSubscriber extends Subscriber { 31 | 32 | private Context mContext; 33 | private String msg; 34 | private boolean showDialog=true; 35 | 36 | /** 37 | * 是否显示浮动dialog 38 | */ 39 | public void showDialog() { 40 | this.showDialog= true; 41 | } 42 | public void hideDialog() { 43 | this.showDialog= true; 44 | } 45 | 46 | public RxSubscriber(Context context, String msg, boolean showDialog) { 47 | this.mContext = context; 48 | this.msg = msg; 49 | this.showDialog=showDialog; 50 | } 51 | public RxSubscriber(Context context) { 52 | this(context, BaseApplication.getAppContext().getString(R.string.loading),true); 53 | } 54 | public RxSubscriber(Context context, boolean showDialog) { 55 | this(context, BaseApplication.getAppContext().getString(R.string.loading),showDialog); 56 | } 57 | 58 | @Override 59 | public void onCompleted() { 60 | if (showDialog) 61 | LoadingDialog.cancelDialogForLoading(); 62 | } 63 | @Override 64 | public void onStart() { 65 | super.onStart(); 66 | if (showDialog) { 67 | try { 68 | LoadingDialog.showDialogForLoading((Activity) mContext,msg,true); 69 | } catch (Exception e) { 70 | e.printStackTrace(); 71 | } 72 | } 73 | } 74 | 75 | 76 | @Override 77 | public void onNext(T t) { 78 | _onNext(t); 79 | } 80 | @Override 81 | public void onError(Throwable e) { 82 | if (showDialog) 83 | LoadingDialog.cancelDialogForLoading(); 84 | e.printStackTrace(); 85 | //网络 86 | if (!NetWorkUtils.isNetConnected(BaseApplication.getAppContext())) { 87 | _onError(BaseApplication.getAppContext().getString(R.string.no_net)); 88 | } 89 | //服务器 90 | else if (e instanceof ServerException) { 91 | _onError(e.getMessage()); 92 | } 93 | //其它 94 | else { 95 | _onError(BaseApplication.getAppContext().getString(R.string.net_error)); 96 | } 97 | } 98 | 99 | protected abstract void _onNext(T t); 100 | 101 | protected abstract void _onError(String message); 102 | 103 | } 104 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/baserx/ServerException.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.baserx; 2 | 3 | /** 4 | * des:服务器请求异常 5 | * Created by qyh on 2016/12/6. 6 | */ 7 | public class ServerException extends Exception { 8 | 9 | public ServerException(String msg){ 10 | super(msg); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/bean/FirstBean.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.bean; 2 | 3 | /** 4 | * 描述: 5 | * Created by qyh on 2016/12/28. 6 | */ 7 | public class FirstBean { 8 | /** 9 | * _id : 57a4056c421aa91e2606478d 10 | * createdAt : 2016-08-05T11:18:04.807Z 11 | * desc : 8.5 12 | * publishedAt : 2016-08-05T11:31:58.293Z 13 | * source : chrome 14 | * type : 福利 15 | * url : http://ww4.sinaimg.cn/large/610dc034jw1f6ipaai7wgj20dw0kugp4.jpg 16 | * used : true 17 | * who : 代码家 18 | */ 19 | 20 | private String _id; 21 | private String createdAt; 22 | private String desc; 23 | private String publishedAt; 24 | private String source; 25 | private String type; 26 | private String url; 27 | private boolean used; 28 | private String who; 29 | 30 | public String get_id() { 31 | return _id; 32 | } 33 | 34 | public void set_id(String _id) { 35 | this._id = _id; 36 | } 37 | 38 | public String getCreatedAt() { 39 | return createdAt; 40 | } 41 | 42 | public void setCreatedAt(String createdAt) { 43 | this.createdAt = createdAt; 44 | } 45 | 46 | public String getDesc() { 47 | return desc; 48 | } 49 | 50 | public void setDesc(String desc) { 51 | this.desc = desc; 52 | } 53 | 54 | public String getPublishedAt() { 55 | return publishedAt; 56 | } 57 | 58 | public void setPublishedAt(String publishedAt) { 59 | this.publishedAt = publishedAt; 60 | } 61 | 62 | public String getSource() { 63 | return source; 64 | } 65 | 66 | public void setSource(String source) { 67 | this.source = source; 68 | } 69 | 70 | public String getType() { 71 | return type; 72 | } 73 | 74 | public void setType(String type) { 75 | this.type = type; 76 | } 77 | 78 | public String getUrl() { 79 | return url; 80 | } 81 | 82 | public void setUrl(String url) { 83 | this.url = url; 84 | } 85 | 86 | public boolean isUsed() { 87 | return used; 88 | } 89 | 90 | public void setUsed(boolean used) { 91 | this.used = used; 92 | } 93 | 94 | public String getWho() { 95 | return who; 96 | } 97 | 98 | public void setWho(String who) { 99 | this.who = who; 100 | } 101 | 102 | @Override 103 | public String toString() { 104 | return "FirstBean{" + 105 | "_id='" + _id + '\'' + 106 | ", createdAt='" + createdAt + '\'' + 107 | ", desc='" + desc + '\'' + 108 | ", publishedAt='" + publishedAt + '\'' + 109 | ", source='" + source + '\'' + 110 | ", type='" + type + '\'' + 111 | ", url='" + url + '\'' + 112 | ", used=" + used + 113 | ", who='" + who + '\'' + 114 | '}'; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/bean/GirlData.java: -------------------------------------------------------------------------------- 1 | 2 | package qyh.androidprojecthelper.bean; 3 | 4 | import java.util.List; 5 | 6 | public class GirlData { 7 | private boolean isError; 8 | private List results; 9 | 10 | public boolean isError() { 11 | return isError; 12 | } 13 | 14 | public void setError(boolean error) { 15 | isError = error; 16 | } 17 | 18 | public void setResults(List results) { 19 | this.results = results; 20 | } 21 | 22 | public List getResults() { 23 | return results; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/bean/SecondChannelTabBean.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.bean; 2 | 3 | /** 4 | * 描述: 5 | * Created by qyh on 2017/1/12. 6 | */ 7 | public class SecondChannelTabBean { 8 | private String name; 9 | private String id; 10 | 11 | public SecondChannelTabBean(String name, String id) { 12 | this.name = name; 13 | this.id = id; 14 | } 15 | 16 | public String getName() { 17 | return name; 18 | } 19 | 20 | public void setName(String name) { 21 | this.name = name; 22 | } 23 | 24 | public String getId() { 25 | return id; 26 | } 27 | 28 | public void setId(String id) { 29 | this.id = id; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/bean/TabEntity.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.bean; 2 | 3 | import com.flyco.tablayout.listener.CustomTabEntity; 4 | 5 | public class TabEntity implements CustomTabEntity { 6 | public String title; 7 | public int selectedIcon; 8 | public int unSelectedIcon; 9 | 10 | public TabEntity(String title, int selectedIcon, int unSelectedIcon) { 11 | this.title = title; 12 | this.selectedIcon = selectedIcon; 13 | this.unSelectedIcon = unSelectedIcon; 14 | } 15 | 16 | @Override 17 | public String getTabTitle() { 18 | return title; 19 | } 20 | 21 | @Override 22 | public int getTabSelectedIcon() { 23 | return selectedIcon; 24 | } 25 | 26 | @Override 27 | public int getTabUnselectedIcon() { 28 | return unSelectedIcon; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/contract/FirstContract.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.contract; 2 | 3 | import java.util.List; 4 | 5 | import qyh.androidprojecthelper.base.BaseModel; 6 | import qyh.androidprojecthelper.base.BasePresenter; 7 | import qyh.androidprojecthelper.base.BaseView; 8 | import qyh.androidprojecthelper.bean.FirstBean; 9 | import rx.Observable; 10 | 11 | /** 12 | * 描述: 13 | * Created by qyh on 2016/12/28. 14 | */ 15 | public interface FirstContract { 16 | 17 | interface Model extends BaseModel{ 18 | //请求获取数据 19 | Observable> getListData(int size,int page); 20 | } 21 | interface View extends BaseView{ 22 | //返回获取的数据 23 | void showListData(List listData); 24 | } 25 | 26 | abstract static class Presenter extends BasePresenter{ 27 | public abstract void getFirstListDataRequest(int size,int page); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/db/SecondChannelManager.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.db; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | import qyh.androidprojecthelper.R; 8 | import qyh.androidprojecthelper.base.BaseApplication; 9 | import qyh.androidprojecthelper.bean.SecondChannelTabBean; 10 | 11 | /** 12 | * 描述: 13 | * Created by qyh on 2017/1/12. 14 | */ 15 | public class SecondChannelManager { 16 | 17 | public static List loadTab(){ 18 | List name = Arrays.asList(BaseApplication.getAppContext().getResources().getStringArray(R.array.second_fragment_name)); 19 | List id = Arrays.asList(BaseApplication.getAppContext().getResources().getStringArray(R.array.second_fragment_id)); 20 | ArrayList list = new ArrayList<>(); 21 | for(int i=0;i implements 33 | FirstContract.View, BaseQuickAdapter.RequestLoadMoreListener, RefreshLayout.RefreshLayoutDelegate { 34 | 35 | private int SIZE=20; 36 | private static final int STARTPAGE=1; 37 | @BindView(R.id.rv_content) 38 | public RecyclerView rv_content; 39 | @BindView(R.id.refresh) 40 | public RefreshLayout refreshLayout; 41 | @BindView(R.id.toolbar_title) 42 | public TextView toolbar_title; 43 | 44 | private Context mContext; 45 | private FirstTabAdapter mFirstTabAdapter; 46 | 47 | @Override 48 | protected int getLayoutResource() { 49 | mContext = getActivity(); 50 | return R.layout.fragment_firtst; 51 | } 52 | 53 | @Override 54 | public void initPresenter() { 55 | mPresenter.setVM(this,mModel); 56 | } 57 | 58 | @Override 59 | protected void initView() { 60 | toolbar_title.setText("妹纸"); 61 | mFirstTabAdapter = new FirstTabAdapter(R.layout.item_first,null); 62 | rv_content.setLayoutManager(new GridLayoutManager(mContext,2)); 63 | rv_content.setHasFixedSize(true); 64 | //设置适配器加载动画 65 | mFirstTabAdapter.openLoadAnimation(BaseQuickAdapter.SCALEIN); 66 | rv_content.setAdapter(mFirstTabAdapter); 67 | //设置适配器可以上拉加载 68 | mFirstTabAdapter.setOnLoadMoreListener(this); 69 | //设置下拉、上拉 70 | refreshLayout.setDelegate(this); 71 | refreshLayout.setRefreshViewHolder(new NormalRefreshViewHolder(mContext,true)); 72 | 73 | mPresenter.getFirstListDataRequest(SIZE,STARTPAGE); 74 | 75 | //条目的点击事件 76 | rv_content.addOnItemTouchListener(new OnItemClickListener() { 77 | @Override 78 | public void SimpleOnItemClick(BaseQuickAdapter adapter, View view, int position) { 79 | System.out.println("position===="+position); 80 | } 81 | }); 82 | 83 | } 84 | 85 | @Override 86 | public void showListData(List listData) { 87 | mFirstTabAdapter.setNewData(listData); 88 | refreshLayout.endRefreshing(); 89 | refreshLayout.endLoadingMore(); 90 | } 91 | //如果使用内嵌的加载提示,需要在这里处理,, 92 | // 我使用的LoadingDialog的方法,加载成功自动消失,所以不用处理进度消失等事件 93 | @Override 94 | public void showLoading(String title) { 95 | LoadingDialog.showDialogForLoading(getActivity()); 96 | } 97 | 98 | @Override 99 | public void stopLoading() { 100 | LoadingDialog.cancelDialogForLoading(); 101 | } 102 | //加载失败提示,根据需要自己处理 103 | @Override 104 | public void showErrorTip(String msg) { 105 | } 106 | 107 | @Override 108 | public void onLoadMoreRequested() { 109 | // BaseQuickAdapter的上拉加载更多方法,和onRefreshLayoutBeginLoadingMore使用其中一个就可以 110 | } 111 | 112 | @Override 113 | public void onRefreshLayoutBeginRefreshing(RefreshLayout refreshLayout) { 114 | System.out.println("onRefreshLayoutBeginRefreshing==="); 115 | mPresenter.getFirstListDataRequest(SIZE,STARTPAGE); 116 | } 117 | 118 | @Override 119 | public boolean onRefreshLayoutBeginLoadingMore(RefreshLayout refreshLayout) { 120 | SIZE+=20; 121 | mPresenter.getFirstListDataRequest(SIZE,STARTPAGE); 122 | return true; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/fragment/SecondListFragment.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.design.widget.TabLayout; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v4.view.ViewPager; 7 | 8 | import com.uuzuche.lib_zxing.view.ViewfinderView; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | import butterknife.BindView; 14 | import qyh.androidprojecthelper.R; 15 | import qyh.androidprojecthelper.base.BaseFragment; 16 | import qyh.androidprojecthelper.base.BaseFragmentAdapter; 17 | import qyh.androidprojecthelper.bean.SecondChannelTabBean; 18 | import qyh.androidprojecthelper.db.SecondChannelManager; 19 | 20 | 21 | /** 22 | * 描述: 23 | * Created by qyh on 2017/1/12. 24 | */ 25 | public class SecondListFragment extends BaseFragment { 26 | @BindView(R.id.tabs) 27 | public TabLayout tabs; 28 | @BindView(R.id.viewpager) 29 | public ViewPager viewPager; 30 | private BaseFragmentAdapter baseFragmentAdapter; 31 | 32 | 33 | @Override 34 | protected int getLayoutResource() { 35 | return R.layout.fragment_second_list; 36 | } 37 | 38 | @Override 39 | public void initPresenter() { 40 | 41 | } 42 | 43 | @Override 44 | protected void initView() { 45 | if(null!=getArguments()){ 46 | String id = getArguments().getString("id"); 47 | System.out.println("id=="+id); 48 | } 49 | ArrayList tabName=new ArrayList<>(); 50 | ArrayList fragments=new ArrayList<>(); 51 | List tabDatas = SecondChannelManager.loadTab(); 52 | for(int i=0;i tabName=new ArrayList<>(); 45 | ArrayList fragments=new ArrayList<>(); 46 | List tabDatas = SecondChannelManager.loadTab(); 47 | for(int i=0;i mPoints; 13 | 14 | 15 | public ViewPath() { 16 | mPoints = new ArrayList<>(); 17 | } 18 | 19 | public void moveTo(float x, float y){ 20 | mPoints.add(ViewPoint.moveTo(x,y,MOVE)); 21 | } 22 | 23 | public void lineTo(float x,float y){ 24 | mPoints.add(ViewPoint.lineTo(x,y,LINE)); 25 | } 26 | 27 | public void curveTo(float x,float y,float x1,float y1,float x2,float y2){ 28 | mPoints.add(ViewPoint.curveTo(x,y,x1,y1,x2,y2,CURVE)); 29 | } 30 | 31 | public void quadTo(float x,float y,float x1,float y1){ 32 | mPoints.add(ViewPoint.quadTo(x,y,x1,y1,QUAD)); 33 | } 34 | 35 | public Collection getPoints(){ 36 | return mPoints; 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/launcher/ViewPathEvaluator.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.launcher; 2 | 3 | import android.animation.TypeEvaluator; 4 | 5 | 6 | public class ViewPathEvaluator implements TypeEvaluator { 7 | 8 | 9 | public ViewPathEvaluator() { 10 | } 11 | 12 | @Override 13 | public ViewPoint evaluate(float t, ViewPoint startValue, ViewPoint endValue) { 14 | 15 | float x ,y; 16 | 17 | float startX,startY; 18 | 19 | if(endValue.operation == ViewPath.LINE){ 20 | 21 | startX = (startValue.operation==ViewPath.QUAD)?startValue.x1:startValue.x; 22 | 23 | startX = (startValue.operation == ViewPath.CURVE)?startValue.x2:startX; 24 | 25 | startY = (startValue.operation==ViewPath.QUAD)?startValue.y1:startValue.y; 26 | 27 | startY = (startValue.operation == ViewPath.CURVE)?startValue.y2:startY; 28 | 29 | x = startX + t * (endValue.x - startX); 30 | y = startY+ t * (endValue.y - startY); 31 | 32 | 33 | 34 | }else if(endValue.operation == ViewPath.CURVE){ 35 | 36 | 37 | startX = (startValue.operation==ViewPath.QUAD)?startValue.x1:startValue.x; 38 | startY = (startValue.operation==ViewPath.QUAD)?startValue.y1:startValue.y; 39 | 40 | float oneMinusT = 1 - t; 41 | 42 | 43 | x = oneMinusT * oneMinusT * oneMinusT * startX + 44 | 3 * oneMinusT * oneMinusT * t * endValue.x + 45 | 3 * oneMinusT * t * t * endValue.x1+ 46 | t * t * t * endValue.x2; 47 | 48 | y = oneMinusT * oneMinusT * oneMinusT * startY + 49 | 3 * oneMinusT * oneMinusT * t * endValue.y + 50 | 3 * oneMinusT * t * t * endValue.y1+ 51 | t * t * t * endValue.y2; 52 | 53 | 54 | }else if(endValue.operation == ViewPath.MOVE){ 55 | 56 | x = endValue.x; 57 | y = endValue.y; 58 | 59 | 60 | }else if(endValue.operation == ViewPath.QUAD){ 61 | 62 | 63 | startX = (startValue.operation==ViewPath.CURVE)?startValue.x2:startValue.x; 64 | startY = (startValue.operation==ViewPath.CURVE)?startValue.y2:startValue.y; 65 | 66 | float oneMinusT = 1 - t; 67 | x = oneMinusT * oneMinusT * startX + 68 | 2 * oneMinusT * t * endValue.x + 69 | t * t * endValue.x1; 70 | 71 | y = oneMinusT * oneMinusT * startY + 72 | 2 * oneMinusT * t * endValue.y + 73 | t * t * endValue.y1; 74 | 75 | 76 | }else { 77 | x = endValue.x; 78 | y = endValue.y; 79 | } 80 | 81 | 82 | return new ViewPoint(x,y); 83 | } 84 | } 85 | 86 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/launcher/ViewPoint.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.launcher; 2 | 3 | 4 | public class ViewPoint { 5 | float x ,y; 6 | 7 | float x1,y1; 8 | 9 | float x2,y2; 10 | 11 | int operation; 12 | 13 | public ViewPoint(float x, float y) { 14 | this.x = x; 15 | this.y = y; 16 | } 17 | 18 | public static ViewPoint moveTo(float x, float y, int operation){ 19 | return new ViewPoint(x,y,operation); 20 | } 21 | 22 | public static ViewPoint lineTo(float x, float y, int operation){ 23 | return new ViewPoint(x,y,operation); 24 | } 25 | public static ViewPoint curveTo(float x, float y,float x1,float y1,float x2,float y2, int operation){ 26 | return new ViewPoint(x,y,x1,y1,x2,y2,operation); 27 | } 28 | 29 | public static ViewPoint quadTo(float x, float y,float x1,float y1, int operation){ 30 | return new ViewPoint(x,y,x1,y1,operation); 31 | } 32 | 33 | 34 | 35 | private ViewPoint(float x, float y, int operation) { 36 | this.x = x; 37 | this.y = y; 38 | this.operation = operation; 39 | } 40 | 41 | public ViewPoint(float x, float y, float x1, float y1, int operation) { 42 | this.x = x; 43 | this.y = y; 44 | this.x1 = x1; 45 | this.y1 = y1; 46 | this.operation = operation; 47 | } 48 | 49 | public ViewPoint(float x, float y, float x1, float y1, float x2, float y2, int operation) { 50 | this.x = x; 51 | this.y = y; 52 | this.x1 = x1; 53 | this.y1 = y1; 54 | this.x2 = x2; 55 | this.y2 = y2; 56 | this.operation = operation; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/model/FirstModel.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.model; 2 | 3 | import java.util.List; 4 | import qyh.androidprojecthelper.api.Api; 5 | import qyh.androidprojecthelper.baserx.RxSchedulers; 6 | import qyh.androidprojecthelper.bean.FirstBean; 7 | import qyh.androidprojecthelper.bean.GirlData; 8 | import qyh.androidprojecthelper.contract.FirstContract; 9 | import rx.Observable; 10 | import rx.functions.Func1; 11 | 12 | /** 13 | * 描述: 14 | * Created by qyh on 2016/12/28. 15 | */ 16 | 17 | public class FirstModel implements FirstContract.Model { 18 | @Override 19 | public Observable> getListData(int size, int page) { 20 | 21 | return Api.getInstance().service.getListData(size,page) 22 | .map(new Func1>() { 23 | @Override 24 | public List call(GirlData girlData) { 25 | return girlData.getResults(); 26 | } 27 | }).compose(RxSchedulers.>io_main()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/presenter/firstPresenter.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.presenter; 2 | 3 | import java.util.List; 4 | 5 | import qyh.androidprojecthelper.R; 6 | import qyh.androidprojecthelper.baserx.RxSubscriber; 7 | import qyh.androidprojecthelper.bean.FirstBean; 8 | import qyh.androidprojecthelper.contract.FirstContract; 9 | 10 | /** 11 | * 描述: 12 | * Created by qyh on 2016/12/28. 13 | */ 14 | public class FirstPresenter extends FirstContract.Presenter{ 15 | 16 | @Override 17 | public void getFirstListDataRequest(int size, int page) { 18 | 19 | mRxManage.add(mModel.getListData(size,page).subscribe(new RxSubscriber>(mContext,false) { 20 | @Override 21 | public void onStart() { 22 | super.onStart(); 23 | mView.showLoading(mContext.getString(R.string.loading)); 24 | } 25 | @Override 26 | protected void _onNext(List firstBeen) { 27 | mView.showListData(firstBeen); 28 | mView.stopLoading(); 29 | } 30 | @Override 31 | protected void _onError(String message) { 32 | mView.showErrorTip(message); 33 | } 34 | })); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/utils/CollectionUtils.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.utils; 2 | 3 | import java.util.Collection; 4 | 5 | /** 6 | * 集合操作工具类 7 | * 8 | */ 9 | public class CollectionUtils { 10 | 11 | /** 12 | * 判断集合是否为null或者0个元素 13 | * 14 | * @param c 15 | * @return 16 | */ 17 | public static boolean isNullOrEmpty(Collection c) { 18 | if (null == c || c.isEmpty()) { 19 | return true; 20 | } 21 | return false; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/utils/GlideRoundTransformUtil.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.utils; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapShader; 6 | import android.graphics.Canvas; 7 | import android.graphics.Paint; 8 | 9 | import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; 10 | import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; 11 | 12 | /** 13 | * description:glide转换圆角图片 14 | * on 2016.04.15:17 15 | */ 16 | public class GlideRoundTransformUtil extends BitmapTransformation { 17 | public GlideRoundTransformUtil(Context context) { 18 | super(context); 19 | } 20 | 21 | @Override 22 | protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) { 23 | return circleCrop(pool, toTransform); 24 | } 25 | 26 | private static Bitmap circleCrop(BitmapPool pool, Bitmap source) { 27 | if (source == null) return null; 28 | 29 | int size = Math.min(source.getWidth(), source.getHeight()); 30 | int x = (source.getWidth() - size) / 2; 31 | int y = (source.getHeight() - size) / 2; 32 | 33 | // TODO this could be acquired from the pool too 34 | Bitmap squared = Bitmap.createBitmap(source, x, y, size, size); 35 | 36 | Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888); 37 | if (result == null) { 38 | result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); 39 | } 40 | 41 | Canvas canvas = new Canvas(result); 42 | Paint paint = new Paint(); 43 | paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP)); 44 | paint.setAntiAlias(true); 45 | float r = size / 2f; 46 | canvas.drawCircle(r, r, r, paint); 47 | return result; 48 | } 49 | 50 | @Override 51 | public String getId() { 52 | return getClass().getName(); 53 | } 54 | } -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/utils/ImageLoaderUtils.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.utils; 2 | 3 | import android.content.Context; 4 | import android.widget.ImageView; 5 | 6 | import com.bumptech.glide.Glide; 7 | import com.bumptech.glide.load.DecodeFormat; 8 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 9 | 10 | 11 | import java.io.File; 12 | 13 | import qyh.androidprojecthelper.R; 14 | 15 | /** 16 | * Description : 图片加载工具类 使用glide框架封装 17 | */ 18 | public class ImageLoaderUtils { 19 | 20 | public static void display(Context context, ImageView imageView, String url, int placeholder, int error) { 21 | if (imageView == null) { 22 | throw new IllegalArgumentException("argument error"); 23 | } 24 | Glide.with(context).load(url).placeholder(placeholder) 25 | .error(error).crossFade().into(imageView); 26 | } 27 | 28 | public static void display(Context context, ImageView imageView, String url) { 29 | if (imageView == null) { 30 | throw new IllegalArgumentException("argument error"); 31 | } 32 | Glide.with(context).load(url) 33 | .diskCacheStrategy(DiskCacheStrategy.ALL) 34 | .centerCrop() 35 | .placeholder(R.mipmap.ic_image_loading) 36 | .error(R.mipmap.ic_empty_picture) 37 | .crossFade().into(imageView); 38 | } 39 | 40 | public static void display(Context context, ImageView imageView, File url) { 41 | if (imageView == null) { 42 | throw new IllegalArgumentException("argument error"); 43 | } 44 | Glide.with(context).load(url) 45 | .diskCacheStrategy(DiskCacheStrategy.ALL) 46 | .centerCrop() 47 | .placeholder(R.mipmap.ic_image_loading) 48 | .error(R.mipmap.ic_empty_picture) 49 | .crossFade().into(imageView); 50 | } 51 | public static void displaySmallPhoto(Context context, ImageView imageView, String url) { 52 | if (imageView == null) { 53 | throw new IllegalArgumentException("argument error"); 54 | } 55 | Glide.with(context).load(url).asBitmap() 56 | .diskCacheStrategy(DiskCacheStrategy.ALL) 57 | .placeholder(R.mipmap.ic_image_loading) 58 | .error(R.mipmap.ic_empty_picture) 59 | .thumbnail(0.5f) 60 | .into(imageView); 61 | } 62 | public static void displayBigPhoto(Context context, ImageView imageView, String url) { 63 | if (imageView == null) { 64 | throw new IllegalArgumentException("argument error"); 65 | } 66 | Glide.with(context).load(url).asBitmap() 67 | .format(DecodeFormat.PREFER_ARGB_8888) 68 | .diskCacheStrategy(DiskCacheStrategy.ALL) 69 | .placeholder(R.mipmap.ic_image_loading) 70 | .error(R.mipmap.ic_empty_picture) 71 | .into(imageView); 72 | } 73 | public static void display(Context context, ImageView imageView, int url) { 74 | if (imageView == null) { 75 | throw new IllegalArgumentException("argument error"); 76 | } 77 | Glide.with(context).load(url) 78 | .diskCacheStrategy(DiskCacheStrategy.ALL) 79 | .centerCrop() 80 | .placeholder(R.mipmap.ic_image_loading) 81 | .error(R.mipmap.ic_empty_picture) 82 | .crossFade().into(imageView); 83 | } 84 | public static void displayRound(Context context, ImageView imageView, String url) { 85 | if (imageView == null) { 86 | throw new IllegalArgumentException("argument error"); 87 | } 88 | Glide.with(context).load(url) 89 | .diskCacheStrategy(DiskCacheStrategy.ALL) 90 | .error(R.mipmap.toux2) 91 | .centerCrop().transform(new GlideRoundTransformUtil(context)).into(imageView); 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/utils/NetWorkUtils.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.utils; 2 | 3 | import android.content.Context; 4 | import android.net.ConnectivityManager; 5 | import android.net.NetworkInfo; 6 | 7 | import java.util.regex.Matcher; 8 | import java.util.regex.Pattern; 9 | 10 | /** 11 | * des:网络管理工具 12 | * Created by qyh on 2016/12/6. 13 | */ 14 | public class NetWorkUtils { 15 | 16 | /** 17 | * 检查网络是否可用 18 | * 19 | * @param paramContext 20 | * @return 21 | */ 22 | public static boolean isNetConnected(Context paramContext) { 23 | boolean i = false; 24 | NetworkInfo localNetworkInfo = ((ConnectivityManager) paramContext 25 | .getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo(); 26 | if ((localNetworkInfo != null) && (localNetworkInfo.isAvailable())) 27 | return true; 28 | return false; 29 | } 30 | /** 31 | * 检测wifi是否连接 32 | */ 33 | public static boolean isWifiConnected(Context context) { 34 | ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 35 | if (cm != null) { 36 | NetworkInfo networkInfo = cm.getActiveNetworkInfo(); 37 | if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI) { 38 | return true; 39 | } 40 | } 41 | return false; 42 | } 43 | 44 | /** 45 | * 检测3G是否连接 46 | */ 47 | public static boolean is3gConnected(Context context) { 48 | ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 49 | if (cm != null) { 50 | NetworkInfo networkInfo = cm.getActiveNetworkInfo(); 51 | if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) { 52 | return true; 53 | } 54 | } 55 | return false; 56 | } 57 | 58 | /** 59 | * 判断网址是否有效 60 | */ 61 | public static boolean isLinkAvailable(String link) { 62 | Pattern pattern = Pattern.compile("^(http://|https://)?((?:[A-Za-z0-9]+-[A-Za-z0-9]+|[A-Za-z0-9]+)\\.)+([A-Za-z]+)[/\\?\\:]?.*$", Pattern.CASE_INSENSITIVE); 63 | Matcher matcher = pattern.matcher(link); 64 | if (matcher.matches()) { 65 | return true; 66 | } 67 | return false; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/utils/TUtil.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.utils; 2 | 3 | import java.lang.reflect.ParameterizedType; 4 | 5 | /** 6 | * 类转换初始化 7 | */ 8 | public class TUtil { 9 | public static T getT(Object o, int i) { 10 | try { 11 | return ((Class) ((ParameterizedType) (o.getClass() 12 | .getGenericSuperclass())).getActualTypeArguments()[i]) 13 | .newInstance(); 14 | } catch (InstantiationException e) { 15 | e.printStackTrace(); 16 | } catch (IllegalAccessException e) { 17 | e.printStackTrace(); 18 | } catch (ClassCastException e) { 19 | e.printStackTrace(); 20 | } 21 | return null; 22 | } 23 | 24 | public static Class forName(String className) { 25 | try { 26 | return Class.forName(className); 27 | } catch (ClassNotFoundException e) { 28 | e.printStackTrace(); 29 | } 30 | return null; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/utils/ToastUitl.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.utils; 2 | 3 | import android.content.Context; 4 | import android.widget.Toast; 5 | import qyh.androidprojecthelper.base.BaseApplication; 6 | 7 | 8 | /** 9 | * Toast统一管理类 10 | */ 11 | public class ToastUitl { 12 | 13 | 14 | private static Toast toast; 15 | private static Toast toast2; 16 | 17 | private static Toast initToast(CharSequence message, int duration) { 18 | if (toast == null) { 19 | toast = Toast.makeText(BaseApplication.getAppContext(), message, duration); 20 | } else { 21 | toast.setText(message); 22 | toast.setDuration(duration); 23 | } 24 | return toast; 25 | } 26 | 27 | /** 28 | * 短时间显示Toast 29 | * 30 | * @param message 31 | */ 32 | public static void showShort(CharSequence message) { 33 | initToast(message, Toast.LENGTH_SHORT).show(); 34 | } 35 | 36 | 37 | /** 38 | * 短时间显示Toast 39 | * 40 | * @param strResId 41 | */ 42 | public static void showShort(int strResId) { 43 | // Toast.makeText(context, strResId, Toast.LENGTH_SHORT).show(); 44 | initToast(BaseApplication.getAppContext().getResources().getText(strResId), Toast.LENGTH_SHORT).show(); 45 | } 46 | 47 | /** 48 | * 长时间显示Toast 49 | * 50 | * @param message 51 | */ 52 | public static void showLong(CharSequence message) { 53 | initToast(message, Toast.LENGTH_LONG).show(); 54 | } 55 | 56 | /** 57 | * 长时间显示Toast 58 | * 59 | * @param strResId 60 | */ 61 | public static void showLong(int strResId) { 62 | initToast(BaseApplication.getAppContext().getResources().getText(strResId), Toast.LENGTH_LONG).show(); 63 | } 64 | 65 | /** 66 | * 自定义显示Toast时间 67 | * 68 | * @param message 69 | * @param duration 70 | */ 71 | public static void show(CharSequence message, int duration) { 72 | initToast(message, duration).show(); 73 | } 74 | 75 | /** 76 | * 自定义显示Toast时间 77 | * 78 | * @param context 79 | * @param strResId 80 | * @param duration 81 | */ 82 | public static void show(Context context, int strResId, int duration) { 83 | initToast(context.getResources().getText(strResId), duration).show(); 84 | } 85 | 86 | // /** 87 | // * 显示有image的toast 88 | // * 89 | // * @param tvStr 90 | // * @param imageResource 91 | // * @return 92 | // */ 93 | // public static Toast showToastWithImg(final String tvStr, final int imageResource) { 94 | // if (toast2 == null) { 95 | // toast2 = new Toast(BaseApplication.getAppContext()); 96 | // } 97 | // View view = LayoutInflater.from(BaseApplication.getAppContext()).inflate(R.layout.toast_custom, null); 98 | // TextView tv = (TextView) view.findViewById(R.id.toast_custom_tv); 99 | // tv.setText(TextUtils.isEmpty(tvStr) ? "" : tvStr); 100 | // ImageView iv = (ImageView) view.findViewById(R.id.toast_custom_iv); 101 | // if (imageResource > 0) { 102 | // iv.setVisibility(View.VISIBLE); 103 | // iv.setImageResource(imageResource); 104 | // } else { 105 | // iv.setVisibility(View.GONE); 106 | // } 107 | // toast2.setView(view); 108 | // toast2.setGravity(Gravity.CENTER, 0, 0); 109 | // toast2.show(); 110 | // return toast2; 111 | // 112 | // } 113 | } 114 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/utils/Utils.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.utils; 2 | 3 | import android.content.Context; 4 | 5 | 6 | public class Utils { 7 | /** 8 | * dp转px 9 | * 10 | * @param context 上下文 11 | * @param dpValue dp值 12 | * @return px值 13 | */ 14 | public static int dp2px(Context context, float dpValue) { 15 | final float scale = context.getResources().getDisplayMetrics().density; 16 | return (int) (dpValue * scale + 0.5f); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/view/CustomViewPager.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.view; 2 | 3 | import android.content.Context; 4 | import android.graphics.PointF; 5 | import android.support.v4.view.ViewPager; 6 | import android.util.AttributeSet; 7 | import android.view.MotionEvent; 8 | import android.view.View; 9 | 10 | public class CustomViewPager extends ViewPager { 11 | 12 | public CustomViewPager(Context context) { 13 | super(context); 14 | } 15 | 16 | public CustomViewPager(Context context, AttributeSet attrs) { 17 | super(context, attrs); 18 | } 19 | 20 | PointF downPoint = new PointF(); 21 | OnSingleTouchListener onSingleTouchListener; 22 | 23 | @Override 24 | public boolean onTouchEvent(MotionEvent evt) { 25 | switch (evt.getAction()) { 26 | case MotionEvent.ACTION_DOWN: 27 | // 记录按下时候的坐标 28 | downPoint.x = evt.getX(); 29 | downPoint.y = evt.getY(); 30 | if (this.getChildCount() > 1) { //有内容,多于1个时 31 | // 通知其父控件,现在进行的是本控件的操作,不允许拦截 32 | getParent().requestDisallowInterceptTouchEvent(true); 33 | } 34 | break; 35 | case MotionEvent.ACTION_MOVE: 36 | if (this.getChildCount() > 1) { //有内容,多于1个时 37 | // 通知其父控件,现在进行的是本控件的操作,不允许拦截 38 | getParent().requestDisallowInterceptTouchEvent(true); 39 | } 40 | break; 41 | case MotionEvent.ACTION_UP: 42 | // 在up时判断是否按下和松手的坐标为一个点 43 | if (PointF.length(evt.getX() - downPoint.x, evt.getY() 44 | - downPoint.y) < (float) 5.0) { 45 | onSingleTouch(this); 46 | return true; 47 | } 48 | break; 49 | } 50 | return super.onTouchEvent(evt); 51 | } 52 | 53 | public void onSingleTouch(View v) { 54 | if (onSingleTouchListener != null) { 55 | onSingleTouchListener.onSingleTouch(v); 56 | } 57 | } 58 | 59 | public interface OnSingleTouchListener { 60 | public void onSingleTouch(View v); 61 | } 62 | 63 | public void setOnSingleTouchListener( 64 | OnSingleTouchListener onSingleTouchListener) { 65 | this.onSingleTouchListener = onSingleTouchListener; 66 | } 67 | } -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/view/LoadingDialog.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.view; 2 | 3 | import android.app.Activity; 4 | import android.app.Dialog; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.widget.LinearLayout; 8 | import android.widget.TextView; 9 | 10 | import qyh.androidprojecthelper.R; 11 | 12 | 13 | /** 14 | * description:弹窗浮动加载进度条 15 | * Created by qyh on 2016/12/7. 16 | */ 17 | public class LoadingDialog { 18 | /** 加载数据对话框 */ 19 | private static Dialog mLoadingDialog; 20 | /** 21 | * 显示加载对话框 22 | * @param context 上下文 23 | * @param msg 对话框显示内容 24 | * @param cancelable 对话框是否可以取消 25 | */ 26 | public static Dialog showDialogForLoading(Activity context, String msg, boolean cancelable) { 27 | View view = LayoutInflater.from(context).inflate(R.layout.dialog_loading, null); 28 | TextView loadingText = (TextView)view.findViewById(R.id.id_tv_loading_dialog_text); 29 | loadingText.setText(msg); 30 | 31 | mLoadingDialog = new Dialog(context, R.style.CustomProgressDialog); 32 | mLoadingDialog.setCancelable(cancelable); 33 | mLoadingDialog.setCanceledOnTouchOutside(false); 34 | mLoadingDialog.setContentView(view, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT)); 35 | mLoadingDialog.show(); 36 | return mLoadingDialog; 37 | } 38 | 39 | public static Dialog showDialogForLoading(Activity context) { 40 | View view = LayoutInflater.from(context).inflate(R.layout.dialog_loading, null); 41 | TextView loadingText = (TextView)view.findViewById(R.id.id_tv_loading_dialog_text); 42 | loadingText.setText("加载中..."); 43 | 44 | mLoadingDialog = new Dialog(context, R.style.CustomProgressDialog); 45 | mLoadingDialog.setCancelable(true); 46 | mLoadingDialog.setCanceledOnTouchOutside(false); 47 | mLoadingDialog.setContentView(view, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT)); 48 | mLoadingDialog.show(); 49 | return mLoadingDialog; 50 | } 51 | 52 | /** 53 | * 关闭加载对话框 54 | */ 55 | public static void cancelDialogForLoading() { 56 | if(mLoadingDialog != null) { 57 | mLoadingDialog.cancel(); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/view/bottombar/BottomBar.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.view.bottombar; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.os.Parcel; 6 | import android.os.Parcelable; 7 | import android.support.v4.view.ViewCompat; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.view.ViewTreeObserver; 12 | import android.view.animation.AccelerateDecelerateInterpolator; 13 | import android.view.animation.Interpolator; 14 | import android.widget.LinearLayout; 15 | 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | 19 | 20 | /** 21 | * Created by YoKeyword on 16/6/3. 22 | */ 23 | public class BottomBar extends LinearLayout { 24 | private static final int TRANSLATE_DURATION_MILLIS = 200; 25 | 26 | private final Interpolator mInterpolator = new AccelerateDecelerateInterpolator(); 27 | private boolean mVisible = true; 28 | 29 | private List mTabs = new ArrayList<>(); 30 | 31 | private LinearLayout mTabLayout; 32 | 33 | private LayoutParams mTabParams; 34 | private int mCurrentPosition = 0; 35 | private OnTabSelectedListener mListener; 36 | 37 | public BottomBar(Context context) { 38 | this(context, null); 39 | } 40 | 41 | public BottomBar(Context context, AttributeSet attrs) { 42 | this(context, attrs, 0); 43 | } 44 | 45 | public BottomBar(Context context, AttributeSet attrs, int defStyleAttr) { 46 | super(context, attrs, defStyleAttr); 47 | init(context, attrs); 48 | } 49 | 50 | private void init(Context context, AttributeSet attrs) { 51 | setOrientation(VERTICAL); 52 | 53 | // ImageView shadowView = new ImageView(context); 54 | // shadowView.setBackgroundResource(R.drawable.actionbar_shadow_up); 55 | // addView(shadowView, new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); 56 | 57 | mTabLayout = new LinearLayout(context); 58 | mTabLayout.setBackgroundColor(Color.WHITE); 59 | mTabLayout.setOrientation(LinearLayout.HORIZONTAL); 60 | addView(mTabLayout, new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); 61 | 62 | mTabParams = new LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT); 63 | mTabParams.weight = 1; 64 | } 65 | 66 | public BottomBar addItem(final BottomBarTab tab) { 67 | tab.setOnClickListener(new OnClickListener() { 68 | @Override 69 | public void onClick(View v) { 70 | if (mListener == null) return; 71 | 72 | int pos = tab.getTabPosition(); 73 | if (mCurrentPosition == pos) { 74 | mListener.onTabReselected(pos); 75 | } else { 76 | mListener.onTabSelected(pos, mCurrentPosition); 77 | tab.setSelected(true); 78 | mListener.onTabUnselected(mCurrentPosition); 79 | mTabs.get(mCurrentPosition).setSelected(false); 80 | mCurrentPosition = pos; 81 | } 82 | } 83 | }); 84 | tab.setTabPosition(mTabLayout.getChildCount()); 85 | tab.setLayoutParams(mTabParams); 86 | mTabLayout.addView(tab); 87 | mTabs.add(tab); 88 | return this; 89 | } 90 | 91 | public void setOnTabSelectedListener(OnTabSelectedListener onTabSelectedListener) { 92 | mListener = onTabSelectedListener; 93 | } 94 | 95 | public void setCurrentItem(final int position) { 96 | mTabLayout.post(new Runnable() { 97 | @Override 98 | public void run() { 99 | mTabLayout.getChildAt(position).performClick(); 100 | } 101 | }); 102 | } 103 | 104 | public int getCurrentItemPosition() { 105 | return mCurrentPosition; 106 | } 107 | 108 | /** 109 | * 获取 Tab 110 | */ 111 | public BottomBarTab getItem(int index) { 112 | if (mTabs.size() < index) return null; 113 | return mTabs.get(index); 114 | } 115 | 116 | public interface OnTabSelectedListener { 117 | void onTabSelected(int position, int prePosition); 118 | 119 | void onTabUnselected(int position); 120 | 121 | void onTabReselected(int position); 122 | } 123 | 124 | @Override 125 | protected Parcelable onSaveInstanceState() { 126 | Parcelable superState = super.onSaveInstanceState(); 127 | return new SavedState(superState, mCurrentPosition); 128 | } 129 | 130 | @Override 131 | protected void onRestoreInstanceState(Parcelable state) { 132 | SavedState ss = (SavedState) state; 133 | super.onRestoreInstanceState(ss.getSuperState()); 134 | 135 | if (mCurrentPosition != ss.position) { 136 | mTabLayout.getChildAt(mCurrentPosition).setSelected(false); 137 | mTabLayout.getChildAt(ss.position).setSelected(true); 138 | } 139 | mCurrentPosition = ss.position; 140 | } 141 | 142 | static class SavedState extends BaseSavedState { 143 | private int position; 144 | 145 | public SavedState(Parcel source) { 146 | super(source); 147 | position = source.readInt(); 148 | } 149 | 150 | public SavedState(Parcelable superState, int position) { 151 | super(superState); 152 | this.position = position; 153 | } 154 | 155 | @Override 156 | public void writeToParcel(Parcel out, int flags) { 157 | super.writeToParcel(out, flags); 158 | out.writeInt(position); 159 | } 160 | 161 | public static final Creator CREATOR = new Creator() { 162 | public SavedState createFromParcel(Parcel in) { 163 | return new SavedState(in); 164 | } 165 | 166 | public SavedState[] newArray(int size) { 167 | return new SavedState[size]; 168 | } 169 | }; 170 | } 171 | 172 | 173 | public void hide() { 174 | hide(true); 175 | } 176 | 177 | public void show() { 178 | show(true); 179 | } 180 | 181 | public void hide(boolean anim) { 182 | toggle(false, anim, false); 183 | } 184 | 185 | public void show(boolean anim) { 186 | toggle(true, anim, false); 187 | } 188 | 189 | public boolean isVisible() { 190 | return mVisible; 191 | } 192 | 193 | private void toggle(final boolean visible, final boolean animate, boolean force) { 194 | if (mVisible != visible || force) { 195 | mVisible = visible; 196 | int height = getHeight(); 197 | if (height == 0 && !force) { 198 | ViewTreeObserver vto = getViewTreeObserver(); 199 | if (vto.isAlive()) { 200 | // view树完成测量并且分配空间而绘制过程还没有开始的时候播放动画。 201 | vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { 202 | @Override 203 | public boolean onPreDraw() { 204 | ViewTreeObserver currentVto = getViewTreeObserver(); 205 | if (currentVto.isAlive()) { 206 | currentVto.removeOnPreDrawListener(this); 207 | } 208 | toggle(visible, animate, true); 209 | return true; 210 | } 211 | }); 212 | return; 213 | } 214 | } 215 | int translationY = visible ? 0 : height; 216 | if (animate) { 217 | animate().setInterpolator(mInterpolator) 218 | .setDuration(TRANSLATE_DURATION_MILLIS) 219 | .translationY(translationY); 220 | } else { 221 | ViewCompat.setTranslationY(this, translationY); 222 | } 223 | } 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/view/bottombar/BottomBarTab.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.view.bottombar; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Color; 6 | import android.graphics.drawable.Drawable; 7 | import android.support.annotation.DrawableRes; 8 | import android.support.v4.content.ContextCompat; 9 | import android.text.TextUtils; 10 | import android.util.AttributeSet; 11 | import android.util.TypedValue; 12 | import android.view.Gravity; 13 | import android.view.ViewGroup; 14 | import android.widget.FrameLayout; 15 | import android.widget.ImageView; 16 | import android.widget.LinearLayout; 17 | import android.widget.TextView; 18 | 19 | import qyh.androidprojecthelper.R; 20 | 21 | 22 | /** 23 | * Created by YoKeyword on 16/6/3. 24 | */ 25 | public class BottomBarTab extends FrameLayout { 26 | private ImageView mIcon; 27 | private TextView mTvTitle; 28 | private Context mContext; 29 | private int mTabPosition = -1; 30 | 31 | private TextView mTvUnreadCount; 32 | 33 | public BottomBarTab(Context context, @DrawableRes int icon, CharSequence title) { 34 | this(context, null, icon, title); 35 | } 36 | 37 | public BottomBarTab(Context context, AttributeSet attrs, int icon, CharSequence title) { 38 | this(context, attrs, 0, icon, title); 39 | } 40 | 41 | public BottomBarTab(Context context, AttributeSet attrs, int defStyleAttr, int icon, CharSequence title) { 42 | super(context, attrs, defStyleAttr); 43 | init(context, icon, title); 44 | } 45 | 46 | private void init(Context context, int icon, CharSequence title) { 47 | mContext = context; 48 | TypedArray typedArray = context.obtainStyledAttributes(new int[]{R.attr.selectableItemBackgroundBorderless}); 49 | Drawable drawable = typedArray.getDrawable(0); 50 | setBackgroundDrawable(drawable); 51 | typedArray.recycle(); 52 | 53 | LinearLayout lLContainer = new LinearLayout(context); 54 | lLContainer.setOrientation(LinearLayout.VERTICAL); 55 | lLContainer.setGravity(Gravity.CENTER); 56 | LayoutParams paramsContainer = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 57 | paramsContainer.gravity = Gravity.CENTER; 58 | lLContainer.setLayoutParams(paramsContainer); 59 | 60 | mIcon = new ImageView(context); 61 | int size = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 27, getResources().getDisplayMetrics()); 62 | LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(size, size); 63 | mIcon.setImageResource(icon); 64 | mIcon.setLayoutParams(params); 65 | mIcon.setColorFilter(ContextCompat.getColor(context, R.color.tab_unselect)); 66 | lLContainer.addView(mIcon); 67 | 68 | mTvTitle = new TextView(context); 69 | mTvTitle.setText(title); 70 | LinearLayout.LayoutParams paramsTv = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 71 | paramsTv.topMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, getResources().getDisplayMetrics()); 72 | mTvTitle.setTextSize(10); 73 | mTvTitle.setTextColor(ContextCompat.getColor(context, R.color.tab_unselect)); 74 | mTvTitle.setLayoutParams(paramsTv); 75 | lLContainer.addView(mTvTitle); 76 | 77 | addView(lLContainer); 78 | 79 | int min = dip2px(context, 20); 80 | int padding = dip2px(context, 5); 81 | mTvUnreadCount = new TextView(context); 82 | mTvUnreadCount.setBackgroundResource(R.drawable.bg_msg_bubble); 83 | mTvUnreadCount.setMinWidth(min); 84 | mTvUnreadCount.setTextColor(Color.WHITE); 85 | mTvUnreadCount.setPadding(padding, 0, padding, 0); 86 | mTvUnreadCount.setGravity(Gravity.CENTER); 87 | FrameLayout.LayoutParams tvUnReadParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, min); 88 | tvUnReadParams.gravity = Gravity.CENTER; 89 | tvUnReadParams.leftMargin = dip2px(context, 17); 90 | tvUnReadParams.bottomMargin = dip2px(context, 14); 91 | mTvUnreadCount.setLayoutParams(tvUnReadParams); 92 | mTvUnreadCount.setVisibility(GONE); 93 | 94 | addView(mTvUnreadCount); 95 | } 96 | 97 | @Override 98 | public void setSelected(boolean selected) { 99 | super.setSelected(selected); 100 | if (selected) { 101 | mIcon.setColorFilter(ContextCompat.getColor(mContext, R.color.colorPrimary)); 102 | mTvTitle.setTextColor(ContextCompat.getColor(mContext, R.color.colorPrimary)); 103 | } else { 104 | mIcon.setColorFilter(ContextCompat.getColor(mContext, R.color.tab_unselect)); 105 | mTvTitle.setTextColor(ContextCompat.getColor(mContext, R.color.tab_unselect)); 106 | } 107 | } 108 | 109 | public void setTabPosition(int position) { 110 | mTabPosition = position; 111 | if (position == 0) { 112 | setSelected(true); 113 | } 114 | } 115 | 116 | public int getTabPosition() { 117 | return mTabPosition; 118 | } 119 | 120 | /** 121 | * 设置未读数量 122 | */ 123 | public void setUnreadCount(int num) { 124 | if (num <= 0) { 125 | mTvUnreadCount.setText(String.valueOf(0)); 126 | mTvUnreadCount.setVisibility(GONE); 127 | } else { 128 | mTvUnreadCount.setVisibility(VISIBLE); 129 | if (num > 99) { 130 | mTvUnreadCount.setText("99+"); 131 | } else { 132 | mTvUnreadCount.setText(String.valueOf(num)); 133 | } 134 | } 135 | } 136 | 137 | /** 138 | * 获取当前未读数量 139 | */ 140 | public int getUnreadCount() { 141 | int count = 0; 142 | if (TextUtils.isEmpty(mTvUnreadCount.getText())) { 143 | return count; 144 | } 145 | if (mTvUnreadCount.getText().toString().equals("99+")) { 146 | return 99; 147 | } 148 | try { 149 | count = Integer.valueOf(mTvUnreadCount.getText().toString()); 150 | } catch (Exception ignored) { 151 | } 152 | return count; 153 | } 154 | 155 | private int dip2px(Context context, float dp) { 156 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics()); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/view/launcher/LauncherView.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.view.launcher; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorListenerAdapter; 5 | import android.animation.AnimatorSet; 6 | import android.animation.ObjectAnimator; 7 | import android.content.Context; 8 | import android.os.Handler; 9 | import android.util.AttributeSet; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.view.animation.AccelerateDecelerateInterpolator; 13 | import android.widget.ImageView; 14 | import android.widget.RelativeLayout; 15 | 16 | import qyh.androidprojecthelper.R; 17 | import qyh.androidprojecthelper.utils.Utils; 18 | 19 | /** 20 | * 描述:自定义app启动动画 21 | * Created by qyh on 2016/12/10. 22 | */ 23 | public class LauncherView extends RelativeLayout { 24 | private int mHeight; 25 | private int mWidth; 26 | private int dp80 = Utils.dp2px(getContext(), 80); 27 | private boolean mHasStart; 28 | 29 | public LauncherView(Context context) { 30 | super(context); 31 | init(); 32 | } 33 | 34 | public LauncherView(Context context, AttributeSet attrs) { 35 | super(context, attrs); 36 | init(); 37 | } 38 | 39 | public LauncherView(Context context, AttributeSet attrs, int defStyleAttr) { 40 | super(context, attrs, defStyleAttr); 41 | init(); 42 | } 43 | 44 | ImageView red, purple, yellow, blue; 45 | 46 | private void init() { 47 | LayoutParams lp = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 48 | lp.addRule(CENTER_HORIZONTAL, TRUE);//这里的TRUE 要注意 不是true 49 | lp.addRule(CENTER_VERTICAL, TRUE); 50 | lp.setMargins(0, 0, 0, dp80); 51 | 52 | purple = new ImageView(getContext()); 53 | purple.setLayoutParams(lp); 54 | purple.setImageResource(R.drawable.shape_circle_purple); 55 | addView(purple); 56 | 57 | yellow = new ImageView(getContext()); 58 | yellow.setLayoutParams(lp); 59 | yellow.setImageResource(R.drawable.shape_circle_yellow); 60 | addView(yellow); 61 | 62 | blue = new ImageView(getContext()); 63 | blue.setLayoutParams(lp); 64 | blue.setImageResource(R.drawable.shape_circle_blue); 65 | addView(blue); 66 | 67 | red = new ImageView(getContext()); 68 | red.setLayoutParams(lp); 69 | red.setImageResource(R.drawable.shape_circle_red); 70 | addView(red); 71 | } 72 | 73 | @Override 74 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 75 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 76 | mWidth = getMeasuredWidth(); 77 | mHeight = getMeasuredHeight(); 78 | } 79 | 80 | @Override 81 | public void onWindowFocusChanged(boolean hasWindowFocus) { 82 | super.onWindowFocusChanged(hasWindowFocus); 83 | if (hasWindowFocus&&!mHasStart){ 84 | new Handler().postDelayed(new Runnable() { 85 | @Override 86 | public void run() { 87 | start(); 88 | mHasStart = true; 89 | } 90 | },500); 91 | } 92 | } 93 | 94 | public void start() { 95 | ViewPath redPath1 = new ViewPath(); //偏移坐标 96 | redPath1.moveTo(0, 0); 97 | redPath1.lineTo(mWidth / 5 - mWidth / 2, 0); 98 | ViewPath redPath2 = new ViewPath(); 99 | redPath2.moveTo(mWidth / 5 - mWidth / 2, 0); 100 | redPath2.curveTo(-700, -mHeight / 2, mWidth / 3 * 2, -mHeight / 3 * 2, 0, -dp80); 101 | setAnimation(red, redPath1, redPath2); 102 | 103 | 104 | ViewPath purplePath1 = new ViewPath(); //偏移坐标 105 | purplePath1.moveTo(0, 0); 106 | purplePath1.lineTo(mWidth / 5 * 2 - mWidth / 2, 0); 107 | ViewPath purplePath2 = new ViewPath(); //偏移坐标 108 | purplePath2.moveTo(mWidth / 5 * 2 - mWidth / 2, 0); 109 | purplePath2.curveTo(-300, -mHeight / 2, mWidth, -mHeight / 9 * 5, 0, -dp80); 110 | setAnimation(purple, purplePath1, purplePath2); 111 | 112 | 113 | ViewPath yellowPath1 = new ViewPath(); //偏移坐标 114 | yellowPath1.moveTo(0, 0); 115 | yellowPath1.lineTo(mWidth / 5 * 3 - mWidth / 2, 0); 116 | ViewPath yellowPath2 = new ViewPath(); //偏移坐标 117 | yellowPath2.moveTo(mWidth / 5 * 3 - mWidth / 2, 0); 118 | yellowPath2.curveTo(300, mHeight, -mWidth, -mHeight / 9 * 5, 0, -dp80); 119 | setAnimation(yellow, yellowPath1, yellowPath2); 120 | 121 | 122 | ViewPath bluePath1 = new ViewPath(); //偏移坐标 123 | bluePath1.moveTo(0, 0); 124 | bluePath1.lineTo(mWidth / 5 * 4 - mWidth / 2, 0); 125 | ViewPath bluePath2 = new ViewPath(); //偏移坐标 126 | bluePath2.moveTo(mWidth / 5 * 4 - mWidth / 2, 0); 127 | bluePath2.curveTo(700, mHeight / 3 * 2, -mWidth / 2, mHeight / 2, 0, -dp80); 128 | setAnimation(blue, bluePath1, bluePath2); 129 | 130 | new Handler().postDelayed(new Runnable() { 131 | @Override 132 | public void run() { 133 | showLogo(); 134 | } 135 | }, 2400); 136 | } 137 | 138 | private void setAnimation(final ImageView target, ViewPath path1, ViewPath path2) { 139 | //左右平移 140 | ObjectAnimator redAnim1 = ObjectAnimator.ofObject(new ViewObj(target), "fabLoc", new ViewPathEvaluator(), path1.getPoints().toArray()); 141 | redAnim1.setInterpolator(new AccelerateDecelerateInterpolator()); 142 | redAnim1.setDuration(800); 143 | //贝塞尔曲线 144 | ObjectAnimator redAnim2 = ObjectAnimator.ofObject(new ViewObj(target), "fabLoc", new ViewPathEvaluator(), path2.getPoints().toArray()); 145 | redAnim2.setInterpolator(new AccelerateDecelerateInterpolator()); 146 | 147 | //组合动画 148 | addAnimation(redAnim1, redAnim2, target); 149 | } 150 | 151 | private void addAnimation(ObjectAnimator animator1, ObjectAnimator animator2, ImageView target) { 152 | ObjectAnimator alpha = ObjectAnimator.ofFloat(target, View.ALPHA, 1f, 0.5f); 153 | ObjectAnimator scaleX = ObjectAnimator.ofFloat(target, View.SCALE_X, 1, getScale(target), 1.0f); 154 | ObjectAnimator scaleY = ObjectAnimator.ofFloat(target, View.SCALE_Y, 1, getScale(target), 1.0f); 155 | 156 | AnimatorSet all2 = new AnimatorSet(); 157 | all2.setDuration(1800); 158 | all2.playTogether(alpha, scaleX, scaleY, animator2); 159 | all2.addListener(new AnimEndListener(target)); 160 | 161 | AnimatorSet all = new AnimatorSet(); 162 | all.playSequentially(animator1, all2); 163 | all.start(); 164 | } 165 | 166 | private float getScale(ImageView target) { 167 | if (target == red) 168 | return 3.0f; 169 | if (target == purple) 170 | return 2.0f; 171 | if (target == yellow) 172 | return 4.5f; 173 | if (target == blue) 174 | return 3.5f; 175 | return 2f; 176 | 177 | } 178 | 179 | 180 | private void showLogo() { 181 | View view = View.inflate(getContext(), R.layout.widget_load_view, this); 182 | View logo = view.findViewById(R.id.iv_logo); 183 | final View slogo = view.findViewById(R.id.iv_slogo); 184 | ObjectAnimator alpha = ObjectAnimator.ofFloat(logo, View.ALPHA, 0f, 1f); 185 | alpha.setDuration(800); 186 | 187 | alpha.start(); 188 | new Handler().postDelayed(new Runnable() { 189 | @Override 190 | public void run() { 191 | ObjectAnimator alpha = ObjectAnimator.ofFloat(slogo, View.ALPHA, 0f, 1f); 192 | alpha.setDuration(200); 193 | alpha.start(); 194 | } 195 | },400); 196 | 197 | } 198 | 199 | private class AnimEndListener extends AnimatorListenerAdapter { 200 | private View target; 201 | 202 | public AnimEndListener(View target) { 203 | this.target = target; 204 | } 205 | 206 | @Override 207 | public void onAnimationEnd(Animator animation) { 208 | super.onAnimationEnd(animation); 209 | removeView((target)); 210 | } 211 | } 212 | 213 | 214 | public class ViewObj { 215 | private final ImageView red; 216 | 217 | public ViewObj(ImageView red){ 218 | this.red = red; 219 | } 220 | 221 | public void setFabLoc(ViewPoint newLoc){ 222 | red.setTranslationX(newLoc.x); 223 | red.setTranslationY(newLoc.y); 224 | } 225 | } 226 | 227 | 228 | } 229 | 230 | 231 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/view/launcher/ViewPath.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.view.launcher; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | 6 | public class ViewPath { 7 | public static final int MOVE = 0; 8 | public static final int LINE = 1; 9 | public static final int QUAD = 2; 10 | public static final int CURVE = 3; 11 | 12 | private ArrayList mPoints; 13 | 14 | 15 | public ViewPath() { 16 | mPoints = new ArrayList<>(); 17 | } 18 | 19 | public void moveTo(float x, float y){ 20 | mPoints.add(ViewPoint.moveTo(x,y,MOVE)); 21 | } 22 | 23 | public void lineTo(float x,float y){ 24 | mPoints.add(ViewPoint.lineTo(x,y,LINE)); 25 | } 26 | 27 | public void curveTo(float x,float y,float x1,float y1,float x2,float y2){ 28 | mPoints.add(ViewPoint.curveTo(x,y,x1,y1,x2,y2,CURVE)); 29 | } 30 | 31 | public void quadTo(float x,float y,float x1,float y1){ 32 | mPoints.add(ViewPoint.quadTo(x,y,x1,y1,QUAD)); 33 | } 34 | 35 | public Collection getPoints(){ 36 | return mPoints; 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/view/launcher/ViewPathEvaluator.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.view.launcher; 2 | 3 | import android.animation.TypeEvaluator; 4 | 5 | 6 | public class ViewPathEvaluator implements TypeEvaluator { 7 | 8 | 9 | public ViewPathEvaluator() { 10 | } 11 | 12 | @Override 13 | public ViewPoint evaluate(float t, ViewPoint startValue, ViewPoint endValue) { 14 | 15 | float x ,y; 16 | 17 | float startX,startY; 18 | 19 | if(endValue.operation == ViewPath.LINE){ 20 | 21 | startX = (startValue.operation== ViewPath.QUAD)?startValue.x1:startValue.x; 22 | 23 | startX = (startValue.operation == ViewPath.CURVE)?startValue.x2:startX; 24 | 25 | startY = (startValue.operation== ViewPath.QUAD)?startValue.y1:startValue.y; 26 | 27 | startY = (startValue.operation == ViewPath.CURVE)?startValue.y2:startY; 28 | 29 | x = startX + t * (endValue.x - startX); 30 | y = startY+ t * (endValue.y - startY); 31 | 32 | 33 | 34 | }else if(endValue.operation == ViewPath.CURVE){ 35 | 36 | 37 | startX = (startValue.operation== ViewPath.QUAD)?startValue.x1:startValue.x; 38 | startY = (startValue.operation== ViewPath.QUAD)?startValue.y1:startValue.y; 39 | 40 | float oneMinusT = 1 - t; 41 | 42 | 43 | x = oneMinusT * oneMinusT * oneMinusT * startX + 44 | 3 * oneMinusT * oneMinusT * t * endValue.x + 45 | 3 * oneMinusT * t * t * endValue.x1+ 46 | t * t * t * endValue.x2; 47 | 48 | y = oneMinusT * oneMinusT * oneMinusT * startY + 49 | 3 * oneMinusT * oneMinusT * t * endValue.y + 50 | 3 * oneMinusT * t * t * endValue.y1+ 51 | t * t * t * endValue.y2; 52 | 53 | 54 | }else if(endValue.operation == ViewPath.MOVE){ 55 | 56 | x = endValue.x; 57 | y = endValue.y; 58 | 59 | 60 | }else if(endValue.operation == ViewPath.QUAD){ 61 | 62 | 63 | startX = (startValue.operation== ViewPath.CURVE)?startValue.x2:startValue.x; 64 | startY = (startValue.operation== ViewPath.CURVE)?startValue.y2:startValue.y; 65 | 66 | float oneMinusT = 1 - t; 67 | x = oneMinusT * oneMinusT * startX + 68 | 2 * oneMinusT * t * endValue.x + 69 | t * t * endValue.x1; 70 | 71 | y = oneMinusT * oneMinusT * startY + 72 | 2 * oneMinusT * t * endValue.y + 73 | t * t * endValue.y1; 74 | 75 | 76 | }else { 77 | x = endValue.x; 78 | y = endValue.y; 79 | } 80 | 81 | 82 | return new ViewPoint(x,y); 83 | } 84 | } 85 | 86 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/view/launcher/ViewPoint.java: -------------------------------------------------------------------------------- 1 | package qyh.androidprojecthelper.view.launcher; 2 | 3 | 4 | public class ViewPoint { 5 | float x ,y; 6 | 7 | float x1,y1; 8 | 9 | float x2,y2; 10 | 11 | int operation; 12 | 13 | public ViewPoint(float x, float y) { 14 | this.x = x; 15 | this.y = y; 16 | } 17 | 18 | public static ViewPoint moveTo(float x, float y, int operation){ 19 | return new ViewPoint(x,y,operation); 20 | } 21 | 22 | public static ViewPoint lineTo(float x, float y, int operation){ 23 | return new ViewPoint(x,y,operation); 24 | } 25 | public static ViewPoint curveTo(float x, float y, float x1, float y1, float x2, float y2, int operation){ 26 | return new ViewPoint(x,y,x1,y1,x2,y2,operation); 27 | } 28 | 29 | public static ViewPoint quadTo(float x, float y, float x1, float y1, int operation){ 30 | return new ViewPoint(x,y,x1,y1,operation); 31 | } 32 | 33 | 34 | 35 | private ViewPoint(float x, float y, int operation) { 36 | this.x = x; 37 | this.y = y; 38 | this.operation = operation; 39 | } 40 | 41 | public ViewPoint(float x, float y, float x1, float y1, int operation) { 42 | this.x = x; 43 | this.y = y; 44 | this.x1 = x1; 45 | this.y1 = y1; 46 | this.operation = operation; 47 | } 48 | 49 | public ViewPoint(float x, float y, float x1, float y1, float x2, float y2, int operation) { 50 | this.x = x; 51 | this.y = y; 52 | this.x1 = x1; 53 | this.y1 = y1; 54 | this.x2 = x2; 55 | this.y2 = y2; 56 | this.operation = operation; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/view/refresh/NormalRefreshViewHolder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 bingoogolapple 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package qyh.androidprojecthelper.view.refresh; 18 | 19 | import android.content.Context; 20 | import android.graphics.Color; 21 | import android.graphics.drawable.AnimationDrawable; 22 | import android.view.View; 23 | import android.view.animation.Animation; 24 | import android.view.animation.RotateAnimation; 25 | import android.widget.ImageView; 26 | import android.widget.TextView; 27 | 28 | import qyh.androidprojecthelper.R; 29 | 30 | 31 | /** 32 | * 描述:类似新浪微博下拉刷新风格 33 | * @author qyh 34 | */ 35 | public class NormalRefreshViewHolder extends RefreshViewHolder { 36 | private TextView mHeaderStatusTv; 37 | private ImageView mHeaderArrowIv; 38 | private ImageView mHeaderChrysanthemumIv; 39 | private AnimationDrawable mHeaderChrysanthemumAd; 40 | private RotateAnimation mUpAnim; 41 | private RotateAnimation mDownAnim; 42 | 43 | private String mPullDownRefreshText = "下拉刷新"; 44 | private String mReleaseRefreshText = "释放更新"; 45 | private String mRefreshingText = "加载中..."; 46 | 47 | /** 48 | * @param context 49 | * @param isLoadingMoreEnabled 上拉加载更多是否可用 50 | */ 51 | public NormalRefreshViewHolder(Context context, boolean isLoadingMoreEnabled) { 52 | super(context, isLoadingMoreEnabled); 53 | initAnimation(); 54 | } 55 | 56 | private void initAnimation() { 57 | mUpAnim = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); 58 | mUpAnim.setDuration(150); 59 | mUpAnim.setFillAfter(true); 60 | 61 | mDownAnim = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); 62 | mDownAnim.setFillAfter(true); 63 | } 64 | 65 | /** 66 | * 设置未满足刷新条件,提示继续往下拉的文本 67 | * 68 | * @param pullDownRefreshText 69 | */ 70 | public void setPullDownRefreshText(String pullDownRefreshText) { 71 | mPullDownRefreshText = pullDownRefreshText; 72 | } 73 | 74 | /** 75 | * 设置满足刷新条件时的文本 76 | * 77 | * @param releaseRefreshText 78 | */ 79 | public void setReleaseRefreshText(String releaseRefreshText) { 80 | mReleaseRefreshText = releaseRefreshText; 81 | } 82 | 83 | /** 84 | * 设置正在刷新时的文本 85 | * 86 | * @param refreshingText 87 | */ 88 | public void setRefreshingText(String refreshingText) { 89 | mRefreshingText = refreshingText; 90 | } 91 | 92 | @Override 93 | public View getRefreshHeaderView() { 94 | if (mRefreshHeaderView == null) { 95 | mRefreshHeaderView = View.inflate(mContext, R.layout.view_refresh_header_normal, null); 96 | mRefreshHeaderView.setBackgroundColor(Color.TRANSPARENT); 97 | if (mRefreshViewBackgroundColorRes != -1) { 98 | mRefreshHeaderView.setBackgroundResource(mRefreshViewBackgroundColorRes); 99 | } 100 | if (mRefreshViewBackgroundDrawableRes != -1) { 101 | mRefreshHeaderView.setBackgroundResource(mRefreshViewBackgroundDrawableRes); 102 | } 103 | mHeaderStatusTv = (TextView) mRefreshHeaderView.findViewById(R.id.tv_normal_refresh_header_status); 104 | mHeaderArrowIv = (ImageView) mRefreshHeaderView.findViewById(R.id.iv_normal_refresh_header_arrow); 105 | mHeaderChrysanthemumIv = (ImageView) mRefreshHeaderView.findViewById(R.id.iv_normal_refresh_header_chrysanthemum); 106 | mHeaderChrysanthemumAd = (AnimationDrawable) mHeaderChrysanthemumIv.getDrawable(); 107 | mHeaderStatusTv.setText(mPullDownRefreshText); 108 | } 109 | return mRefreshHeaderView; 110 | } 111 | 112 | @Override 113 | public void handleScale(float scale, int moveYDistance) { 114 | } 115 | 116 | @Override 117 | public void changeToIdle() { 118 | } 119 | 120 | @Override 121 | public void changeToPullDown() { 122 | mHeaderStatusTv.setText(mPullDownRefreshText); 123 | mHeaderChrysanthemumIv.setVisibility(View.INVISIBLE); 124 | mHeaderChrysanthemumAd.stop(); 125 | mHeaderArrowIv.setVisibility(View.VISIBLE); 126 | mDownAnim.setDuration(150); 127 | mHeaderArrowIv.startAnimation(mDownAnim); 128 | } 129 | 130 | @Override 131 | public void changeToReleaseRefresh() { 132 | mHeaderStatusTv.setText(mReleaseRefreshText); 133 | mHeaderChrysanthemumIv.setVisibility(View.INVISIBLE); 134 | mHeaderChrysanthemumAd.stop(); 135 | mHeaderArrowIv.setVisibility(View.VISIBLE); 136 | mHeaderArrowIv.startAnimation(mUpAnim); 137 | } 138 | 139 | @Override 140 | public void changeToRefreshing() { 141 | mHeaderStatusTv.setText(mRefreshingText); 142 | // 必须把动画清空才能隐藏成功 143 | mHeaderArrowIv.clearAnimation(); 144 | mHeaderArrowIv.setVisibility(View.INVISIBLE); 145 | mHeaderChrysanthemumIv.setVisibility(View.VISIBLE); 146 | mHeaderChrysanthemumAd.start(); 147 | } 148 | 149 | @Override 150 | public void onEndRefreshing() { 151 | mHeaderStatusTv.setText(mPullDownRefreshText); 152 | mHeaderChrysanthemumIv.setVisibility(View.INVISIBLE); 153 | mHeaderChrysanthemumAd.stop(); 154 | mHeaderArrowIv.setVisibility(View.VISIBLE); 155 | mDownAnim.setDuration(0); 156 | mHeaderArrowIv.startAnimation(mDownAnim); 157 | } 158 | 159 | } -------------------------------------------------------------------------------- /app/src/main/java/qyh/androidprojecthelper/view/refresh/RefreshViewHolder.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package qyh.androidprojecthelper.view.refresh; 4 | 5 | import android.content.Context; 6 | import android.graphics.Color; 7 | import android.graphics.drawable.AnimationDrawable; 8 | import android.support.annotation.ColorRes; 9 | import android.support.annotation.DrawableRes; 10 | import android.view.View; 11 | import android.widget.ImageView; 12 | import android.widget.TextView; 13 | 14 | import qyh.androidprojecthelper.R; 15 | 16 | 17 | /** 18 | * 描述:继承该抽象类实现响应的抽象方法,做出各种下拉刷新效果。 19 | * 参考NormalRefreshViewHolder 20 | * @author qyh 21 | */ 22 | public abstract class RefreshViewHolder { 23 | /** 24 | * 手指移动距离与下拉刷新控件paddingTop移动距离的比值 25 | */ 26 | private static final float PULL_DISTANCE_SCALE = 1.8f; 27 | /** 28 | * 手指移动距离与下拉刷新控件paddingTop移动距离的比值,默认1.8f 29 | */ 30 | private float mPullDistanceScale = PULL_DISTANCE_SCALE; 31 | /** 32 | * 下拉刷新控件paddingTop的弹簧距离与下拉刷新控件高度的比值 33 | */ 34 | private static final float SPRING_DISTANCE_SCALE = 0.4f; 35 | /** 36 | * 下拉刷新控件paddingTop的弹簧距离与下拉刷新控件高度的比值,默认0.4f 37 | */ 38 | private float mSpringDistanceScale = SPRING_DISTANCE_SCALE; 39 | 40 | protected Context mContext; 41 | /** 42 | * 下拉刷新上拉加载更多控件 43 | */ 44 | protected RefreshLayout mRefreshLayout; 45 | /** 46 | * 下拉刷新控件 47 | */ 48 | protected View mRefreshHeaderView; 49 | /** 50 | * 上拉加载更多控件 51 | */ 52 | protected View mLoadMoreFooterView; 53 | /** 54 | * 底部加载更多提示控件 55 | */ 56 | protected TextView mFooterStatusTv; 57 | /** 58 | * 底部加载更多菊花控件 59 | */ 60 | protected ImageView mFooterChrysanthemumIv; 61 | /** 62 | * 底部加载更多菊花drawable 63 | */ 64 | protected AnimationDrawable mFooterChrysanthemumAd; 65 | /** 66 | * 正在加载更多时的文本 67 | */ 68 | protected String mLodingMoreText = "加载中..."; 69 | /** 70 | * 是否开启加载更多功能 71 | */ 72 | private boolean mIsLoadingMoreEnabled = true; 73 | /** 74 | * 整个加载更多控件的背景颜色资源id 75 | */ 76 | private int mLoadMoreBackgroundColorRes = -1; 77 | /** 78 | * 整个加载更多控件的背景drawable资源id 79 | */ 80 | private int mLoadMoreBackgroundDrawableRes = -1; 81 | /** 82 | * 下拉刷新控件的背景颜色资源id 83 | */ 84 | protected int mRefreshViewBackgroundColorRes = -1; 85 | /** 86 | * 下拉刷新控件的背景drawable资源id 87 | */ 88 | protected int mRefreshViewBackgroundDrawableRes = -1; 89 | /** 90 | * 头部控件移动动画时常 91 | */ 92 | private int mTopAnimDuration = 500; 93 | 94 | /** 95 | * @param context 96 | * @param isLoadingMoreEnabled 上拉加载更多是否可用 97 | */ 98 | public RefreshViewHolder(Context context, boolean isLoadingMoreEnabled) { 99 | mContext = context; 100 | mIsLoadingMoreEnabled = isLoadingMoreEnabled; 101 | } 102 | 103 | /** 104 | * 设置正在加载更多时的文本 105 | * 106 | * @param loadingMoreText 107 | */ 108 | public void setLoadingMoreText(String loadingMoreText) { 109 | mLodingMoreText = loadingMoreText; 110 | } 111 | 112 | /** 113 | * 设置整个加载更多控件的背景颜色资源id 114 | * 115 | * @param loadMoreBackgroundColorRes 116 | */ 117 | public void setLoadMoreBackgroundColorRes(@ColorRes int loadMoreBackgroundColorRes) { 118 | mLoadMoreBackgroundColorRes = loadMoreBackgroundColorRes; 119 | } 120 | 121 | /** 122 | * 设置整个加载更多控件的背景drawable资源id 123 | * 124 | * @param loadMoreBackgroundDrawableRes 125 | */ 126 | public void setLoadMoreBackgroundDrawableRes(@DrawableRes int loadMoreBackgroundDrawableRes) { 127 | mLoadMoreBackgroundDrawableRes = loadMoreBackgroundDrawableRes; 128 | } 129 | 130 | /** 131 | * 设置下拉刷新控件的背景颜色资源id 132 | * 133 | * @param refreshViewBackgroundColorRes 134 | */ 135 | public void setRefreshViewBackgroundColorRes(@ColorRes int refreshViewBackgroundColorRes) { 136 | mRefreshViewBackgroundColorRes = refreshViewBackgroundColorRes; 137 | } 138 | 139 | /** 140 | * 设置下拉刷新控件的背景drawable资源id 141 | * 142 | * @param refreshViewBackgroundDrawableRes 143 | */ 144 | public void setRefreshViewBackgroundDrawableRes(@DrawableRes int refreshViewBackgroundDrawableRes) { 145 | mRefreshViewBackgroundDrawableRes = refreshViewBackgroundDrawableRes; 146 | } 147 | 148 | /** 149 | * 获取顶部未满足下拉刷新条件时回弹到初始状态、满足刷新条件时回弹到正在刷新状态、刷新完毕后回弹到初始状态的动画时间,默认为500毫秒 150 | * 151 | * @return 152 | */ 153 | public int getTopAnimDuration() { 154 | return mTopAnimDuration; 155 | } 156 | 157 | /** 158 | * 设置顶部未满足下拉刷新条件时回弹到初始状态、满足刷新条件时回弹到正在刷新状态、刷新完毕后回弹到初始状态的动画时间,默认为300毫秒 159 | * 160 | * @param topAnimDuration 161 | */ 162 | public void setTopAnimDuration(int topAnimDuration) { 163 | mTopAnimDuration = topAnimDuration; 164 | } 165 | 166 | /** 167 | * 获取上拉加载更多控件,如果不喜欢这种上拉刷新风格可重写该方法实现自定义LoadMoreFooterView 168 | * 169 | * @return 170 | */ 171 | public View getLoadMoreFooterView() { 172 | if (!mIsLoadingMoreEnabled) { 173 | return null; 174 | } 175 | if (mLoadMoreFooterView == null) { 176 | mLoadMoreFooterView = View.inflate(mContext, R.layout.view_normal_refresh_footer, null); 177 | mLoadMoreFooterView.setBackgroundColor(Color.TRANSPARENT); 178 | if (mLoadMoreBackgroundColorRes != -1) { 179 | mLoadMoreFooterView.setBackgroundResource(mLoadMoreBackgroundColorRes); 180 | } 181 | if (mLoadMoreBackgroundDrawableRes != -1) { 182 | mLoadMoreFooterView.setBackgroundResource(mLoadMoreBackgroundDrawableRes); 183 | } 184 | mFooterStatusTv = (TextView) mLoadMoreFooterView.findViewById(R.id.tv_normal_refresh_footer_status); 185 | mFooterChrysanthemumIv = (ImageView) mLoadMoreFooterView.findViewById(R.id.iv_normal_refresh_footer_chrysanthemum); 186 | mFooterChrysanthemumAd = (AnimationDrawable) mFooterChrysanthemumIv.getDrawable(); 187 | mFooterStatusTv.setText(mLodingMoreText); 188 | } 189 | return mLoadMoreFooterView; 190 | } 191 | 192 | /** 193 | * 获取头部下拉刷新控件 194 | * 195 | * @return 196 | */ 197 | public abstract View getRefreshHeaderView(); 198 | 199 | /** 200 | * 下拉刷新控件可见时,处理上下拉进度 201 | * 202 | * @param scale 下拉过程0 到 1,回弹过程1 到 0,没有加上弹簧距离移动时的比例 203 | * @param moveYDistance 整个下拉刷新控件paddingTop变化的值,如果有弹簧距离,会大于整个下拉刷新控件的高度 204 | */ 205 | public abstract void handleScale(float scale, int moveYDistance); 206 | 207 | /** 208 | * 进入到未处理下拉刷新状态 209 | */ 210 | public abstract void changeToIdle(); 211 | 212 | /** 213 | * 进入下拉状态 214 | */ 215 | public abstract void changeToPullDown(); 216 | 217 | /** 218 | * 进入释放刷新状态 219 | */ 220 | public abstract void changeToReleaseRefresh(); 221 | 222 | /** 223 | * 进入正在刷新状态 224 | */ 225 | public abstract void changeToRefreshing(); 226 | 227 | /** 228 | * 结束下拉刷新 229 | */ 230 | public abstract void onEndRefreshing(); 231 | 232 | /** 233 | * 手指移动距离与下拉刷新控件paddingTop移动距离的比值 234 | * 235 | * @return 236 | */ 237 | public float getPaddingTopScale() { 238 | return mPullDistanceScale; 239 | } 240 | 241 | /** 242 | * 设置手指移动距离与下拉刷新控件paddingTop移动距离的比值 243 | * 244 | * @param pullDistanceScale 245 | */ 246 | public void setPullDistanceScale(float pullDistanceScale) { 247 | mPullDistanceScale = pullDistanceScale; 248 | } 249 | 250 | /** 251 | * 下拉刷新控件paddingTop的弹簧距离与下拉刷新控件高度的比值 252 | * 253 | * @return 254 | */ 255 | public float getSpringDistanceScale() { 256 | return mSpringDistanceScale; 257 | } 258 | 259 | /** 260 | * 设置下拉刷新控件paddingTop的弹簧距离与下拉刷新控件高度的比值,不能小于0,如果刷新控件比较高,建议将该值设置小一些 261 | * 262 | * @param springDistanceScale 263 | */ 264 | public void setSpringDistanceScale(float springDistanceScale) { 265 | if (springDistanceScale < 0) { 266 | throw new RuntimeException("下拉刷新控件paddingTop的弹簧距离与下拉刷新控件高度的比值springDistanceScale不能小于0"); 267 | } 268 | mSpringDistanceScale = springDistanceScale; 269 | } 270 | 271 | /** 272 | * 是处于能够进入刷新状态 273 | * 274 | * @return 275 | */ 276 | public boolean canChangeToRefreshingStatus() { 277 | return false; 278 | } 279 | 280 | /** 281 | * 进入加载更多状态 282 | */ 283 | public void changeToLoadingMore() { 284 | if (mIsLoadingMoreEnabled && mFooterChrysanthemumAd != null) { 285 | mFooterChrysanthemumAd.start(); 286 | } 287 | } 288 | 289 | /** 290 | * 结束上拉加载更多 291 | */ 292 | public void onEndLoadingMore() { 293 | if (mIsLoadingMoreEnabled && mFooterChrysanthemumAd != null) { 294 | mFooterChrysanthemumAd.stop(); 295 | } 296 | } 297 | 298 | /** 299 | * 获取下拉刷新控件的高度,如果初始化时的高度和最后展开的最大高度不一致,需重写该方法返回最大高度 300 | * 301 | * @return 302 | */ 303 | public int getRefreshHeaderViewHeight() { 304 | if (mRefreshHeaderView != null) { 305 | // 测量下拉刷新控件的高度 306 | mRefreshHeaderView.measure(0, 0); 307 | return mRefreshHeaderView.getMeasuredHeight(); 308 | } 309 | return 0; 310 | } 311 | 312 | /** 313 | * 改变整个下拉刷新头部控件移动一定的距离(带动画),自定义刷新控件进入刷新状态前后的高度有变化时可以使用该方法(参考BGAStickinessRefreshView) 314 | * 315 | * @param distance 316 | */ 317 | public void startChangeWholeHeaderViewPaddingTop(int distance) { 318 | mRefreshLayout.startChangeWholeHeaderViewPaddingTop(distance); 319 | } 320 | 321 | /** 322 | * 设置下拉刷新上拉加载更多控件,该方法是设置BGARefreshViewHolder给BGARefreshLayout时由BGARefreshLayout调用 323 | * 324 | * @param refreshLayout 325 | */ 326 | public void setRefreshLayout(RefreshLayout refreshLayout) { 327 | mRefreshLayout = refreshLayout; 328 | } 329 | 330 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_msg_bubble.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 11 | 14 | 17 | 20 | 23 | 26 | 29 | 32 | 35 | 38 | 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/loading_dialog_progressbar.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_circle_blue.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_circle_purple.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_circle_red.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_circle_yellow.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_loading_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_luncher.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 11 | 12 |