├── .gitignore ├── Android-Sloth.iml ├── README.md ├── app ├── app.iml ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── xyz │ │ └── ibat │ │ └── sloth │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── xyz │ │ └── ibat │ │ └── sloth │ │ ├── SlothApplication.java │ │ ├── base │ │ ├── BaseActivity.java │ │ ├── BaseFragment.java │ │ ├── FragmentFactory.java │ │ ├── TabsFragment.java │ │ ├── adapter │ │ │ └── NewLoadMoreWrapper.java │ │ └── webview │ │ │ ├── WebActivity.java │ │ │ └── WebFragment.java │ │ ├── domain │ │ ├── info │ │ │ └── InfoFragment.java │ │ ├── main │ │ │ ├── activities │ │ │ │ ├── FriendActivity.java │ │ │ │ ├── ImagePreviewActivity.java │ │ │ │ ├── MainActivity.java │ │ │ │ ├── MeiziActivity.java │ │ │ │ └── MessageActivity.java │ │ │ ├── adapter │ │ │ │ ├── HomeAdapter.java │ │ │ │ ├── HomeHolder.java │ │ │ │ ├── MeiziAdapter.java │ │ │ │ └── MeiziHolder.java │ │ │ ├── fragments │ │ │ │ ├── DataFragment.java │ │ │ │ └── MainFragment.java │ │ │ └── model │ │ │ │ └── DataModel.java │ │ ├── map │ │ │ └── MeiziFragment.java │ │ └── mine │ │ │ └── MineFragment.java │ │ ├── network │ │ ├── ImageLoader.java │ │ ├── RetrofitFactory.java │ │ └── api │ │ │ └── ApiService.java │ │ ├── utils │ │ ├── DensityUtil.java │ │ ├── SlothUtil.java │ │ └── T.java │ │ └── view │ │ ├── AppBarStateChangeListener.java │ │ ├── RefreshLayout.java │ │ ├── SlothRecycler.java │ │ ├── behavior │ │ ├── BottomScrollBehavior.java │ │ ├── FABScrollBehavior.java │ │ ├── FollowBehavior.java │ │ └── ScrollBehavior.java │ │ ├── picasso │ │ └── CircleTransform.java │ │ └── widget │ │ ├── CircleImageView.java │ │ └── ZoomImageView.java │ └── res │ ├── drawable │ ├── info_tab_selector.xml │ ├── loadfail_btn_bg_selector.xml │ ├── main_tab_selector.xml │ ├── map_tab_selector.xml │ ├── mine_tab_selector.xml │ ├── progress_animation.xml │ ├── progressbar.xml │ ├── tab_text_selector.xml │ └── webview_progress_bar_states.xml │ ├── layout │ ├── activity_base.xml │ ├── activity_friend.xml │ ├── activity_image_preview.xml │ ├── activity_main.xml │ ├── activity_meizi.xml │ ├── activity_message.xml │ ├── activity_web.xml │ ├── common_toolbar.xml │ ├── default_loading.xml │ ├── fragment_base.xml │ ├── fragment_one.xml │ ├── fragment_tab.xml │ ├── fragment_tab_info.xml │ ├── fragment_tab_main.xml │ ├── fragment_tab_map.xml │ ├── fragment_tab_mine.xml │ ├── fragment_web.xml │ ├── item_fragment_home.xml │ ├── item_meizi.xml │ ├── item_refresh_foot.xml │ └── navigationview_header.xml │ ├── menu │ ├── menu_drawer.xml │ └── menu_main.xml │ ├── mipmap-hdpi │ ├── banner2.jpg │ ├── ic_dashboard.png │ ├── ic_discuss.png │ ├── ic_done.png │ ├── ic_event.png │ ├── ic_forum.png │ ├── ic_headset.png │ ├── ic_launcher.png │ ├── ic_menu.png │ └── ic_toolbar_drawer.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ ├── ic_toolbar_drawer.png │ ├── icon_arrow_back.png │ ├── icon_head.jpg │ ├── icon_info_default.png │ ├── icon_info_pressed.png │ ├── icon_load_failed.png │ ├── icon_main_default.png │ ├── icon_main_pressed.png │ ├── icon_map_default.png │ ├── icon_map_pressed.png │ ├── icon_mine_default.png │ ├── icon_mine_pressed.png │ ├── icon_search.png │ ├── icon_search_white.png │ └── icon_share.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_toolbar_drawer.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── transition │ ├── explode.xml │ ├── fade.xml │ └── slide.xml │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── attrs.xml │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── baseadapter-recyclerview ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── zhy │ │ └── baseadapter_recyclerview │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── zhy │ │ └── adapter │ │ └── recyclerview │ │ ├── CommonAdapter.java │ │ ├── MultiItemTypeAdapter.java │ │ ├── base │ │ ├── ItemViewDelegate.java │ │ ├── ItemViewDelegateManager.java │ │ └── ViewHolder.java │ │ ├── utils │ │ └── WrapperUtils.java │ │ └── wrapper │ │ ├── EmptyWrapper.java │ │ ├── HeaderAndFooterWrapper.java │ │ └── LoadMoreWrapper.java │ └── test │ └── java │ └── com │ └── zhy │ └── baseadapter_recyclerview │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── image ├── sloth_drawerlayout.png ├── sloth_home.png ├── sloth_image_preview.png ├── sloth_me.png └── sloth_meizi.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | /.gradle 2 | /.idea 3 | /local.properties 4 | /build 5 | # OSX 6 | /gradlew 7 | *.DS_Store 8 | 9 | /gradlew.bat 10 | 11 | /Android-Sloth.iml 12 | 13 | /app/app.iml 14 | 15 | # Gradle files 16 | build/ 17 | .gradle/ 18 | */build/ 19 | 20 | # IDEA 21 | *.iml 22 | .idea/* 23 | .idea/.name 24 | .idea/encodings.xml 25 | .idea/misc.xml 26 | .idea/modules.xml 27 | .idea/vcs.xml 28 | .idea/workspace.xml 29 | 30 | 31 | 32 | 33 | # Built application files 34 | 35 | *.ap_ 36 | 37 | 38 | # Files for the Dalvik VM 39 | *.dex 40 | 41 | 42 | # Java class files 43 | *.class 44 | 45 | 46 | # Generated files 47 | antLauncher/bin 48 | antLauncher/gen 49 | 50 | 51 | # Local configuration file (sdk path, etc) 52 | local.properties 53 | 54 | 55 | # Log Files 56 | *.log 57 | gradle/* 58 | app/src/main/gen/ 59 | -------------------------------------------------------------------------------- /Android-Sloth.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Sloth 2 | ### 项目介绍: 3 | 4 | 这是一个用于Android学习的项目,使用了代码家的http://gank.io中的接口, 5 | 里面内容包括,Rxjava,Retroft,,Picasso,WebView预览图片,图片预览放大、 6 | 缩小、移动,Material Design控件使用和activity切换动画等. 7 | 目前代码结构还不是很好,以后会慢慢重构.有新的技术也会不断往项目里面添加. 8 | 希望能通过这个项目技术有一定得提升.当然你也可以安装到手机上,空闲时间看看技术文章和妹纸. 9 | 10 | ### 效果: 11 | ![首页](image/sloth_home.png) 12 | ![drawerlayout](image/sloth_drawerlayout.png) 13 | ![妹子](image/sloth_meizi.png) 14 | ![图片预览](image/sloth_image_preview.png) 15 | ![关于](image/sloth_me.png) 16 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "22.0.0" 6 | 7 | defaultConfig { 8 | applicationId "xyz.ibat.sloth" 9 | minSdkVersion 14 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | 21 | } 22 | 23 | dependencies { 24 | compile fileTree(include: ['*.jar'], dir: 'libs') 25 | compile 'com.android.support:support-v4:23.1.1' 26 | compile 'com.android.support:appcompat-v7:23.1.1' 27 | compile 'com.android.support:design:23.1.1' 28 | compile 'com.jakewharton:butterknife:7.0.1' 29 | compile 'com.android.support:cardview-v7:23.2.0' 30 | compile 'io.reactivex:rxjava:1.2.5' 31 | compile 'io.reactivex:rxandroid:1.2.1' 32 | compile 'com.squareup.retrofit2:retrofit:2.1.0' 33 | compile 'com.squareup.retrofit2:converter-gson:2.1.0' 34 | compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0' 35 | compile 'com.squareup.picasso:picasso:2.5.2' 36 | compile project(':baseadapter-recyclerview') 37 | } 38 | -------------------------------------------------------------------------------- /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 E:\Android\Android-Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/xyz/ibat/sloth/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth; 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 | 9 | 15 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 28 | 32 | 35 | 38 | 42 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/SlothApplication.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | 6 | /** 7 | * Created by DongJr on 2016/4/1. 8 | */ 9 | public class SlothApplication extends Application { 10 | 11 | private static Context mContext; 12 | 13 | @Override 14 | public void onCreate() { 15 | super.onCreate(); 16 | 17 | mContext = getApplicationContext(); 18 | 19 | } 20 | 21 | public static Context getContext() { 22 | return mContext; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/base/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.base; 2 | 3 | import android.os.Build; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.view.WindowManager; 7 | 8 | import xyz.ibat.sloth.R; 9 | 10 | /** 11 | * Created by DongJr on 2016/03/31 12 | */ 13 | public class BaseActivity extends AppCompatActivity { 14 | 15 | 16 | @Override 17 | protected void onCreate(Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | setContentView(R.layout.activity_base); 20 | 21 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 22 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 23 | } 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/base/BaseFragment.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.base; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.Fragment; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import xyz.ibat.sloth.R; 10 | 11 | public class BaseFragment extends Fragment { 12 | 13 | @Override 14 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 15 | Bundle savedInstanceState) { 16 | return inflater.inflate(R.layout.fragment_base, container, false); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/base/FragmentFactory.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.base; 2 | 3 | import android.os.Bundle; 4 | 5 | import java.util.HashMap; 6 | 7 | import xyz.ibat.sloth.base.webview.WebFragment; 8 | import xyz.ibat.sloth.domain.main.fragments.MainFragment; 9 | import xyz.ibat.sloth.domain.map.MeiziFragment; 10 | import xyz.ibat.sloth.domain.mine.MineFragment; 11 | 12 | /** 13 | * Created by DongJr on 2016/4/15. 14 | */ 15 | public class FragmentFactory { 16 | 17 | public static final String MAIN_TAG = "main"; 18 | public static final String MAP_TAG = "map"; 19 | public static final String INFO_TAG = "info"; 20 | public static final String MINE_TAG = "mine"; 21 | 22 | private MainFragment mainFragment; 23 | private MeiziFragment mapFragment; 24 | private WebFragment infoFragment; 25 | private MineFragment mineFragment; 26 | 27 | 28 | private static FragmentFactory mFactory; 29 | private HashMap mHashMap = new HashMap<>(); 30 | 31 | private FragmentFactory() { 32 | 33 | } 34 | 35 | public static FragmentFactory getInstance() { 36 | if (mFactory == null) { 37 | synchronized (FragmentFactory.class) { 38 | if (mFactory == null) { 39 | mFactory = new FragmentFactory(); 40 | } 41 | } 42 | } 43 | return mFactory; 44 | } 45 | 46 | public BaseFragment getFragmentByTag(String tag) { 47 | 48 | if (tag.equals(MAIN_TAG) && mainFragment == null) { 49 | mainFragment = new MainFragment(); 50 | mHashMap.put(MAIN_TAG, mainFragment); 51 | } 52 | if (tag.equals(MAP_TAG) && mapFragment == null) { 53 | mapFragment = new MeiziFragment(); 54 | mHashMap.put(MAP_TAG, mapFragment); 55 | } 56 | if (tag.equals(INFO_TAG) && infoFragment == null) { 57 | infoFragment = new WebFragment(); 58 | Bundle bundle = new Bundle(); 59 | bundle.putString(WebFragment.URL_TAG, "http://ibat.xyz"); 60 | infoFragment.setArguments(bundle); 61 | mHashMap.put(INFO_TAG, infoFragment); 62 | } 63 | if (tag.equals(MINE_TAG) && mineFragment == null) { 64 | mineFragment = new MineFragment(); 65 | mHashMap.put(MINE_TAG, mineFragment); 66 | } 67 | return mHashMap.get(tag); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/base/TabsFragment.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.base; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.FragmentTransaction; 5 | import android.text.TextUtils; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.FrameLayout; 10 | import android.widget.RadioButton; 11 | import android.widget.RadioGroup; 12 | 13 | import butterknife.Bind; 14 | import butterknife.ButterKnife; 15 | import xyz.ibat.sloth.R; 16 | 17 | /** 18 | * Created by DongJr on 2016/4/12. 19 | */ 20 | public class TabsFragment extends BaseFragment implements View.OnClickListener { 21 | 22 | @Bind(R.id.fragment_tab) 23 | FrameLayout fragmentTab; 24 | @Bind(R.id.tab_group) 25 | RadioGroup tabGroup; 26 | @Bind(R.id.main_tab) 27 | RadioButton mainTab; 28 | @Bind(R.id.map_tab) 29 | RadioButton mapTab; 30 | @Bind(R.id.info_tab) 31 | RadioButton infoTab; 32 | @Bind(R.id.mine_tab) 33 | RadioButton mineTab; 34 | 35 | private FragmentFactory mFactory; 36 | private String mCurrentTag; 37 | 38 | @Override 39 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 40 | View view = inflater.inflate(R.layout.fragment_tab, container, false); 41 | 42 | ButterKnife.bind(this, view); 43 | return view; 44 | } 45 | 46 | @Override 47 | public void onViewCreated(View view, Bundle savedInstanceState) { 48 | initView(); 49 | } 50 | 51 | private void initView() { 52 | mainTab.setChecked(true); 53 | mFactory = FragmentFactory.getInstance(); 54 | 55 | mainTab.setOnClickListener(this); 56 | mapTab.setOnClickListener(this); 57 | infoTab.setOnClickListener(this); 58 | mineTab.setOnClickListener(this); 59 | 60 | initFragment(FragmentFactory.MAIN_TAG); 61 | } 62 | 63 | @Override 64 | public void onClick(View v) { 65 | switch (v.getId()) { 66 | case R.id.main_tab: 67 | initFragment(FragmentFactory.MAIN_TAG); 68 | break; 69 | case R.id.map_tab: 70 | initFragment(FragmentFactory.MAP_TAG); 71 | break; 72 | case R.id.info_tab: 73 | initFragment(FragmentFactory.INFO_TAG); 74 | break; 75 | case R.id.mine_tab: 76 | initFragment(FragmentFactory.MINE_TAG); 77 | break; 78 | } 79 | } 80 | 81 | private void initFragment(String tag) { 82 | BaseFragment baseFragment = mFactory.getFragmentByTag(tag); 83 | if (baseFragment == null) { 84 | throw new IllegalAccessError("tag is error!"); 85 | } 86 | if (tag.equals(mCurrentTag)) { 87 | return; 88 | } else { 89 | FragmentTransaction transaction = getFragmentManager().beginTransaction(); 90 | if (!TextUtils.isEmpty(mCurrentTag)) { 91 | transaction.hide(mFactory.getFragmentByTag(mCurrentTag)); 92 | } 93 | if (!baseFragment.isAdded()) { 94 | transaction.add(R.id.fragment_tab, baseFragment); 95 | } else { 96 | transaction.show(baseFragment); 97 | } 98 | transaction.commitAllowingStateLoss(); 99 | } 100 | mCurrentTag = tag; 101 | } 102 | 103 | @Override 104 | public void onDestroyView() { 105 | super.onDestroyView(); 106 | ButterKnife.unbind(this); 107 | } 108 | 109 | 110 | } 111 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/base/adapter/NewLoadMoreWrapper.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.base.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.widget.ProgressBar; 8 | import android.widget.TextView; 9 | 10 | import com.zhy.adapter.recyclerview.wrapper.LoadMoreWrapper; 11 | 12 | import xyz.ibat.sloth.R; 13 | 14 | /** 15 | * Created by DongJr on 2017/1/16. 16 | */ 17 | 18 | public class NewLoadMoreWrapper extends LoadMoreWrapper { 19 | 20 | private LoadState mState = LoadState.LOAD; 21 | 22 | private View mFooterView; 23 | 24 | private ProgressBar loadProgress; 25 | private TextView loadText; 26 | 27 | private LayoutInflater mInflater; 28 | 29 | public NewLoadMoreWrapper(Context context, RecyclerView.Adapter adapter,RecyclerView parent) { 30 | super(adapter); 31 | 32 | mInflater = LayoutInflater.from(context); 33 | mFooterView = mInflater.inflate(R.layout.default_loading,parent, false); 34 | loadProgress = (ProgressBar) mFooterView.findViewById(R.id.load_progress); 35 | loadText = (TextView) mFooterView.findViewById(R.id.loading_text); 36 | setLoadMoreView(mFooterView); 37 | } 38 | 39 | public void setLoadState(LoadState state) { 40 | this.mState = state; 41 | switch (state) { 42 | case LOAD: 43 | showLoadView(); 44 | setShouldLoadMore(true); 45 | break; 46 | case ERROR: 47 | setShouldLoadMore(false); 48 | showLoadErrorView(); 49 | break; 50 | case NOMORE: 51 | setShouldLoadMore(false); 52 | showLoadNoMoreView(); 53 | break; 54 | default: 55 | throw new IllegalArgumentException("please input correct argument!"); 56 | } 57 | } 58 | 59 | private void showLoadView() { 60 | loadProgress.setVisibility(View.VISIBLE); 61 | loadText.setText("正在加载..."); 62 | } 63 | 64 | private void showLoadErrorView() { 65 | loadProgress.setVisibility(View.GONE); 66 | loadText.setText("加载失败啦..."); 67 | } 68 | 69 | private void showLoadNoMoreView() { 70 | loadProgress.setVisibility(View.GONE); 71 | loadText.setText("已经到底啦"); 72 | } 73 | 74 | public LoadState getCurrentState() { 75 | return mState; 76 | } 77 | 78 | public enum LoadState { 79 | LOAD, 80 | ERROR, 81 | NOMORE 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/base/webview/WebActivity.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.base.webview; 2 | 3 | import android.animation.AnimatorSet; 4 | import android.animation.ObjectAnimator; 5 | import android.annotation.SuppressLint; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.graphics.Bitmap; 9 | import android.os.Bundle; 10 | import android.support.v7.widget.Toolbar; 11 | import android.view.View; 12 | import android.view.animation.DecelerateInterpolator; 13 | import android.webkit.JavascriptInterface; 14 | import android.webkit.WebChromeClient; 15 | import android.webkit.WebResourceError; 16 | import android.webkit.WebResourceRequest; 17 | import android.webkit.WebSettings; 18 | import android.webkit.WebView; 19 | import android.webkit.WebViewClient; 20 | import android.widget.FrameLayout; 21 | import android.widget.LinearLayout; 22 | import android.widget.ProgressBar; 23 | 24 | import butterknife.Bind; 25 | import butterknife.ButterKnife; 26 | import xyz.ibat.sloth.R; 27 | import xyz.ibat.sloth.base.BaseActivity; 28 | import xyz.ibat.sloth.domain.main.activities.ImagePreviewActivity; 29 | import xyz.ibat.sloth.utils.T; 30 | 31 | public class WebActivity extends BaseActivity { 32 | 33 | @Bind(R.id.main_toolbar) 34 | Toolbar mainToolbar; 35 | @Bind(R.id.webview) 36 | WebView mWebView; 37 | @Bind(R.id.progress) 38 | ProgressBar mProgress; 39 | @Bind(R.id.btn_reload) 40 | FrameLayout btnReload; 41 | @Bind(R.id.load_fail_view) 42 | LinearLayout mLoadFailView; 43 | 44 | private static final String URL_TAG = "URL_TAG"; 45 | private static final String TITLE_TAG = "TITLE_TAG"; 46 | 47 | 48 | private String mUrl; 49 | private String mTitle; 50 | private boolean progressAnimStart = false; 51 | private boolean isReceivedError; 52 | 53 | public static void startActivity(Context context, String url) { 54 | startActivity(context, url, "Sloth"); 55 | } 56 | 57 | public static void startActivity(Context context, String url, String title) { 58 | Intent intent = new Intent(); 59 | intent.setClass(context, WebActivity.class); 60 | intent.putExtra(URL_TAG, url); 61 | intent.putExtra(TITLE_TAG, title); 62 | context.startActivity(intent); 63 | } 64 | 65 | @Override 66 | protected void onCreate(Bundle savedInstanceState) { 67 | super.onCreate(savedInstanceState); 68 | setContentView(R.layout.activity_web); 69 | ButterKnife.bind(this); 70 | 71 | Intent intent = getIntent(); 72 | mUrl = intent.getStringExtra(URL_TAG); 73 | mTitle = intent.getStringExtra(TITLE_TAG); 74 | 75 | mainToolbar.setTitle(mTitle); 76 | setSupportActionBar(mainToolbar); 77 | mainToolbar.setNavigationIcon(R.mipmap.icon_arrow_back); 78 | mainToolbar.setNavigationOnClickListener(new View.OnClickListener() { 79 | @Override 80 | public void onClick(View v) { 81 | finish(); 82 | } 83 | }); 84 | 85 | 86 | mWebView.loadUrl(mUrl); 87 | initView(); 88 | initWebView(); 89 | } 90 | 91 | private void initView() { 92 | mProgress.setProgressDrawable(getResources() 93 | .getDrawable(R.drawable.webview_progress_bar_states)); 94 | 95 | btnReload.setOnClickListener(new View.OnClickListener() { 96 | @Override 97 | public void onClick(View v) { 98 | mWebView.reload(); 99 | mLoadFailView.setVisibility(View.GONE); 100 | isReceivedError = false; 101 | } 102 | }); 103 | 104 | } 105 | 106 | @SuppressLint({"SetJavaScriptEnabled", "JavascriptInterface"}) 107 | private void initWebView() { 108 | WebSettings webSettings = mWebView.getSettings(); 109 | //设置与js交互 110 | webSettings.setJavaScriptEnabled(true); 111 | //设置是否支持缩放,默认true 112 | webSettings.setSupportZoom(false); 113 | //设置是否显示缩放工具 114 | webSettings.setBuiltInZoomControls(false); 115 | 116 | 117 | mWebView.setWebChromeClient(new SlothWebChromeClient()); 118 | 119 | mWebView.setWebViewClient(new SlothWebViewClient()); 120 | 121 | 122 | mWebView.addJavascriptInterface(new JSInterface(this), "webview"); 123 | 124 | } 125 | 126 | private void addImageClickListner() { 127 | // 遍历所有的img节点,并添加onclick函数 128 | mWebView.loadUrl("javascript:(function(){" + 129 | "var objs = document.getElementsByTagName(\"img\"); " + 130 | "for(var i=0;i= 100) { 182 | progressAnimStart = false; 183 | mProgress.setProgress(newProgress); 184 | mProgress.setVisibility(View.GONE); 185 | } else { 186 | if (!progressAnimStart) { 187 | mProgress.setVisibility(View.VISIBLE); 188 | startProgressAnimation(); 189 | } 190 | } 191 | } 192 | 193 | @Override 194 | public void onReceivedTitle(WebView view, String title) { 195 | super.onReceivedTitle(view, title); 196 | } 197 | 198 | 199 | } 200 | 201 | class SlothWebViewClient extends WebViewClient { 202 | 203 | @Override 204 | public boolean shouldOverrideUrlLoading(WebView view, String url) { 205 | //while return false means the current WebView handles the url. 206 | return super.shouldOverrideUrlLoading(view, url); 207 | 208 | } 209 | 210 | @Override 211 | public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { 212 | 213 | mWebView.setVisibility(View.GONE); 214 | mLoadFailView.setVisibility(View.VISIBLE); 215 | T.show(R.string.network_error); 216 | isReceivedError = true; 217 | 218 | } 219 | 220 | @Override 221 | public void onPageFinished(WebView view, String url) { 222 | if (!isReceivedError) { 223 | mWebView.setVisibility(View.VISIBLE); 224 | } 225 | addImageClickListner(); 226 | } 227 | 228 | @Override 229 | public void onPageStarted(WebView view, String url, Bitmap favicon) { 230 | 231 | super.onPageStarted(view, url, favicon); 232 | } 233 | 234 | 235 | } 236 | 237 | } 238 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/base/webview/WebFragment.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.base.webview; 2 | 3 | import android.animation.AnimatorSet; 4 | import android.animation.ObjectAnimator; 5 | import android.annotation.SuppressLint; 6 | import android.content.Context; 7 | import android.graphics.Bitmap; 8 | import android.os.Bundle; 9 | import android.support.annotation.Nullable; 10 | import android.support.v7.app.AppCompatActivity; 11 | import android.support.v7.widget.Toolbar; 12 | import android.view.LayoutInflater; 13 | import android.view.View; 14 | import android.view.ViewGroup; 15 | import android.view.animation.DecelerateInterpolator; 16 | import android.webkit.JavascriptInterface; 17 | import android.webkit.WebChromeClient; 18 | import android.webkit.WebResourceError; 19 | import android.webkit.WebResourceRequest; 20 | import android.webkit.WebSettings; 21 | import android.webkit.WebView; 22 | import android.webkit.WebViewClient; 23 | import android.widget.FrameLayout; 24 | import android.widget.LinearLayout; 25 | import android.widget.ProgressBar; 26 | 27 | import butterknife.Bind; 28 | import butterknife.ButterKnife; 29 | import xyz.ibat.sloth.R; 30 | import xyz.ibat.sloth.base.BaseFragment; 31 | import xyz.ibat.sloth.domain.main.activities.ImagePreviewActivity; 32 | import xyz.ibat.sloth.utils.T; 33 | 34 | /** 35 | * Created by DongJr on 2017/3/16. 36 | */ 37 | 38 | public class WebFragment extends BaseFragment { 39 | 40 | @Bind(R.id.progress) 41 | ProgressBar mProgress; 42 | @Bind(R.id.webview) 43 | WebView mWebView; 44 | @Bind(R.id.btn_reload) 45 | FrameLayout btnReload; 46 | @Bind(R.id.load_fail_view) 47 | LinearLayout mLoadFailView; 48 | @Bind(R.id.main_toolbar) 49 | Toolbar mainToolbar; 50 | private View mRootView; 51 | 52 | public static final String URL_TAG = "URL_TAG"; 53 | 54 | private String mUrl; 55 | private boolean progressAnimStart = false; 56 | private boolean isReceivedError; 57 | 58 | @Nullable 59 | @Override 60 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 61 | mRootView = inflater.inflate(R.layout.fragment_web, container, false); 62 | ButterKnife.bind(this, mRootView); 63 | 64 | ((AppCompatActivity) getActivity()).setSupportActionBar(mainToolbar); 65 | 66 | return mRootView; 67 | } 68 | 69 | @Override 70 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 71 | Bundle bundle = getArguments(); 72 | mUrl = bundle.getString(URL_TAG); 73 | 74 | if (mUrl != null) { 75 | mWebView.loadUrl(mUrl); 76 | initView(); 77 | initWebView(); 78 | } 79 | } 80 | 81 | private void initView() { 82 | mProgress.setProgressDrawable(getResources() 83 | .getDrawable(R.drawable.webview_progress_bar_states)); 84 | 85 | btnReload.setOnClickListener(new View.OnClickListener() { 86 | @Override 87 | public void onClick(View v) { 88 | mWebView.reload(); 89 | mLoadFailView.setVisibility(View.GONE); 90 | isReceivedError = false; 91 | } 92 | }); 93 | 94 | } 95 | 96 | @SuppressLint({"SetJavaScriptEnabled", "JavascriptInterface"}) 97 | private void initWebView() { 98 | WebSettings webSettings = mWebView.getSettings(); 99 | //设置与js交互 100 | webSettings.setJavaScriptEnabled(true); 101 | //设置是否支持缩放,默认true 102 | webSettings.setSupportZoom(false); 103 | //设置是否显示缩放工具 104 | webSettings.setBuiltInZoomControls(false); 105 | 106 | 107 | mWebView.setWebChromeClient(new SlothWebChromeClient()); 108 | 109 | mWebView.setWebViewClient(new SlothWebViewClient()); 110 | 111 | 112 | mWebView.addJavascriptInterface(new JSInterface(getContext()), "webview"); 113 | 114 | } 115 | 116 | private void addImageClickListner() { 117 | // 遍历所有的img节点,并添加onclick函数 118 | mWebView.loadUrl("javascript:(function(){" + 119 | "var objs = document.getElementsByTagName(\"img\"); " + 120 | "for(var i=0;i= 100) { 169 | progressAnimStart = false; 170 | mProgress.setProgress(newProgress); 171 | mProgress.setVisibility(View.GONE); 172 | } else { 173 | if (!progressAnimStart) { 174 | mProgress.setVisibility(View.VISIBLE); 175 | startProgressAnimation(); 176 | } 177 | } 178 | } 179 | 180 | @Override 181 | public void onReceivedTitle(WebView view, String title) { 182 | super.onReceivedTitle(view, title); 183 | } 184 | 185 | 186 | } 187 | 188 | class SlothWebViewClient extends WebViewClient { 189 | 190 | @Override 191 | public boolean shouldOverrideUrlLoading(WebView view, String url) { 192 | 193 | WebActivity.startActivity(getContext(), url); 194 | //while return false means the current WebView handles the url. 195 | return true; 196 | } 197 | 198 | @Override 199 | public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { 200 | 201 | mWebView.setVisibility(View.GONE); 202 | mLoadFailView.setVisibility(View.VISIBLE); 203 | T.show(R.string.network_error); 204 | isReceivedError = true; 205 | 206 | } 207 | 208 | @Override 209 | public void onPageFinished(WebView view, String url) { 210 | if (!isReceivedError) { 211 | mWebView.setVisibility(View.VISIBLE); 212 | } 213 | addImageClickListner(); 214 | } 215 | 216 | @Override 217 | public void onPageStarted(WebView view, String url, Bitmap favicon) { 218 | 219 | super.onPageStarted(view, url, favicon); 220 | } 221 | 222 | 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/domain/info/InfoFragment.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.domain.info; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v7.widget.Toolbar; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | import butterknife.Bind; 11 | import butterknife.ButterKnife; 12 | import xyz.ibat.sloth.R; 13 | import xyz.ibat.sloth.base.BaseActivity; 14 | import xyz.ibat.sloth.base.BaseFragment; 15 | 16 | /** 17 | * Created by DongJr on 2016/4/15. 18 | */ 19 | public class InfoFragment extends BaseFragment { 20 | @Bind(R.id.main_toolbar) 21 | Toolbar mainToolbar; 22 | 23 | @Override 24 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 25 | View view = inflater.inflate(R.layout.fragment_tab_info, container, false); 26 | ButterKnife.bind(this, view); 27 | return view; 28 | } 29 | 30 | 31 | @Override 32 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 33 | ((BaseActivity) getActivity()).setSupportActionBar(mainToolbar); 34 | } 35 | 36 | @Override 37 | public void onDestroyView() { 38 | super.onDestroyView(); 39 | ButterKnife.unbind(this); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/domain/main/activities/FriendActivity.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.domain.main.activities; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.view.MotionEvent; 6 | import android.view.View; 7 | 8 | import butterknife.Bind; 9 | import butterknife.ButterKnife; 10 | import xyz.ibat.sloth.R; 11 | 12 | /** 13 | * create by DongJr 2016/05/04 14 | */ 15 | public class FriendActivity extends AppCompatActivity { 16 | 17 | @Bind(R.id.first) 18 | View first; 19 | @Bind(R.id.second) 20 | View second; 21 | 22 | 23 | private float startY; 24 | private float endY; 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | setContentView(R.layout.activity_friend); 29 | ButterKnife.bind(this); 30 | } 31 | 32 | @Override 33 | public boolean onTouchEvent(MotionEvent event) { 34 | switch (event.getAction()){ 35 | case MotionEvent.ACTION_DOWN: 36 | startY = event.getY(); 37 | break; 38 | case MotionEvent.ACTION_MOVE: 39 | endY = event.getY(); 40 | float moveY = endY - startY; 41 | first.setY(moveY); 42 | break; 43 | } 44 | return true; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/domain/main/activities/ImagePreviewActivity.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.domain.main.activities; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Build; 6 | import android.os.Bundle; 7 | import android.transition.Transition; 8 | import android.transition.TransitionInflater; 9 | import android.view.Window; 10 | 11 | import butterknife.Bind; 12 | import butterknife.ButterKnife; 13 | import xyz.ibat.sloth.R; 14 | import xyz.ibat.sloth.base.BaseActivity; 15 | import xyz.ibat.sloth.network.ImageLoader; 16 | import xyz.ibat.sloth.view.widget.ZoomImageView; 17 | 18 | public class ImagePreviewActivity extends BaseActivity { 19 | 20 | @Bind(R.id.image) 21 | ZoomImageView image; 22 | 23 | public static final String URL_TAG = "URL_TAG"; 24 | 25 | public static final String SCALETYPE_TAG = "SCALETYPE_TAG"; 26 | 27 | public static final String SCALETYPE_CENTERCROP = "CENTER_CROP"; 28 | 29 | public static final String SCALETYPE_FITXY = "FIT_XY"; 30 | 31 | private String SCALETYPE = SCALETYPE_FITXY; 32 | 33 | private String url; 34 | 35 | public static void startActivity(Context context, String url) { 36 | startActivity(context, url, SCALETYPE_FITXY); 37 | } 38 | 39 | public static void startActivity(Context context, String url, String scropType) { 40 | Intent intent = new Intent(); 41 | intent.setClass(context, ImagePreviewActivity.class); 42 | intent.putExtra(URL_TAG, url); 43 | intent.putExtra(SCALETYPE_TAG, scropType); 44 | context.startActivity(intent); 45 | } 46 | 47 | 48 | @Override 49 | protected void onCreate(Bundle savedInstanceState) { 50 | getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS); 51 | super.onCreate(savedInstanceState); 52 | setContentView(R.layout.activity_image_preview); 53 | ButterKnife.bind(this); 54 | 55 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 56 | Transition explode = TransitionInflater.from(this).inflateTransition(R.transition.fade); 57 | //退出时使用 58 | getWindow().setExitTransition(explode); 59 | //第一次进入时使用 60 | getWindow().setEnterTransition(explode); 61 | //再次进入时使用 62 | getWindow().setReenterTransition(explode); 63 | } 64 | 65 | Intent intent = getIntent(); 66 | url = intent.getStringExtra(URL_TAG); 67 | SCALETYPE = intent.getStringExtra(SCALETYPE_TAG); 68 | 69 | if (SCALETYPE_FITXY.equals(SCALETYPE)) { 70 | // image.setScaleType(ImageView.ScaleType.FIT_XY); 71 | } else if (SCALETYPE_CENTERCROP.equals(SCALETYPE)) { 72 | // image.setScaleType(ImageView.ScaleType.CENTER_CROP); 73 | } else { 74 | // image.setScaleType(ImageView.ScaleType.CENTER_CROP); 75 | } 76 | 77 | ImageLoader.load(url, image); 78 | 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/domain/main/activities/MainActivity.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.domain.main.activities; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.FragmentManager; 5 | import android.support.v4.app.FragmentTransaction; 6 | 7 | import butterknife.ButterKnife; 8 | import xyz.ibat.sloth.R; 9 | import xyz.ibat.sloth.base.BaseActivity; 10 | import xyz.ibat.sloth.base.TabsFragment; 11 | 12 | /** 13 | * create by DongJr 2016/03/31 14 | * 图片素材,参考 https://design.google.com/icons/ 15 | * 子模块rooter实现: http://www.jianshu.com/p/7cb2cc9b726a?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io 16 | */ 17 | public class MainActivity extends BaseActivity { 18 | 19 | 20 | 21 | @Override 22 | protected void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | setContentView(R.layout.activity_main); 25 | ButterKnife.bind(this); 26 | initFragment(); 27 | } 28 | 29 | private void initFragment() { 30 | FragmentManager manager = getSupportFragmentManager(); 31 | FragmentTransaction transaction = manager.beginTransaction(); 32 | transaction.replace(R.id.fl_root,new TabsFragment()); 33 | transaction.commitAllowingStateLoss(); 34 | } 35 | 36 | 37 | 38 | 39 | /** 40 | * Activity彻底运行起来之后的回调 41 | * Called when activity start-up is complete 42 | * (after onStart() and onRestoreInstanceState(Bundle) have been called). 43 | */ 44 | @Override 45 | protected void onPostCreate(Bundle savedInstanceState) { 46 | super.onPostCreate(savedInstanceState); 47 | //箭头旋转动画的关键 48 | // mDrawerToggle.syncState(); 49 | } 50 | 51 | 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/domain/main/activities/MeiziActivity.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.domain.main.activities; 2 | 3 | import android.app.ActivityOptions; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.Build; 7 | import android.os.Bundle; 8 | import android.support.v4.widget.SwipeRefreshLayout; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.support.v7.widget.StaggeredGridLayoutManager; 11 | import android.support.v7.widget.Toolbar; 12 | import android.view.View; 13 | import android.view.ViewGroup; 14 | import android.widget.ImageView; 15 | 16 | import com.zhy.adapter.recyclerview.CommonAdapter; 17 | import com.zhy.adapter.recyclerview.MultiItemTypeAdapter; 18 | import com.zhy.adapter.recyclerview.base.ViewHolder; 19 | import com.zhy.adapter.recyclerview.wrapper.LoadMoreWrapper; 20 | 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | 24 | import butterknife.Bind; 25 | import butterknife.ButterKnife; 26 | import rx.Subscriber; 27 | import xyz.ibat.sloth.R; 28 | import xyz.ibat.sloth.base.BaseActivity; 29 | import xyz.ibat.sloth.base.adapter.NewLoadMoreWrapper; 30 | import xyz.ibat.sloth.domain.main.model.DataModel; 31 | import xyz.ibat.sloth.network.ImageLoader; 32 | import xyz.ibat.sloth.network.RetrofitFactory; 33 | import xyz.ibat.sloth.utils.DensityUtil; 34 | import xyz.ibat.sloth.utils.T; 35 | 36 | import static xyz.ibat.sloth.R.id.meizi; 37 | 38 | public class MeiziActivity extends BaseActivity implements SwipeRefreshLayout.OnRefreshListener { 39 | 40 | 41 | @Bind(R.id.main_toolbar) 42 | Toolbar mainToolbar; 43 | @Bind(R.id.recyclerView) 44 | RecyclerView recyclerView; 45 | @Bind(R.id.refresh) 46 | SwipeRefreshLayout mRefresh; 47 | 48 | private CommonAdapter mAdapter; 49 | private NewLoadMoreWrapper mLoadMoreWrapper; 50 | private List mResultsList = new ArrayList<>(); 51 | 52 | int mPageIndex = 1; 53 | 54 | public static void startActivity(Context context) { 55 | Intent intent = new Intent(); 56 | intent.setClass(context, MeiziActivity.class); 57 | context.startActivity(intent); 58 | } 59 | 60 | @Override 61 | protected void onCreate(Bundle savedInstanceState) { 62 | super.onCreate(savedInstanceState); 63 | setContentView(R.layout.activity_meizi); 64 | ButterKnife.bind(this); 65 | 66 | 67 | mainToolbar.setTitle("妹纸"); 68 | setSupportActionBar(mainToolbar); 69 | mainToolbar.setNavigationIcon(R.mipmap.icon_arrow_back); 70 | mainToolbar.setNavigationOnClickListener(new View.OnClickListener() { 71 | @Override 72 | public void onClick(View v) { 73 | finish(); 74 | } 75 | }); 76 | mRefresh.setColorSchemeResources(android.R.color.holo_blue_bright); 77 | mRefresh.setOnRefreshListener(this); 78 | 79 | StaggeredGridLayoutManager sgm = new StaggeredGridLayoutManager 80 | (2, StaggeredGridLayoutManager.VERTICAL); 81 | 82 | recyclerView.setLayoutManager(sgm); 83 | initAdapter(); 84 | requestData(); 85 | } 86 | 87 | private void initAdapter() { 88 | mAdapter = new CommonAdapter(this, R.layout.item_meizi, mResultsList) { 89 | @Override 90 | protected void convert(ViewHolder holder, DataModel.ResultsBean resultsBean, int position) { 91 | ImageView view = (ImageView) holder.getView(meizi); 92 | ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); 93 | layoutParams.height = (int) (DensityUtil.dp2px(160) + Math.random() * 200f); 94 | 95 | ImageLoader.load(resultsBean.getUrl(), view); 96 | } 97 | }; 98 | mLoadMoreWrapper = new NewLoadMoreWrapper(this, mAdapter, recyclerView); 99 | mLoadMoreWrapper.setLoadMoreView(R.layout.default_loading); 100 | mLoadMoreWrapper.setOnLoadMoreListener(new LoadMoreWrapper.OnLoadMoreListener() { 101 | @Override 102 | public void onLoadMoreRequested() { 103 | mPageIndex++; 104 | requestData(); 105 | } 106 | }); 107 | 108 | recyclerView.setAdapter(mLoadMoreWrapper); 109 | 110 | mAdapter.setOnItemClickListener(new MultiItemTypeAdapter.OnItemClickListener() { 111 | @Override 112 | public void onItemClick(View view, RecyclerView.ViewHolder holder, int position) { 113 | Intent intent = new Intent(); 114 | intent.setClass(MeiziActivity.this, ImagePreviewActivity.class); 115 | intent.putExtra(ImagePreviewActivity.URL_TAG, mResultsList.get(position).getUrl()); 116 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 117 | startActivity(intent, ActivityOptions.makeSceneTransitionAnimation 118 | (MeiziActivity.this).toBundle()); 119 | } else { 120 | startActivity(intent); 121 | } 122 | } 123 | 124 | @Override 125 | public boolean onItemLongClick(View view, RecyclerView.ViewHolder holder, int position) { 126 | return false; 127 | } 128 | }); 129 | 130 | } 131 | 132 | 133 | private void requestData() { 134 | Subscriber subscriber = new Subscriber() { 135 | @Override 136 | public void onCompleted() { 137 | if (mRefresh != null) { 138 | mRefresh.setRefreshing(false); 139 | } 140 | } 141 | 142 | @Override 143 | public void onError(Throwable e) { 144 | mLoadMoreWrapper.setLoadState(NewLoadMoreWrapper.LoadState.ERROR); 145 | T.show(e.getMessage()); 146 | } 147 | 148 | @Override 149 | public void onNext(DataModel homeDataModel) { 150 | 151 | if (mPageIndex == 1) { 152 | mResultsList.clear(); 153 | } 154 | List results = homeDataModel.getResults(); 155 | if (results.size() < 10) { 156 | mLoadMoreWrapper.setLoadState(NewLoadMoreWrapper.LoadState.NOMORE); 157 | } else { 158 | mLoadMoreWrapper.setLoadState(NewLoadMoreWrapper.LoadState.LOAD); 159 | } 160 | mResultsList.addAll(results); 161 | mLoadMoreWrapper.notifyDataSetChanged(); 162 | } 163 | }; 164 | 165 | RetrofitFactory.getInstance().getAndroidData(subscriber, "福利", mPageIndex); 166 | } 167 | 168 | 169 | @Override 170 | public void onRefresh() { 171 | mPageIndex = 1; 172 | requestData(); 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/domain/main/activities/MessageActivity.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.domain.main.activities; 2 | 3 | import android.os.Bundle; 4 | import android.support.design.widget.AppBarLayout; 5 | import android.support.design.widget.CollapsingToolbarLayout; 6 | import android.support.design.widget.CoordinatorLayout; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.support.v7.widget.Toolbar; 9 | import android.view.View; 10 | import android.widget.ImageView; 11 | 12 | import butterknife.Bind; 13 | import butterknife.ButterKnife; 14 | import xyz.ibat.sloth.R; 15 | /** 16 | * create by DongJr 2016/04/29 17 | */ 18 | public class MessageActivity extends AppCompatActivity { 19 | 20 | @Bind(R.id.backdrop) 21 | ImageView backdrop; 22 | @Bind(R.id.toolbar) 23 | Toolbar toolbar; 24 | @Bind(R.id.collapsing_toolbar) 25 | CollapsingToolbarLayout collapsingToolbar; 26 | @Bind(R.id.appbar) 27 | AppBarLayout appbar; 28 | @Bind(R.id.main_content) 29 | CoordinatorLayout mainContent; 30 | 31 | // 使用CollapsingToolbarLayout实现折叠效果,需要注意3点 32 | // 1. AppBarLayout的高度固定 33 | // 2. CollapsingToolbarLayout的子视图设置layout_collapseMode属性 34 | // 3. 关联悬浮视图设置app:layout_anchor,app:layout_anchorGravity属性 35 | @Override 36 | protected void onCreate(Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | setContentView(R.layout.activity_message); 39 | ButterKnife.bind(this); 40 | setSupportActionBar(toolbar); 41 | toolbar.setTitle("Sloth"); 42 | toolbar.setNavigationIcon(R.mipmap.icon_arrow_back); 43 | toolbar.setNavigationOnClickListener(new View.OnClickListener() { 44 | @Override 45 | public void onClick(View view) { 46 | finish(); 47 | } 48 | }); 49 | } 50 | 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/domain/main/adapter/HomeAdapter.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.domain.main.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.ViewGroup; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import xyz.ibat.sloth.domain.main.model.DataModel; 11 | 12 | /** 13 | * Created by DongJr on 2017/1/13. 14 | */ 15 | 16 | public class HomeAdapter extends RecyclerView.Adapter { 17 | 18 | private Context mContext; 19 | 20 | private List mList = new ArrayList<>(); 21 | 22 | public HomeAdapter(Context context) { 23 | mContext = context; 24 | } 25 | 26 | public HomeAdapter(Context context, DataModel model) { 27 | mContext = context; 28 | List list = model.getResults(); 29 | mList.addAll(list); 30 | } 31 | 32 | public void setData(DataModel model) { 33 | mList.clear(); 34 | mList.addAll(model.getResults()); 35 | notifyDataSetChanged(); 36 | } 37 | 38 | @Override 39 | public HomeHolder onCreateViewHolder(ViewGroup parent, int viewType) { 40 | return HomeHolder.newIntance(mContext, parent); 41 | } 42 | 43 | @Override 44 | public void onBindViewHolder(HomeHolder holder, int position) { 45 | if (mList != null) { 46 | holder.getView(mList.get(position)); 47 | } 48 | } 49 | 50 | @Override 51 | public int getItemCount() { 52 | return mList.size(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/domain/main/adapter/HomeHolder.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.domain.main.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | 10 | import xyz.ibat.sloth.R; 11 | import xyz.ibat.sloth.domain.main.model.DataModel; 12 | 13 | /** 14 | * Created by DongJr on 2017/1/13. 15 | */ 16 | 17 | public class HomeHolder extends RecyclerView.ViewHolder { 18 | 19 | private TextView mTitle; 20 | private TextView mDate; 21 | private TextView mAuthor; 22 | 23 | public HomeHolder(View itemView) { 24 | super(itemView); 25 | mTitle = (TextView) itemView.findViewById(R.id.tv_title); 26 | mDate = (TextView) itemView.findViewById(R.id.tv_date); 27 | mAuthor = (TextView) itemView.findViewById(R.id.tv_author); 28 | } 29 | 30 | public static HomeHolder newIntance(Context context, ViewGroup parent) { 31 | View view = LayoutInflater.from(context).inflate(R.layout.item_fragment_home, parent, false); 32 | return new HomeHolder(view); 33 | } 34 | 35 | public void getView(DataModel.ResultsBean bean) { 36 | mTitle.setText(bean.getDesc()); 37 | mDate.setText(bean.getPublishedAt()); 38 | mAuthor.setText(bean.getWho()); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/domain/main/adapter/MeiziAdapter.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.domain.main.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.ViewGroup; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import xyz.ibat.sloth.domain.main.model.DataModel; 11 | 12 | /** 13 | * Created by jerry on 2017/1/14. 14 | */ 15 | 16 | public class MeiziAdapter extends RecyclerView.Adapter{ 17 | 18 | private Context mContext; 19 | 20 | private List mList = new ArrayList<>(); 21 | 22 | public MeiziAdapter(Context context) { 23 | mContext = context; 24 | } 25 | 26 | public MeiziAdapter(Context context, DataModel model) { 27 | mContext = context; 28 | List list = model.getResults(); 29 | mList.addAll(list); 30 | } 31 | 32 | public void setData(DataModel model) { 33 | mList.clear(); 34 | mList.addAll(model.getResults()); 35 | notifyDataSetChanged(); 36 | } 37 | 38 | @Override 39 | public MeiziHolder onCreateViewHolder(ViewGroup parent, int viewType) { 40 | return MeiziHolder.newIntance(mContext,parent); 41 | } 42 | 43 | @Override 44 | public void onBindViewHolder(MeiziHolder holder, int position) { 45 | holder.getView(mList.get(position)); 46 | } 47 | 48 | @Override 49 | public int getItemCount() { 50 | return mList.size(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/domain/main/adapter/MeiziHolder.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.domain.main.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | 10 | import xyz.ibat.sloth.R; 11 | import xyz.ibat.sloth.domain.main.activities.ImagePreviewActivity; 12 | import xyz.ibat.sloth.domain.main.model.DataModel; 13 | import xyz.ibat.sloth.network.ImageLoader; 14 | import xyz.ibat.sloth.utils.DensityUtil; 15 | 16 | /** 17 | * Created by jerry on 2017/1/14. 18 | */ 19 | 20 | public class MeiziHolder extends RecyclerView.ViewHolder{ 21 | 22 | private ImageView meizi; 23 | 24 | public MeiziHolder(View itemView) { 25 | super(itemView); 26 | meizi = (ImageView) itemView.findViewById(R.id.meizi); 27 | } 28 | 29 | public static MeiziHolder newIntance(Context context, ViewGroup parent) { 30 | View view = LayoutInflater.from(context).inflate(R.layout.item_meizi, parent, false); 31 | return new MeiziHolder(view); 32 | } 33 | 34 | public void getView(final DataModel.ResultsBean bean) { 35 | 36 | ViewGroup.LayoutParams layoutParams = meizi.getLayoutParams(); 37 | layoutParams.height = (int) (DensityUtil.dp2px(160) + Math.random()*200f); 38 | ImageLoader.load(bean.getUrl(),meizi); 39 | 40 | meizi.setOnClickListener(new View.OnClickListener() { 41 | @Override 42 | public void onClick(View v) { 43 | ImagePreviewActivity.startActivity(v.getContext(),bean.getUrl()); 44 | } 45 | }); 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/domain/main/fragments/DataFragment.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.domain.main.fragments; 2 | 3 | import android.os.Bundle; 4 | import android.support.design.widget.FloatingActionButton; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v4.widget.SwipeRefreshLayout; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | 13 | import com.zhy.adapter.recyclerview.CommonAdapter; 14 | import com.zhy.adapter.recyclerview.MultiItemTypeAdapter; 15 | import com.zhy.adapter.recyclerview.base.ViewHolder; 16 | import com.zhy.adapter.recyclerview.wrapper.LoadMoreWrapper; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | import java.util.Random; 21 | 22 | import butterknife.Bind; 23 | import butterknife.ButterKnife; 24 | import rx.Subscriber; 25 | import xyz.ibat.sloth.R; 26 | import xyz.ibat.sloth.base.adapter.NewLoadMoreWrapper; 27 | import xyz.ibat.sloth.base.webview.WebActivity; 28 | import xyz.ibat.sloth.domain.main.model.DataModel; 29 | import xyz.ibat.sloth.network.RetrofitFactory; 30 | import xyz.ibat.sloth.utils.T; 31 | import xyz.ibat.sloth.view.SlothRecycler; 32 | import xyz.ibat.sloth.view.behavior.FABScrollBehavior; 33 | 34 | /** 35 | * Created by DongJr on 2016/03/31 36 | */ 37 | public class DataFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { 38 | 39 | @Bind(R.id.recycler_one) 40 | SlothRecycler mRecyclerView; 41 | @Bind(R.id.refresh_one) 42 | SwipeRefreshLayout mRefresh; 43 | @Bind(R.id.fab) 44 | FloatingActionButton mFab; 45 | 46 | private CommonAdapter mAdapter; 47 | private NewLoadMoreWrapper mLoadMoreWrapper; 48 | 49 | public static String TYPE_TAG = "TYPE_TAG"; 50 | private int mPageIndex = 1; 51 | private String mType; 52 | 53 | private List mResultsList = new ArrayList<>(); 54 | 55 | @Override 56 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 57 | Bundle savedInstanceState) { 58 | View view = inflater.inflate(R.layout.fragment_one, container, false); 59 | ButterKnife.bind(this, view); 60 | return view; 61 | } 62 | 63 | @Override 64 | public void onViewCreated(View view, Bundle savedInstanceState) { 65 | Bundle arguments = getArguments(); 66 | 67 | if (arguments != null) { 68 | mType = arguments.getString(TYPE_TAG); 69 | } 70 | 71 | mRefresh.setColorSchemeResources(android.R.color.holo_blue_bright); 72 | mRefresh.setOnRefreshListener(this); 73 | 74 | mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false)); 75 | 76 | initAdapter(); 77 | 78 | requestData(); 79 | 80 | mRecyclerView.addOnScrollListener(new FABScrollBehavior(mFab)); 81 | 82 | mFab.setOnClickListener(new View.OnClickListener() { 83 | @Override 84 | public void onClick(View v) { 85 | if (!mResultsList.isEmpty()) { 86 | Random random = new Random(); 87 | WebActivity.startActivity(getContext() 88 | , mResultsList.get(random.nextInt(mResultsList.size())).getUrl() 89 | , "随机看"); 90 | } 91 | } 92 | }); 93 | 94 | } 95 | 96 | private void initAdapter() { 97 | mAdapter = new CommonAdapter(getContext(), R.layout.item_fragment_home, mResultsList) { 98 | @Override 99 | protected void convert(ViewHolder holder, DataModel.ResultsBean resultsBean, int position) { 100 | holder.setText(R.id.tv_title, resultsBean.getDesc()) 101 | .setText(R.id.tv_author, resultsBean.getWho()) 102 | .setText(R.id.tv_date, resultsBean.getCreatedAt()); 103 | } 104 | }; 105 | mLoadMoreWrapper = new NewLoadMoreWrapper(getContext(), mAdapter, mRecyclerView); 106 | mLoadMoreWrapper.setOnLoadMoreListener(new LoadMoreWrapper.OnLoadMoreListener() { 107 | @Override 108 | public void onLoadMoreRequested() { 109 | mPageIndex++; 110 | requestData(); 111 | } 112 | }); 113 | 114 | mRecyclerView.setAdapter(mLoadMoreWrapper); 115 | 116 | mAdapter.setOnItemClickListener(new MultiItemTypeAdapter.OnItemClickListener() { 117 | @Override 118 | public void onItemClick(View view, RecyclerView.ViewHolder holder, int position) { 119 | DataModel.ResultsBean resultsBean = mResultsList.get(position); 120 | WebActivity.startActivity(getContext() 121 | , resultsBean.getUrl(), resultsBean.getDesc()); 122 | } 123 | 124 | @Override 125 | public boolean onItemLongClick(View view, RecyclerView.ViewHolder holder, int position) { 126 | return false; 127 | } 128 | }); 129 | 130 | } 131 | 132 | private void requestData() { 133 | RetrofitFactory.getInstance().getAndroidData(new Subscriber() { 134 | @Override 135 | public void onCompleted() { 136 | if (mRefresh != null) { 137 | mRefresh.setRefreshing(false); 138 | } 139 | } 140 | 141 | @Override 142 | public void onError(Throwable e) { 143 | mLoadMoreWrapper.setLoadState(NewLoadMoreWrapper.LoadState.ERROR); 144 | T.show(e.getMessage()); 145 | } 146 | 147 | @Override 148 | public void onNext(DataModel model) { 149 | if (mPageIndex == 1) { 150 | mResultsList.clear(); 151 | } 152 | List results = model.getResults(); 153 | if (results.size() < 10) { 154 | mLoadMoreWrapper.setLoadState(NewLoadMoreWrapper.LoadState.NOMORE); 155 | } else { 156 | mLoadMoreWrapper.setLoadState(NewLoadMoreWrapper.LoadState.LOAD); 157 | } 158 | mResultsList.addAll(results); 159 | mLoadMoreWrapper.notifyDataSetChanged(); 160 | 161 | } 162 | }, mType, mPageIndex); 163 | } 164 | 165 | @Override 166 | public void onDestroyView() { 167 | super.onDestroyView(); 168 | ButterKnife.unbind(this); 169 | } 170 | 171 | @Override 172 | public void onRefresh() { 173 | mPageIndex = 1; 174 | requestData(); 175 | } 176 | 177 | } 178 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/domain/main/model/DataModel.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.domain.main.model; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by DongJr on 2017/1/13. 7 | */ 8 | 9 | public class DataModel { 10 | 11 | 12 | /** 13 | * error : false 14 | * results : [{"_id":"5875e66c421aa9315ea79931","createdAt":"2017-01-11T16:01:48.998Z","desc":"在Chrome DevTools内查看Android设备上所有HTTP(S)流量","images":["http://img.gank.io/b33cc839-18de-48e0-8644-089e6986609a","http://img.gank.io/a4ce3373-2f20-4fe5-bbcf-9f6dc3847591"],"publishedAt":"2017-01-12T11:30:59.369Z","source":"web","type":"Android","url":"https://github.com/misakuo/Dream-Catcher","used":true,"who":"moxun"},{"_id":"5876e940421aa93161103df1","createdAt":"2017-01-12T10:26:08.237Z","desc":"类似 Facebook 加载时,条目的闪烁效果,酷酷的。","images":["http://img.gank.io/985a1011-632f-40c1-9ca5-1bd9cb17a69f","http://img.gank.io/c5c916fc-b391-40ec-9962-df8588f23cba"],"publishedAt":"2017-01-12T11:30:59.369Z","source":"chrome","type":"Android","url":"https://github.com/sharish/ShimmerRecyclerView","used":true,"who":"代码家"},{"_id":"5872fb61421aa9315bfbe843","createdAt":"2017-01-09T10:54:25.659Z","desc":"android多图选择 图片/视频 单选or多选,以及视频录制。","images":["http://img.gank.io/eafb5329-c252-42f3-a8cc-48f6b247c9f8","http://img.gank.io/f58b7772-ce21-4875-b709-2f21ba2d2c3f"],"publishedAt":"2017-01-11T12:05:20.787Z","source":"web","type":"Android","url":"https://github.com/LuckSiege/PictureSelector","used":true,"who":null},{"_id":"587469c5421aa9316407fb95","createdAt":"2017-01-10T12:57:41.909Z","desc":"top-5-android-libraries-january-2017","publishedAt":"2017-01-11T12:05:20.787Z","source":"web","type":"Android","url":"https://medium.cobeisfresh.com/top-5-android-libraries-january-2017-53e217783fc9","used":true,"who":"kg"},{"_id":"58759363421aa93161103ddd","createdAt":"2017-01-11T10:07:31.126Z","desc":"Android 多渠道打包的 Android Studio / IDEA 插件","images":["http://img.gank.io/e9e0de53-aaba-4e2b-a123-cdaac87eeb56"],"publishedAt":"2017-01-11T12:05:20.787Z","source":"web","type":"Android","url":"https://github.com/nukc/ApkMultiChannelPlugin","used":true,"who":"C君"},{"_id":"58759c0d421aa93161103ddf","createdAt":"2017-01-11T10:44:29.208Z","desc":"Android 状态切换按钮效果","images":["http://img.gank.io/10c58071-a555-4e1f-84ff-8220644a35e9"],"publishedAt":"2017-01-11T12:05:20.787Z","source":"chrome","type":"Android","url":"https://github.com/zagum/Android-SwitchIcon","used":true,"who":"代码家"},{"_id":"58759c56421aa9315bfbe856","createdAt":"2017-01-11T10:45:42.636Z","desc":"Android 跑马灯效果,适合做个小广告,通知之类的。","images":["http://img.gank.io/ba7b29c2-55d9-4cc5-9861-ffc19d332950"],"publishedAt":"2017-01-11T12:05:20.787Z","source":"chrome","type":"Android","url":"https://github.com/gongwen/MarqueeViewLibrary","used":true,"who":"代码家"},{"_id":"58732679421aa93161103dd0","createdAt":"2017-01-09T13:58:17.708Z","desc":"Tinker接入及源码分析,从简单介绍到如何接入再到加载补丁、合成补丁源码分析","images":["http://img.gank.io/1408b5b4-23b3-410e-80cb-9cb096d1ad8a"],"publishedAt":"2017-01-10T11:33:19.525Z","source":"web","type":"Android","url":"http://qlm.pw/2017/01/07/tinker%E6%8E%A5%E5%85%A5%E5%8F%8A%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90%EF%BC%88%E4%B8%80%EF%BC%89/","used":true,"who":"Linmin Qiu"},{"_id":"58732e0a421aa9316407fb8a","createdAt":"2017-01-09T14:30:34.824Z","desc":"两行代码搞定Android视图扩散切换效果~","images":["http://img.gank.io/082da85a-9c5a-4330-a6c9-8ab624792b9f"],"publishedAt":"2017-01-10T11:33:19.525Z","source":"web","type":"Android","url":"https://github.com/zhangke3016/ViewSpreadTranslationController","used":true,"who":"张珂"},{"_id":"58745452421aa9316407fb93","createdAt":"2017-01-10T11:26:10.880Z","desc":"支持计数效果的 FloatingActionButton","images":["http://img.gank.io/2047fbd1-57cc-4efe-be4e-a31487904825"],"publishedAt":"2017-01-10T11:33:19.525Z","source":"chrome","type":"Android","url":"https://github.com/andremion/CounterFab","used":true,"who":"代码家"}] 15 | */ 16 | 17 | private boolean error; 18 | /** 19 | * _id : 5875e66c421aa9315ea79931 20 | * createdAt : 2017-01-11T16:01:48.998Z 21 | * desc : 在Chrome DevTools内查看Android设备上所有HTTP(S)流量 22 | * images : ["http://img.gank.io/b33cc839-18de-48e0-8644-089e6986609a","http://img.gank.io/a4ce3373-2f20-4fe5-bbcf-9f6dc3847591"] 23 | * publishedAt : 2017-01-12T11:30:59.369Z 24 | * source : web 25 | * type : Android 26 | * url : https://github.com/misakuo/Dream-Catcher 27 | * used : true 28 | * who : moxun 29 | */ 30 | 31 | private List results; 32 | 33 | public boolean isError() { 34 | return error; 35 | } 36 | 37 | public void setError(boolean error) { 38 | this.error = error; 39 | } 40 | 41 | public List getResults() { 42 | return results; 43 | } 44 | 45 | public void setResults(List results) { 46 | this.results = results; 47 | } 48 | 49 | public static class ResultsBean { 50 | private String _id; 51 | private String createdAt; 52 | private String desc; 53 | private String publishedAt; 54 | private String source; 55 | private String type; 56 | private String url; 57 | private boolean used; 58 | private String who; 59 | private List images; 60 | 61 | public String get_id() { 62 | return _id; 63 | } 64 | 65 | public void set_id(String _id) { 66 | this._id = _id; 67 | } 68 | 69 | public String getCreatedAt() { 70 | return createdAt; 71 | } 72 | 73 | public void setCreatedAt(String createdAt) { 74 | this.createdAt = createdAt; 75 | } 76 | 77 | public String getDesc() { 78 | return desc; 79 | } 80 | 81 | public void setDesc(String desc) { 82 | this.desc = desc; 83 | } 84 | 85 | public String getPublishedAt() { 86 | return publishedAt; 87 | } 88 | 89 | public void setPublishedAt(String publishedAt) { 90 | this.publishedAt = publishedAt; 91 | } 92 | 93 | public String getSource() { 94 | return source; 95 | } 96 | 97 | public void setSource(String source) { 98 | this.source = source; 99 | } 100 | 101 | public String getType() { 102 | return type; 103 | } 104 | 105 | public void setType(String type) { 106 | this.type = type; 107 | } 108 | 109 | public String getUrl() { 110 | return url; 111 | } 112 | 113 | public void setUrl(String url) { 114 | this.url = url; 115 | } 116 | 117 | public boolean isUsed() { 118 | return used; 119 | } 120 | 121 | public void setUsed(boolean used) { 122 | this.used = used; 123 | } 124 | 125 | public String getWho() { 126 | return who; 127 | } 128 | 129 | public void setWho(String who) { 130 | this.who = who; 131 | } 132 | 133 | public List getImages() { 134 | return images; 135 | } 136 | 137 | public void setImages(List images) { 138 | this.images = images; 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/domain/map/MeiziFragment.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.domain.map; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.design.widget.FloatingActionButton; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.support.v7.widget.StaggeredGridLayoutManager; 8 | import android.support.v7.widget.Toolbar; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | 13 | import butterknife.Bind; 14 | import butterknife.ButterKnife; 15 | import rx.Subscriber; 16 | import xyz.ibat.sloth.R; 17 | import xyz.ibat.sloth.base.BaseActivity; 18 | import xyz.ibat.sloth.base.BaseFragment; 19 | import xyz.ibat.sloth.domain.main.adapter.MeiziAdapter; 20 | import xyz.ibat.sloth.domain.main.model.DataModel; 21 | import xyz.ibat.sloth.network.RetrofitFactory; 22 | import xyz.ibat.sloth.utils.T; 23 | 24 | /** 25 | * Created by DongJr on 2016/4/15. 26 | */ 27 | public class MeiziFragment extends BaseFragment { 28 | 29 | @Bind(R.id.main_toolbar) 30 | Toolbar mainToolbar; 31 | @Bind(R.id.recyclerView) 32 | RecyclerView recyclerView; 33 | @Bind(R.id.fab) 34 | FloatingActionButton fab; 35 | 36 | private MeiziAdapter mAdapter; 37 | 38 | @Override 39 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 40 | View view = inflater.inflate(R.layout.fragment_tab_map, container, false); 41 | ButterKnife.bind(this, view); 42 | return view; 43 | } 44 | 45 | @Override 46 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 47 | mainToolbar.setTitle("妹纸"); 48 | ((BaseActivity) getActivity()).setSupportActionBar(mainToolbar); 49 | 50 | StaggeredGridLayoutManager sgm = new StaggeredGridLayoutManager 51 | (2, StaggeredGridLayoutManager.VERTICAL); 52 | 53 | recyclerView.setLayoutManager(sgm); 54 | 55 | requestData(); 56 | 57 | fab.setOnClickListener(new View.OnClickListener() { 58 | @Override 59 | public void onClick(View v) { 60 | requestData(); 61 | } 62 | }); 63 | 64 | } 65 | 66 | private void requestData() { 67 | Subscriber subscriber = new Subscriber() { 68 | @Override 69 | public void onCompleted() { 70 | 71 | } 72 | 73 | @Override 74 | public void onError(Throwable e) { 75 | T.show(e.getMessage()); 76 | } 77 | 78 | @Override 79 | public void onNext(DataModel dataModel) { 80 | if (mAdapter == null) { 81 | mAdapter = new MeiziAdapter(getContext(), dataModel); 82 | recyclerView.setAdapter(mAdapter); 83 | } else { 84 | mAdapter.setData(dataModel); 85 | } 86 | } 87 | }; 88 | 89 | RetrofitFactory.getInstance().getRandomData(subscriber, "福利"); 90 | } 91 | 92 | 93 | @Override 94 | public void onDestroyView() { 95 | super.onDestroyView(); 96 | ButterKnife.unbind(this); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/domain/mine/MineFragment.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.domain.mine; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.design.widget.CollapsingToolbarLayout; 6 | import android.support.v7.widget.Toolbar; 7 | import android.text.Spannable; 8 | import android.text.SpannableStringBuilder; 9 | import android.text.method.LinkMovementMethod; 10 | import android.text.style.ClickableSpan; 11 | import android.text.style.URLSpan; 12 | import android.view.LayoutInflater; 13 | import android.view.View; 14 | import android.view.ViewGroup; 15 | import android.webkit.URLUtil; 16 | import android.widget.ImageView; 17 | import android.widget.TextView; 18 | 19 | import butterknife.Bind; 20 | import butterknife.ButterKnife; 21 | import xyz.ibat.sloth.R; 22 | import xyz.ibat.sloth.base.BaseActivity; 23 | import xyz.ibat.sloth.base.BaseFragment; 24 | import xyz.ibat.sloth.base.webview.WebActivity; 25 | import xyz.ibat.sloth.network.ImageLoader; 26 | 27 | /** 28 | * Created by DongJr on 2016/4/15. 29 | */ 30 | public class MineFragment extends BaseFragment { 31 | 32 | 33 | @Bind(R.id.user_head) 34 | ImageView userHead; 35 | @Bind(R.id.toolbar) 36 | Toolbar toolbar; 37 | @Bind(R.id.collapsing_toolbar) 38 | CollapsingToolbarLayout collapsingToolbar; 39 | @Bind(R.id.tv_thanks) 40 | TextView tvThanks; 41 | @Bind(R.id.tv_blog) 42 | TextView tvBlog; 43 | 44 | @Override 45 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 46 | View view = inflater.inflate(R.layout.fragment_tab_mine, container, false); 47 | ButterKnife.bind(this, view); 48 | return view; 49 | } 50 | 51 | @Override 52 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 53 | 54 | collapsingToolbar.setTitle("小董同学"); 55 | ((BaseActivity) getActivity()).setSupportActionBar(toolbar); 56 | ImageLoader.loadCircle(R.mipmap.icon_head, userHead); 57 | 58 | 59 | 60 | setTextLink(); 61 | } 62 | 63 | private void setTextLink() { 64 | interceptLink(tvThanks); 65 | interceptLink(tvBlog); 66 | } 67 | 68 | private void interceptLink(TextView view) { 69 | 70 | view.setMovementMethod(LinkMovementMethod.getInstance()); 71 | 72 | CharSequence text = view.getText(); 73 | 74 | if (text instanceof Spannable) { 75 | 76 | Spannable spannable = (Spannable) text; 77 | URLSpan[] spans = spannable.getSpans(0, text.length(), URLSpan.class); 78 | if (spans.length == 0) { 79 | return; 80 | } 81 | SpannableStringBuilder ssb = new SpannableStringBuilder(text); 82 | 83 | for (URLSpan urlSpan : spans) { 84 | final String url = urlSpan.getURL(); 85 | if (URLUtil.isNetworkUrl(url)) { 86 | 87 | ClickableSpan clickableSpan = new ClickableSpan() { 88 | @Override 89 | public void onClick(View widget) { 90 | WebActivity.startActivity(getActivity(), url); 91 | } 92 | }; 93 | ssb.setSpan(clickableSpan, spannable.getSpanStart(urlSpan) 94 | , spannable.getSpanEnd(urlSpan), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 95 | } 96 | } 97 | view.setText(ssb); 98 | } 99 | 100 | 101 | } 102 | 103 | 104 | @Override 105 | public void onDestroyView() { 106 | super.onDestroyView(); 107 | ButterKnife.unbind(this); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/network/ImageLoader.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.network; 2 | 3 | import android.graphics.Bitmap; 4 | import android.widget.ImageView; 5 | 6 | import com.squareup.picasso.Picasso; 7 | 8 | import java.io.File; 9 | 10 | import xyz.ibat.sloth.SlothApplication; 11 | import xyz.ibat.sloth.view.picasso.CircleTransform; 12 | 13 | /** 14 | * Created by jerry on 2017/1/14. 15 | */ 16 | 17 | public class ImageLoader { 18 | 19 | 20 | private ImageLoader() { 21 | 22 | } 23 | 24 | /** 25 | * ALPHA_8:每个像素占用1byte内存 26 | * ARGB_4444:每个像素占用2byte内存 27 | * ARGB_8888:每个像素占用4byte内存 28 | * RGB_565:每个像素占用2byte内存 29 | */ 30 | public static void load(String url, ImageView view) { 31 | Picasso.with(SlothApplication.getContext()) 32 | .load(url) 33 | .config(Bitmap.Config.RGB_565) 34 | .into(view); 35 | } 36 | 37 | public static void load(int drawableRes, ImageView view) { 38 | Picasso.with(SlothApplication.getContext()) 39 | .load(drawableRes) 40 | .config(Bitmap.Config.RGB_565) 41 | .into(view); 42 | } 43 | 44 | public static void load(File file, ImageView view) { 45 | Picasso.with(SlothApplication.getContext()) 46 | .load(file) 47 | .config(Bitmap.Config.RGB_565) 48 | .into(view); 49 | } 50 | 51 | public static void loadCircle(String url, ImageView view) { 52 | Picasso.with(SlothApplication.getContext()) 53 | .load(url) 54 | .transform(new CircleTransform(SlothApplication.getContext())) 55 | .config(Bitmap.Config.RGB_565) 56 | .into(view); 57 | } 58 | 59 | public static void loadCircle(int drawableRes, ImageView view) { 60 | Picasso.with(SlothApplication.getContext()) 61 | .load(drawableRes) 62 | .transform(new CircleTransform(SlothApplication.getContext())) 63 | .config(Bitmap.Config.RGB_565) 64 | .into(view); 65 | } 66 | 67 | 68 | } 69 | 70 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/network/RetrofitFactory.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.network; 2 | 3 | import retrofit2.Retrofit; 4 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; 5 | import retrofit2.converter.gson.GsonConverterFactory; 6 | import rx.Subscriber; 7 | import rx.android.schedulers.AndroidSchedulers; 8 | import rx.schedulers.Schedulers; 9 | import xyz.ibat.sloth.domain.main.model.DataModel; 10 | import xyz.ibat.sloth.network.api.ApiService; 11 | 12 | /** 13 | * Created by DongJr on 2017/1/13. 14 | */ 15 | 16 | public class RetrofitFactory { 17 | 18 | private static final String BASE_URL = "http://gank.io/api/"; 19 | 20 | private Retrofit retrofit; 21 | 22 | private ApiService apiService; 23 | 24 | private RetrofitFactory() { 25 | 26 | retrofit = new Retrofit.Builder() 27 | .baseUrl(BASE_URL) 28 | .addConverterFactory(GsonConverterFactory.create()) 29 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 30 | .build(); 31 | 32 | apiService = retrofit.create(ApiService.class); 33 | } 34 | 35 | private static class SingletonHolder { 36 | private static final RetrofitFactory INSTANCE = new RetrofitFactory(); 37 | } 38 | 39 | public static RetrofitFactory getInstance() { 40 | return SingletonHolder.INSTANCE; 41 | } 42 | 43 | public void getAndroidData(Subscriber subscriber, String type, int pageIndex) { 44 | 45 | apiService.getAndroidData(type, pageIndex) 46 | .subscribeOn(Schedulers.io()) 47 | .observeOn(AndroidSchedulers.mainThread()) 48 | .subscribe(subscriber); 49 | 50 | } 51 | 52 | public void getRandomData(Subscriber subscriber,String type){ 53 | 54 | apiService.getRandomData(type) 55 | .subscribeOn(Schedulers.io()) 56 | .observeOn(AndroidSchedulers.mainThread()) 57 | .subscribe(subscriber); 58 | 59 | } 60 | 61 | 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/network/api/ApiService.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.network.api; 2 | 3 | import retrofit2.http.GET; 4 | import retrofit2.http.Path; 5 | import rx.Observable; 6 | import xyz.ibat.sloth.domain.main.model.DataModel; 7 | 8 | /** 9 | * Created by DongJr on 2017/1/13. 10 | */ 11 | 12 | public interface ApiService { 13 | 14 | @GET("data/{type}/10/{page}") 15 | Observable getAndroidData(@Path("type") String type, @Path("page") int page); 16 | 17 | @GET("random/data/{type}/20") 18 | Observable getRandomData(@Path("type") String type); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/utils/DensityUtil.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.utils; 2 | 3 | import android.content.res.Resources; 4 | 5 | /** 6 | * Created by jerry on 2017/1/14. 7 | */ 8 | 9 | public class DensityUtil { 10 | 11 | private DensityUtil() { 12 | /** cannot be instantiated **/ 13 | throw new UnsupportedOperationException("cannot be instantiated"); 14 | } 15 | 16 | /** 17 | * dp转px 18 | */ 19 | public static int dp2px(float dpVal) { 20 | final float scale = Resources.getSystem().getDisplayMetrics().density; 21 | return (int) (dpVal * scale + 0.5f); 22 | } 23 | 24 | /** 25 | * sp转px 26 | */ 27 | public static int sp2px(float spVal) { 28 | final float fontScale = Resources.getSystem().getDisplayMetrics().scaledDensity; 29 | return (int) (spVal * fontScale + 0.5f); 30 | } 31 | 32 | /** 33 | * px转dp 34 | */ 35 | public static float px2dp(float pxVal) { 36 | final float scale = Resources.getSystem().getDisplayMetrics().density; 37 | return (pxVal / scale); 38 | } 39 | 40 | /** 41 | * px转sp 42 | */ 43 | public static float px2sp(float pxVal) { 44 | return (pxVal / Resources.getSystem().getDisplayMetrics().scaledDensity); 45 | } 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/utils/SlothUtil.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.utils; 2 | 3 | import android.widget.Toast; 4 | 5 | import xyz.ibat.sloth.SlothApplication; 6 | 7 | /** 8 | * Created by DongJr on 2016/4/1. 9 | */ 10 | public class SlothUtil { 11 | 12 | public static void showToast(String msg) { 13 | Toast.makeText(SlothApplication.getContext(), msg, Toast.LENGTH_SHORT).show(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/utils/T.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.utils; 2 | 3 | import android.widget.Toast; 4 | 5 | import xyz.ibat.sloth.SlothApplication; 6 | 7 | /** 8 | * Created by DongJr on 2017/1/13. 9 | */ 10 | 11 | public class T { 12 | 13 | private static Toast toast; 14 | 15 | private T() { 16 | 17 | } 18 | 19 | public static void show(int msg) { 20 | if (toast == null) { 21 | toast = Toast.makeText(SlothApplication.getContext(), msg, Toast.LENGTH_SHORT); 22 | } else { 23 | toast.setText(msg); 24 | } 25 | toast.show(); 26 | } 27 | 28 | public static void show(String msg) { 29 | if (toast == null) { 30 | toast = Toast.makeText(SlothApplication.getContext(), msg, Toast.LENGTH_SHORT); 31 | } else { 32 | toast.setText(msg); 33 | } 34 | toast.show(); 35 | } 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/view/AppBarStateChangeListener.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.view; 2 | 3 | import android.support.design.widget.AppBarLayout; 4 | import android.util.Log; 5 | 6 | /** 7 | * Created by DongJr on 2017/1/5. 8 | */ 9 | 10 | public abstract class AppBarStateChangeListener implements AppBarLayout.OnOffsetChangedListener { 11 | 12 | public enum State { 13 | EXPANDED, 14 | COLLAPSED, 15 | IDLE 16 | } 17 | 18 | private State mCurrentState = State.IDLE; 19 | 20 | @Override 21 | public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { 22 | 23 | 24 | float percent = (float) Math.abs(verticalOffset) / (float) appBarLayout.getTotalScrollRange(); 25 | Log.e("dong", percent + "================" + verticalOffset + "=======" + appBarLayout.getTotalScrollRange()); 26 | 27 | if (verticalOffset == 0) { 28 | onStateChanged(appBarLayout, State.EXPANDED, percent); 29 | mCurrentState = State.EXPANDED; 30 | } else if (Math.abs(verticalOffset) >= appBarLayout.getTotalScrollRange()) { 31 | onStateChanged(appBarLayout, State.COLLAPSED, percent); 32 | mCurrentState = State.COLLAPSED; 33 | } else { 34 | onStateChanged(appBarLayout, State.IDLE, percent); 35 | mCurrentState = State.IDLE; 36 | } 37 | 38 | } 39 | 40 | public abstract void onStateChanged(AppBarLayout appBarLayout, State state, float percent); 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/view/RefreshLayout.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.view; 2 | 3 | import android.content.Context; 4 | import android.support.v4.widget.SwipeRefreshLayout; 5 | import android.util.AttributeSet; 6 | import android.view.View; 7 | import android.widget.AbsListView; 8 | import android.widget.ListView; 9 | import android.widget.ProgressBar; 10 | import android.widget.TextView; 11 | 12 | import xyz.ibat.sloth.R; 13 | 14 | /** 15 | * Created by DongJr on 2016/4/5. 16 | */ 17 | public class RefreshLayout extends SwipeRefreshLayout implements AbsListView.OnScrollListener { 18 | 19 | private OnLoadListener mOnloadListener; 20 | 21 | private ListView mListView; 22 | 23 | private int mLastVisiblePosition; 24 | 25 | //是否正在加载 26 | private boolean isLoading = false; 27 | 28 | private View mFootView; 29 | 30 | private ProgressBar mProgress; 31 | private TextView mTextView; 32 | 33 | public RefreshLayout(Context context) { 34 | super(context); 35 | init(context); 36 | } 37 | 38 | public RefreshLayout(Context context, AttributeSet attrs) { 39 | super(context, attrs); 40 | init(context); 41 | } 42 | 43 | public enum LoadState { 44 | ONLOADING, 45 | NOMORE 46 | } 47 | 48 | public void setLoadState(LoadState loadState) { 49 | switch (loadState) { 50 | case ONLOADING: 51 | mTextView.setText("正在刷新"); 52 | mProgress.setVisibility(VISIBLE); 53 | break; 54 | case NOMORE: 55 | mTextView.setText("没有更多了"); 56 | mProgress.setVisibility(GONE); 57 | break; 58 | 59 | } 60 | } 61 | 62 | private void init(Context context) { 63 | mFootView = View.inflate(context, R.layout.item_refresh_foot, null); 64 | mProgress = (ProgressBar) mFootView.findViewById(R.id.load_progress); 65 | mTextView = (TextView) mFootView.findViewById(R.id.loadmore_text); 66 | } 67 | 68 | @Override 69 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 70 | super.onLayout(changed, left, top, right, bottom); 71 | if (mListView == null) { 72 | getView(); 73 | } 74 | } 75 | 76 | //绑定当前listView 77 | private void getView() { 78 | int childCount = getChildCount(); 79 | if (childCount > 0) { 80 | for (int i = 0; i < childCount; i++) { 81 | View childView = getChildAt(i); 82 | if (childView instanceof ListView) { 83 | mListView = (ListView) childView; 84 | setScrollListener(); 85 | } 86 | } 87 | } 88 | } 89 | 90 | private void setScrollListener() { 91 | if (mListView != null) { 92 | mListView.setOnScrollListener(this); 93 | } 94 | } 95 | 96 | private void loadData() { 97 | if (mOnloadListener != null) { 98 | setLoading(true); 99 | mOnloadListener.onLoad(); 100 | } 101 | } 102 | 103 | public void setLoading(boolean loading) { 104 | isLoading = loading; 105 | if (isLoading) { 106 | //防止重绘 107 | if (mListView.getFooterViewsCount() == 0) { 108 | mListView.addFooterView(mFootView); 109 | } 110 | } else { 111 | mListView.removeFooterView(mFootView); 112 | } 113 | } 114 | 115 | public void setOnLoadListener(OnLoadListener onLoadListener) { 116 | mOnloadListener = onLoadListener; 117 | } 118 | 119 | public void setListener(OnRefreshListener onRefreshListener,OnLoadListener onLoadListener){ 120 | setOnRefreshListener(onRefreshListener); 121 | mOnloadListener = onLoadListener; 122 | } 123 | 124 | @Override 125 | public void onScrollStateChanged(AbsListView view, int scrollState) { 126 | 127 | int visibleItemCount = view.getChildCount(); 128 | int totalItemCount = mListView.getAdapter().getCount(); 129 | mLastVisiblePosition = mListView.getLastVisiblePosition(); 130 | 131 | if ((visibleItemCount > 0 && scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE && 132 | (mLastVisiblePosition) == totalItemCount - 1)) { 133 | if (!isLoading) { 134 | loadData(); 135 | isLoading = false; 136 | } 137 | } 138 | } 139 | 140 | @Override 141 | public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 142 | 143 | } 144 | 145 | 146 | public interface OnLoadListener { 147 | void onLoad(); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/view/SlothRecycler.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.view; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.GridLayoutManager; 5 | import android.support.v7.widget.LinearLayoutManager; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.util.AttributeSet; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.ProgressBar; 12 | import android.widget.TextView; 13 | 14 | import java.util.List; 15 | 16 | import xyz.ibat.sloth.R; 17 | 18 | /** 19 | * Created by DongJr on 2016/4/6. 20 | */ 21 | public class SlothRecycler extends RecyclerView { 22 | 23 | private boolean mIsLoading = false; 24 | private OnLoadListener mOnLoadListener; 25 | private int mLastVisiblePosition; 26 | 27 | private View mFootView; 28 | private ProgressBar mProgress; 29 | private TextView mTextView; 30 | 31 | public SlothRecycler(Context context) { 32 | super(context); 33 | init(context); 34 | } 35 | 36 | public SlothRecycler(Context context, AttributeSet attrs) { 37 | super(context, attrs); 38 | init(context); 39 | } 40 | 41 | public SlothRecycler(Context context, AttributeSet attrs, int defStyle) { 42 | super(context, attrs, defStyle); 43 | init(context); 44 | } 45 | 46 | public enum LoadState { 47 | ONLOADING, 48 | NOMORE 49 | } 50 | 51 | public void setLoadState(LoadState loadState) { 52 | switch (loadState) { 53 | case ONLOADING: 54 | mTextView.setText("正在刷新"); 55 | mProgress.setVisibility(VISIBLE); 56 | break; 57 | case NOMORE: 58 | mTextView.setText("没有更多了"); 59 | mProgress.setVisibility(GONE); 60 | break; 61 | 62 | } 63 | } 64 | 65 | 66 | private void init(Context context) { 67 | mFootView = View.inflate(context, R.layout.item_refresh_foot, null); 68 | mProgress = (ProgressBar) mFootView.findViewById(R.id.load_progress); 69 | mTextView = (TextView) mFootView.findViewById(R.id.loadmore_text); 70 | addOnScrollListener(new OnScrollListener() { 71 | @Override 72 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 73 | super.onScrolled(recyclerView, dx, dy); 74 | } 75 | 76 | @Override 77 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 78 | super.onScrollStateChanged(recyclerView, newState); 79 | LayoutManager layoutManager = recyclerView.getLayoutManager(); 80 | if (!mIsLoading && getLastVisiblePosition() == layoutManager.getItemCount() - 1 81 | && newState == RecyclerView.SCROLL_STATE_IDLE) { 82 | loadData(); 83 | mIsLoading = false; 84 | } 85 | 86 | } 87 | }); 88 | } 89 | 90 | public int getLastVisiblePosition() { 91 | int totalItemCount = getLayoutManager().getItemCount(); 92 | if (getLayoutManager() instanceof LinearLayoutManager) { 93 | mLastVisiblePosition = ((LinearLayoutManager) getLayoutManager()).findLastVisibleItemPosition(); 94 | } else if (getLayoutManager() instanceof GridLayoutManager) { 95 | mLastVisiblePosition = ((GridLayoutManager) getLayoutManager()).findLastVisibleItemPosition(); 96 | } else { 97 | mLastVisiblePosition = totalItemCount - 1; 98 | } 99 | return mLastVisiblePosition; 100 | } 101 | 102 | private void loadData() { 103 | if (mOnLoadListener != null) { 104 | setOnLoading(true); 105 | mOnLoadListener.onLoad(); 106 | } 107 | } 108 | 109 | public void setOnLoading(boolean isLoading) { 110 | mIsLoading = isLoading; 111 | 112 | } 113 | 114 | public void setOnLoadListener(OnLoadListener onLoadListener) { 115 | mOnLoadListener = onLoadListener; 116 | } 117 | 118 | public interface OnLoadListener { 119 | void onLoad(); 120 | } 121 | 122 | 123 | public static abstract class LoadMoreAdaper extends RecyclerView.Adapter { 124 | private Context context; 125 | private List list; 126 | 127 | public LoadMoreAdaper(Context context, List list) { 128 | this.context = context; 129 | this.list = list; 130 | } 131 | 132 | @Override 133 | public int getItemViewType(int position) { 134 | if (position == list.size()) { 135 | return 0; 136 | } else { 137 | return getItemType(); 138 | } 139 | } 140 | 141 | public int getItemType() { 142 | return 1; 143 | } 144 | 145 | @Override 146 | public int getItemCount() { 147 | return list.size() + 1; 148 | } 149 | 150 | @Override 151 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 152 | if (viewType == 0) { 153 | View footView = LayoutInflater.from(context).inflate(R.layout.item_refresh_foot, parent, false); 154 | return new FootHolder(footView); 155 | } else { 156 | return onCreateHolder(parent, viewType); 157 | } 158 | } 159 | 160 | public abstract RecyclerView.ViewHolder onCreateHolder(ViewGroup parent, int viewType); 161 | 162 | @Override 163 | public abstract void onBindViewHolder(RecyclerView.ViewHolder holder, int position); 164 | 165 | 166 | } 167 | 168 | static class FootHolder extends RecyclerView.ViewHolder { 169 | 170 | public FootHolder(View itemView) { 171 | super(itemView); 172 | } 173 | 174 | } 175 | } -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/view/behavior/BottomScrollBehavior.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.view.behavior; 2 | 3 | import android.animation.Animator; 4 | import android.content.Context; 5 | import android.support.design.widget.CoordinatorLayout; 6 | import android.support.v4.view.ViewCompat; 7 | import android.util.AttributeSet; 8 | import android.util.Log; 9 | import android.view.View; 10 | import android.view.ViewPropertyAnimator; 11 | import android.view.animation.AccelerateDecelerateInterpolator; 12 | import android.view.animation.Interpolator; 13 | 14 | /** 15 | * Created by DongJr on 2016/5/4. 16 | */ 17 | public class BottomScrollBehavior extends CoordinatorLayout.Behavior { 18 | 19 | int offsetTotal = 0; 20 | 21 | private static final Interpolator INTERPOLATOR = new AccelerateDecelerateInterpolator(); 22 | 23 | 24 | private int sinceDirectionChange; 25 | private int hideHeight = 0; 26 | 27 | public BottomScrollBehavior(Context context, AttributeSet attrs){ 28 | super(context,attrs); 29 | } 30 | 31 | @Override 32 | public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) { 33 | return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0; 34 | } 35 | 36 | @Override 37 | public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) { 38 | Log.e("behavior",dyConsumed+"===========dyConsumed==============="); 39 | //dy>0 向上滑 else 向下滑 40 | if (dyConsumed > 0 && sinceDirectionChange < 0 || dyConsumed < 0 && sinceDirectionChange > 0) { 41 | child.animate().cancel(); 42 | sinceDirectionChange = 0; 43 | } 44 | sinceDirectionChange += dyConsumed; 45 | if (sinceDirectionChange > child.getHeight()) { 46 | hide(child); 47 | } else if (sinceDirectionChange < 0 ) { 48 | show(child); 49 | } 50 | } 51 | 52 | @Override 53 | public boolean onNestedFling(CoordinatorLayout coordinatorLayout, View child, View target, float velocityX, float velocityY, boolean consumed) { 54 | //当快速滑动 55 | return super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed); 56 | } 57 | 58 | private void hide(final View view) { 59 | hideHeight = view.getHeight(); 60 | ViewPropertyAnimator animator = view.animate().translationY(hideHeight) 61 | .setInterpolator(INTERPOLATOR).setDuration(400); 62 | animator.setListener(new Animator.AnimatorListener() { 63 | @Override 64 | public void onAnimationStart(Animator animator) { 65 | 66 | } 67 | 68 | @Override 69 | public void onAnimationEnd(Animator animator) { 70 | // view.setVisibility(View.INVISIBLE); 71 | } 72 | 73 | @Override 74 | public void onAnimationCancel(Animator animator) { 75 | show(view); 76 | } 77 | 78 | @Override 79 | public void onAnimationRepeat(Animator animator) { 80 | 81 | } 82 | }); 83 | animator.start(); 84 | } 85 | 86 | 87 | private void show(final View view) { 88 | ViewPropertyAnimator animator = view.animate().translationY(0) 89 | .setInterpolator(INTERPOLATOR).setDuration(400); 90 | animator.setListener(new Animator.AnimatorListener() { 91 | @Override 92 | public void onAnimationStart(Animator animator) { 93 | 94 | } 95 | 96 | @Override 97 | public void onAnimationEnd(Animator animator) { 98 | // view.setVisibility(View.VISIBLE); 99 | } 100 | 101 | @Override 102 | public void onAnimationCancel(Animator animator) { 103 | hide(view); 104 | } 105 | 106 | @Override 107 | public void onAnimationRepeat(Animator animator) { 108 | 109 | } 110 | }); 111 | animator.start(); 112 | 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/view/behavior/FABScrollBehavior.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.view.behavior; 2 | 3 | import android.animation.Animator; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.util.Log; 6 | import android.view.View; 7 | import android.view.ViewPropertyAnimator; 8 | import android.view.animation.AccelerateDecelerateInterpolator; 9 | import android.view.animation.Interpolator; 10 | 11 | import xyz.ibat.sloth.utils.DensityUtil; 12 | 13 | /** 14 | * Created by DongJr on 2016/5/4. 15 | */ 16 | public class FABScrollBehavior extends RecyclerView.OnScrollListener { 17 | 18 | int offsetTotal = 0; 19 | 20 | private static final Interpolator INTERPOLATOR = new AccelerateDecelerateInterpolator(); 21 | 22 | private int mState; 23 | private int sinceDirectionChange; 24 | private int hideHeight = 0; 25 | 26 | private View innerView; 27 | 28 | public FABScrollBehavior(View innerView){ 29 | this.innerView = innerView; 30 | } 31 | 32 | 33 | @Override 34 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 35 | if (mState != RecyclerView.SCROLL_STATE_DRAGGING){ 36 | return; 37 | } 38 | Log.e("behavior",dy+"===========dy==============="); 39 | 40 | //dy>0 向上滑 else 向下滑 41 | if (dy > 0 && sinceDirectionChange < 0 || dy < 0 && sinceDirectionChange > 0) { 42 | innerView.animate().cancel(); 43 | sinceDirectionChange = 0; 44 | } 45 | sinceDirectionChange += dy; 46 | if (sinceDirectionChange > DensityUtil.dp2px(46)) { 47 | hide(innerView); 48 | } else if (sinceDirectionChange < 0 ) { 49 | show(innerView); 50 | } 51 | } 52 | 53 | @Override 54 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 55 | mState = newState; 56 | } 57 | 58 | private void hide(final View view) { 59 | hideHeight = view.getBottom(); 60 | ViewPropertyAnimator animator = view.animate().translationY(hideHeight) 61 | .setInterpolator(INTERPOLATOR).setDuration(400); 62 | animator.setListener(new Animator.AnimatorListener() { 63 | @Override 64 | public void onAnimationStart(Animator animator) { 65 | 66 | } 67 | 68 | @Override 69 | public void onAnimationEnd(Animator animator) { 70 | // view.setVisibility(View.INVISIBLE); 71 | } 72 | 73 | @Override 74 | public void onAnimationCancel(Animator animator) { 75 | show(view); 76 | } 77 | 78 | @Override 79 | public void onAnimationRepeat(Animator animator) { 80 | 81 | } 82 | }); 83 | animator.start(); 84 | } 85 | 86 | 87 | private void show(final View view) { 88 | ViewPropertyAnimator animator = view.animate().translationY(0) 89 | .setInterpolator(INTERPOLATOR).setDuration(400); 90 | animator.setListener(new Animator.AnimatorListener() { 91 | @Override 92 | public void onAnimationStart(Animator animator) { 93 | 94 | } 95 | 96 | @Override 97 | public void onAnimationEnd(Animator animator) { 98 | // view.setVisibility(View.VISIBLE); 99 | } 100 | 101 | @Override 102 | public void onAnimationCancel(Animator animator) { 103 | hide(view); 104 | } 105 | 106 | @Override 107 | public void onAnimationRepeat(Animator animator) { 108 | 109 | } 110 | }); 111 | animator.start(); 112 | 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/view/behavior/FollowBehavior.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.view.behavior; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.support.design.widget.CoordinatorLayout; 6 | import android.util.AttributeSet; 7 | import android.view.View; 8 | 9 | import xyz.ibat.sloth.R; 10 | 11 | /** 12 | * Created by DongJr on 2016/5/4. 13 | */ 14 | public class FollowBehavior extends CoordinatorLayout.Behavior { 15 | 16 | private int targetId; 17 | 18 | public FollowBehavior(Context context, AttributeSet attrs){ 19 | super(context,attrs); 20 | //AttributeSet和TypedArray区别。都可以获取属性值,但TypedArray更方便些,如果属性引用了 21 | //values文件下的值,用AttributeSet拿到的是属性id,但TypedArray可以获得具体的值 22 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FollowBehavior); 23 | for (int i = 0; i < a.getIndexCount(); i++) { 24 | int attr = a.getIndex(i); 25 | if(a.getIndex(i) == R.styleable.FollowBehavior_target){ 26 | targetId = a.getResourceId(attr, -1); 27 | } 28 | } 29 | a.recycle(); 30 | } 31 | 32 | //确定依赖哪个view 33 | @Override 34 | public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) { 35 | return dependency.getId() == targetId; 36 | } 37 | 38 | //child 是指应用behavior的View ,dependency 担任触发behavior的角色,其实就是上面依赖的view,并与child进行互动。 39 | //确定你是否依赖于这个View。CoordinatorLayout会将自己所有View遍历判断。 40 | //如果确定依赖。这个方法很重要。当所依赖的View变动时会回调这个方法。 41 | @Override 42 | public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) { 43 | child.setY(dependency.getY()+dependency.getHeight()); 44 | return true; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/view/behavior/ScrollBehavior.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.view.behavior; 2 | 3 | import android.content.Context; 4 | import android.support.design.widget.CoordinatorLayout; 5 | import android.util.AttributeSet; 6 | import android.util.Log; 7 | import android.view.View; 8 | 9 | /** 10 | * Created by DongJr on 2016/5/4. 11 | */ 12 | public class ScrollBehavior extends CoordinatorLayout.Behavior { 13 | 14 | int offsetTotal = 0; 15 | 16 | public ScrollBehavior(Context context, AttributeSet attrs){ 17 | super(context,attrs); 18 | } 19 | 20 | @Override 21 | public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) { 22 | //nestedScrollAxes滑动方向 23 | return true; 24 | } 25 | 26 | @Override 27 | public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) { 28 | //滑动事件处理 29 | onScroll(child,dyConsumed); 30 | Log.e("behavior","=============dtConsumed======="+dyConsumed); 31 | Log.e("behavior","=============dtUnConsumed======="+dyUnconsumed); 32 | } 33 | 34 | private void onScroll(View child, int dyConsumed) { 35 | int old = offsetTotal; 36 | int top = offsetTotal - dyConsumed; 37 | top = Math.max(top, -child.getHeight()); 38 | top = Math.min(top, 0); 39 | offsetTotal = top; 40 | if (old == offsetTotal){ 41 | return; 42 | } 43 | int delta = offsetTotal-old; 44 | child.offsetTopAndBottom(delta); 45 | // int top = -dyConsumed; 46 | // top = Math.min(top,child.getHeight()); 47 | // child.offsetTopAndBottom(top); 48 | } 49 | 50 | 51 | @Override 52 | public boolean onNestedFling(CoordinatorLayout coordinatorLayout, View child, View target, float velocityX, float velocityY, boolean consumed) { 53 | //当快速滑动 54 | return super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/xyz/ibat/sloth/view/picasso/CircleTransform.java: -------------------------------------------------------------------------------- 1 | package xyz.ibat.sloth.view.picasso; 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.squareup.picasso.Transformation; 10 | 11 | /** 12 | * Created by DongJr on 2017/1/17. 13 | */ 14 | 15 | public class CircleTransform implements Transformation { 16 | 17 | private Context context; 18 | 19 | public CircleTransform(Context context) { 20 | this.context = context; 21 | } 22 | 23 | @Override 24 | public Bitmap transform(Bitmap source) { 25 | int size = Math.min(source.getWidth(), source.getHeight()); 26 | int x = (source.getWidth() - size) / 2; 27 | int y = (source.getHeight() - size) / 2; 28 | Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size); 29 | if (squaredBitmap != source) { 30 | source.recycle(); 31 | } 32 | Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig()); 33 | Canvas canvas = new Canvas(bitmap); 34 | Paint paint = new Paint(); 35 | BitmapShader shader = new BitmapShader(squaredBitmap, 36 | BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP); 37 | paint.setShader(shader); 38 | paint.setAntiAlias(true); 39 | paint.setStyle(Paint.Style.FILL); 40 | float r = size / 2f; 41 | canvas.drawCircle(r, r, r, paint); 42 | squaredBitmap.recycle(); 43 | return bitmap; 44 | } 45 | 46 | @Override 47 | public String key() { 48 | return "circle"; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/info_tab_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/loadfail_btn_bg_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_tab_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/map_tab_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/mine_tab_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/progress_animation.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/progressbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tab_text_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/webview_progress_bar_states.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_base.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_friend.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 17 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_image_preview.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_meizi.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_message.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 15 | 16 | 28 | 29 | 38 | 39 | 46 | 47 | 48 | 49 | 50 | 51 | 55 | 56 | 61 | 62 | 68 | 74 | 75 | 80 | 81 | 85 | 86 | 87 | 88 | 89 | 96 | 102 | 103 | 108 | 109 | 113 | 114 | 115 | 116 | 117 | 124 | 130 | 131 | 136 | 137 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 158 | 159 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_web.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 14 | 19 | 20 | 23 | 24 | 28 | 29 | 30 | 31 | 40 | 41 | 46 | 47 | 53 | 54 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /app/src/main/res/layout/common_toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/default_loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_base.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_one.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | 19 | 20 | 21 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_tab.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 13 | 14 | 15 | 16 | 23 | 24 | 28 | 29 | 35 | 36 | 46 | 47 | 57 | 58 | 68 | 69 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_tab_info.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 20 | 21 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_tab_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 16 | 17 | 18 | 23 | 24 | 31 | 32 | 37 | 38 | 39 | 40 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_tab_map.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 19 | 20 | 23 | 24 | 28 | 29 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_tab_mine.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 15 | 16 | 28 | 29 | 35 | 36 | 43 | 44 | 45 | 46 | 57 | 58 | 59 | 60 | 61 | 62 | 66 | 67 | 71 | 72 | 82 | 83 | 92 | 93 | 103 | 104 | 115 | 116 | 126 | 127 | 138 | 139 | 148 | 149 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_web.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 25 | 26 | 31 | 32 | 35 | 36 | 40 | 41 | 42 | 43 | 52 | 53 | 58 | 59 | 65 | 66 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_fragment_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 19 | 20 | 31 | 32 | 44 | 45 | 46 | 52 | 53 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_meizi.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_refresh_foot.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/navigationview_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 18 | 19 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_drawer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 13 | 17 | 21 | 22 | 23 | 24 | 25 | 29 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 9 | 13 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/banner2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-hdpi/banner2.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-hdpi/ic_dashboard.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_discuss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-hdpi/ic_discuss.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_done.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-hdpi/ic_done.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_event.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-hdpi/ic_event.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_forum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-hdpi/ic_forum.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_headset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-hdpi/ic_headset.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-hdpi/ic_menu.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_toolbar_drawer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-hdpi/ic_toolbar_drawer.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_toolbar_drawer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-xhdpi/ic_toolbar_drawer.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/icon_arrow_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-xhdpi/icon_arrow_back.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/icon_head.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-xhdpi/icon_head.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/icon_info_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-xhdpi/icon_info_default.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/icon_info_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-xhdpi/icon_info_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/icon_load_failed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-xhdpi/icon_load_failed.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/icon_main_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-xhdpi/icon_main_default.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/icon_main_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-xhdpi/icon_main_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/icon_map_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-xhdpi/icon_map_default.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/icon_map_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-xhdpi/icon_map_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/icon_mine_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-xhdpi/icon_mine_default.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/icon_mine_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-xhdpi/icon_mine_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/icon_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-xhdpi/icon_search.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/icon_search_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-xhdpi/icon_search_white.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/icon_share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-xhdpi/icon_share.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_toolbar_drawer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-xxhdpi/ic_toolbar_drawer.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/transition/explode.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/transition/fade.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/transition/slide.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #2196F3 4 | #1976D2 5 | #FF4081 6 | #ffffff 7 | #00000000 8 | #66ffffff 9 | #000000 10 | #66000000 11 | #f2f2f2 12 | #333333 13 | 14 | 15 | #999999 16 | #5EDDCA 17 | #eaeaea 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | 7 | 14sp 8 | 24sp 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Sloth 3 | Settings 4 | About 5 | 搜索 6 | 分享 7 | 8 | 9 | Hello blank fragment 10 | 首页 11 | 地图 12 | 咨询 13 | 我的 14 | 15 | 松开刷新 16 | 刷新中... 17 | 上次更新时间: 18 | 查看更多 19 | 下拉刷新 20 | 加载中 21 | 22 | 网络不给力哦 23 | 24 | \t\t这是用于Android学习的一个项目,里面的内容包括 25 | ,RxJava,Retroft,,Picasso,WebView预览图片,图片预览放大、缩小、移动,Material Design控件使用,activity酷炫切换动画等 26 | .目前代码结构还不是很好,以后会慢慢重构.有新的技术也会不断往项目里面添加.希望能通过这个项目技术有一定得提升 27 | 28 | \t\t项目用到了代码家的 gank.io 的api接口,还有张鸿洋的baseadapter等,鸿洋的博客( zhanghongyang.com )是我在刚接触android的时候就 29 | 一直在看的 , 学到了很多东西 . 感谢一直在为开源做贡献的人们 . 30 | 31 | \t\t附上我的博客: ibat.xyz .里面内容很少,但希望能坚持写下去 32 | \t\t邮箱:idongjr@gmail.com 33 | Please do not see me off.The journey I am walking on alone is lonely and dangerous. 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 16 | 17 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /baseadapter-recyclerview/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /baseadapter-recyclerview/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | //apply plugin: 'com.novoda.bintray-release' 3 | 4 | android { 5 | compileSdkVersion 23 6 | buildToolsVersion "23.0.1" 7 | 8 | defaultConfig { 9 | minSdkVersion 10 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | dependencies { 22 | compile fileTree(dir: 'libs', include: ['*.jar']) 23 | testCompile 'junit:junit:4.12' 24 | compile 'com.android.support:recyclerview-v7:23.4.0' 25 | } 26 | 27 | //publish { 28 | // userOrg = 'hongyangandroid' 29 | // groupId = 'com.zhy' 30 | // artifactId = 'base-rvadapter' 31 | // publishVersion = '3.0.3' 32 | // desc = 'a easy adapter for recyclerview' 33 | // website = 'https://github.com/hongyangAndroid/baseAdapter' 34 | // licences = ['Apache-2.0'] 35 | //} 36 | -------------------------------------------------------------------------------- /baseadapter-recyclerview/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 /Users/zhy/android/sdk/android-sdk-macosx/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 | -------------------------------------------------------------------------------- /baseadapter-recyclerview/src/androidTest/java/com/zhy/baseadapter_recyclerview/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.zhy.baseadapter_recyclerview; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase 10 | { 11 | public ApplicationTest() 12 | { 13 | super(Application.class); 14 | } 15 | } -------------------------------------------------------------------------------- /baseadapter-recyclerview/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /baseadapter-recyclerview/src/main/java/com/zhy/adapter/recyclerview/CommonAdapter.java: -------------------------------------------------------------------------------- 1 | package com.zhy.adapter.recyclerview; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | 6 | import com.zhy.adapter.recyclerview.base.ItemViewDelegate; 7 | import com.zhy.adapter.recyclerview.base.ViewHolder; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * Created by zhy on 16/4/9. 13 | */ 14 | public abstract class CommonAdapter extends MultiItemTypeAdapter 15 | { 16 | protected Context mContext; 17 | protected int mLayoutId; 18 | protected List mDatas; 19 | protected LayoutInflater mInflater; 20 | 21 | public CommonAdapter(final Context context, final int layoutId, List datas) 22 | { 23 | super(context, datas); 24 | mContext = context; 25 | mInflater = LayoutInflater.from(context); 26 | mLayoutId = layoutId; 27 | mDatas = datas; 28 | 29 | addItemViewDelegate(new ItemViewDelegate() 30 | { 31 | @Override 32 | public int getItemViewLayoutId() 33 | { 34 | return layoutId; 35 | } 36 | 37 | @Override 38 | public boolean isForViewType( T item, int position) 39 | { 40 | return true; 41 | } 42 | 43 | @Override 44 | public void convert(ViewHolder holder, T t, int position) 45 | { 46 | CommonAdapter.this.convert(holder, t, position); 47 | } 48 | }); 49 | } 50 | 51 | protected abstract void convert(ViewHolder holder, T t, int position); 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /baseadapter-recyclerview/src/main/java/com/zhy/adapter/recyclerview/MultiItemTypeAdapter.java: -------------------------------------------------------------------------------- 1 | package com.zhy.adapter.recyclerview; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import com.zhy.adapter.recyclerview.base.ItemViewDelegate; 9 | import com.zhy.adapter.recyclerview.base.ItemViewDelegateManager; 10 | import com.zhy.adapter.recyclerview.base.ViewHolder; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * Created by zhy on 16/4/9. 16 | */ 17 | public class MultiItemTypeAdapter extends RecyclerView.Adapter { 18 | protected Context mContext; 19 | protected List mDatas; 20 | 21 | protected ItemViewDelegateManager mItemViewDelegateManager; 22 | protected OnItemClickListener mOnItemClickListener; 23 | 24 | 25 | public MultiItemTypeAdapter(Context context, List datas) { 26 | mContext = context; 27 | mDatas = datas; 28 | mItemViewDelegateManager = new ItemViewDelegateManager(); 29 | } 30 | 31 | @Override 32 | public int getItemViewType(int position) { 33 | if (!useItemViewDelegateManager()) return super.getItemViewType(position); 34 | return mItemViewDelegateManager.getItemViewType(mDatas.get(position), position); 35 | } 36 | 37 | 38 | @Override 39 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 40 | ItemViewDelegate itemViewDelegate = mItemViewDelegateManager.getItemViewDelegate(viewType); 41 | int layoutId = itemViewDelegate.getItemViewLayoutId(); 42 | ViewHolder holder = ViewHolder.createViewHolder(mContext, parent, layoutId); 43 | onViewHolderCreated(holder,holder.getConvertView()); 44 | setListener(parent, holder, viewType); 45 | return holder; 46 | } 47 | 48 | public void onViewHolderCreated(ViewHolder holder,View itemView){ 49 | 50 | } 51 | 52 | public void convert(ViewHolder holder, T t) { 53 | mItemViewDelegateManager.convert(holder, t, holder.getAdapterPosition()); 54 | } 55 | 56 | protected boolean isEnabled(int viewType) { 57 | return true; 58 | } 59 | 60 | 61 | protected void setListener(final ViewGroup parent, final ViewHolder viewHolder, int viewType) { 62 | if (!isEnabled(viewType)) return; 63 | viewHolder.getConvertView().setOnClickListener(new View.OnClickListener() { 64 | @Override 65 | public void onClick(View v) { 66 | if (mOnItemClickListener != null) { 67 | int position = viewHolder.getAdapterPosition(); 68 | mOnItemClickListener.onItemClick(v, viewHolder , position); 69 | } 70 | } 71 | }); 72 | 73 | viewHolder.getConvertView().setOnLongClickListener(new View.OnLongClickListener() { 74 | @Override 75 | public boolean onLongClick(View v) { 76 | if (mOnItemClickListener != null) { 77 | int position = viewHolder.getAdapterPosition(); 78 | return mOnItemClickListener.onItemLongClick(v, viewHolder, position); 79 | } 80 | return false; 81 | } 82 | }); 83 | } 84 | 85 | @Override 86 | public void onBindViewHolder(ViewHolder holder, int position) { 87 | convert(holder, mDatas.get(position)); 88 | } 89 | 90 | @Override 91 | public int getItemCount() { 92 | int itemCount = mDatas.size(); 93 | return itemCount; 94 | } 95 | 96 | 97 | public List getDatas() { 98 | return mDatas; 99 | } 100 | 101 | public MultiItemTypeAdapter addItemViewDelegate(ItemViewDelegate itemViewDelegate) { 102 | mItemViewDelegateManager.addDelegate(itemViewDelegate); 103 | return this; 104 | } 105 | 106 | public MultiItemTypeAdapter addItemViewDelegate(int viewType, ItemViewDelegate itemViewDelegate) { 107 | mItemViewDelegateManager.addDelegate(viewType, itemViewDelegate); 108 | return this; 109 | } 110 | 111 | protected boolean useItemViewDelegateManager() { 112 | return mItemViewDelegateManager.getItemViewDelegateCount() > 0; 113 | } 114 | 115 | public interface OnItemClickListener { 116 | void onItemClick(View view, RecyclerView.ViewHolder holder, int position); 117 | 118 | boolean onItemLongClick(View view, RecyclerView.ViewHolder holder, int position); 119 | } 120 | 121 | public void setOnItemClickListener(OnItemClickListener onItemClickListener) { 122 | this.mOnItemClickListener = onItemClickListener; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /baseadapter-recyclerview/src/main/java/com/zhy/adapter/recyclerview/base/ItemViewDelegate.java: -------------------------------------------------------------------------------- 1 | package com.zhy.adapter.recyclerview.base; 2 | 3 | 4 | import android.view.View; 5 | 6 | /** 7 | * Created by zhy on 16/6/22. 8 | */ 9 | public interface ItemViewDelegate 10 | { 11 | 12 | int getItemViewLayoutId(); 13 | 14 | boolean isForViewType(T item, int position); 15 | 16 | void convert(ViewHolder holder, T t, int position); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /baseadapter-recyclerview/src/main/java/com/zhy/adapter/recyclerview/base/ItemViewDelegateManager.java: -------------------------------------------------------------------------------- 1 | package com.zhy.adapter.recyclerview.base; 2 | 3 | import android.support.v4.util.SparseArrayCompat; 4 | 5 | 6 | /** 7 | * Created by zhy on 16/6/22. 8 | */ 9 | public class ItemViewDelegateManager 10 | { 11 | SparseArrayCompat> delegates = new SparseArrayCompat(); 12 | 13 | public int getItemViewDelegateCount() 14 | { 15 | return delegates.size(); 16 | } 17 | 18 | public ItemViewDelegateManager addDelegate(ItemViewDelegate delegate) 19 | { 20 | int viewType = delegates.size(); 21 | if (delegate != null) 22 | { 23 | delegates.put(viewType, delegate); 24 | viewType++; 25 | } 26 | return this; 27 | } 28 | 29 | public ItemViewDelegateManager addDelegate(int viewType, ItemViewDelegate delegate) 30 | { 31 | if (delegates.get(viewType) != null) 32 | { 33 | throw new IllegalArgumentException( 34 | "An ItemViewDelegate is already registered for the viewType = " 35 | + viewType 36 | + ". Already registered ItemViewDelegate is " 37 | + delegates.get(viewType)); 38 | } 39 | delegates.put(viewType, delegate); 40 | return this; 41 | } 42 | 43 | public ItemViewDelegateManager removeDelegate(ItemViewDelegate delegate) 44 | { 45 | if (delegate == null) 46 | { 47 | throw new NullPointerException("ItemViewDelegate is null"); 48 | } 49 | int indexToRemove = delegates.indexOfValue(delegate); 50 | 51 | if (indexToRemove >= 0) 52 | { 53 | delegates.removeAt(indexToRemove); 54 | } 55 | return this; 56 | } 57 | 58 | public ItemViewDelegateManager removeDelegate(int itemType) 59 | { 60 | int indexToRemove = delegates.indexOfKey(itemType); 61 | 62 | if (indexToRemove >= 0) 63 | { 64 | delegates.removeAt(indexToRemove); 65 | } 66 | return this; 67 | } 68 | 69 | public int getItemViewType(T item, int position) 70 | { 71 | int delegatesCount = delegates.size(); 72 | for (int i = delegatesCount - 1; i >= 0; i--) 73 | { 74 | ItemViewDelegate delegate = delegates.valueAt(i); 75 | if (delegate.isForViewType( item, position)) 76 | { 77 | return delegates.keyAt(i); 78 | } 79 | } 80 | throw new IllegalArgumentException( 81 | "No ItemViewDelegate added that matches position=" + position + " in data source"); 82 | } 83 | 84 | public void convert(ViewHolder holder, T item, int position) 85 | { 86 | int delegatesCount = delegates.size(); 87 | for (int i = 0; i < delegatesCount; i++) 88 | { 89 | ItemViewDelegate delegate = delegates.valueAt(i); 90 | 91 | if (delegate.isForViewType( item, position)) 92 | { 93 | delegate.convert(holder, item, position); 94 | return; 95 | } 96 | } 97 | throw new IllegalArgumentException( 98 | "No ItemViewDelegateManager added that matches position=" + position + " in data source"); 99 | } 100 | 101 | 102 | public ItemViewDelegate getItemViewDelegate(int viewType) 103 | { 104 | return delegates.get(viewType); 105 | } 106 | 107 | public int getItemViewLayoutId(int viewType) 108 | { 109 | return getItemViewDelegate(viewType).getItemViewLayoutId(); 110 | } 111 | 112 | public int getItemViewType(ItemViewDelegate itemViewDelegate) 113 | { 114 | return delegates.indexOfValue(itemViewDelegate); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /baseadapter-recyclerview/src/main/java/com/zhy/adapter/recyclerview/utils/WrapperUtils.java: -------------------------------------------------------------------------------- 1 | package com.zhy.adapter.recyclerview.utils; 2 | 3 | import android.support.v7.widget.GridLayoutManager; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.support.v7.widget.StaggeredGridLayoutManager; 6 | import android.view.ViewGroup; 7 | 8 | /** 9 | * Created by zhy on 16/6/28. 10 | */ 11 | public class WrapperUtils 12 | { 13 | public interface SpanSizeCallback 14 | { 15 | int getSpanSize(GridLayoutManager layoutManager , GridLayoutManager.SpanSizeLookup oldLookup, int position); 16 | } 17 | 18 | public static void onAttachedToRecyclerView(RecyclerView.Adapter innerAdapter, RecyclerView recyclerView, final SpanSizeCallback callback) 19 | { 20 | innerAdapter.onAttachedToRecyclerView(recyclerView); 21 | 22 | RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); 23 | if (layoutManager instanceof GridLayoutManager) 24 | { 25 | final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager; 26 | final GridLayoutManager.SpanSizeLookup spanSizeLookup = gridLayoutManager.getSpanSizeLookup(); 27 | 28 | gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() 29 | { 30 | @Override 31 | public int getSpanSize(int position) 32 | { 33 | return callback.getSpanSize(gridLayoutManager, spanSizeLookup, position); 34 | } 35 | }); 36 | gridLayoutManager.setSpanCount(gridLayoutManager.getSpanCount()); 37 | } 38 | } 39 | 40 | public static void setFullSpan(RecyclerView.ViewHolder holder) 41 | { 42 | ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); 43 | 44 | if (lp != null 45 | && lp instanceof StaggeredGridLayoutManager.LayoutParams) 46 | { 47 | 48 | StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp; 49 | 50 | p.setFullSpan(true); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /baseadapter-recyclerview/src/main/java/com/zhy/adapter/recyclerview/wrapper/EmptyWrapper.java: -------------------------------------------------------------------------------- 1 | package com.zhy.adapter.recyclerview.wrapper; 2 | 3 | import android.support.v7.widget.GridLayoutManager; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import com.zhy.adapter.recyclerview.base.ViewHolder; 9 | import com.zhy.adapter.recyclerview.utils.WrapperUtils; 10 | 11 | 12 | /** 13 | * Created by zhy on 16/6/23. 14 | */ 15 | public class EmptyWrapper extends RecyclerView.Adapter 16 | { 17 | public static final int ITEM_TYPE_EMPTY = Integer.MAX_VALUE - 1; 18 | 19 | private RecyclerView.Adapter mInnerAdapter; 20 | private View mEmptyView; 21 | private int mEmptyLayoutId; 22 | 23 | 24 | public EmptyWrapper(RecyclerView.Adapter adapter) 25 | { 26 | mInnerAdapter = adapter; 27 | } 28 | 29 | private boolean isEmpty() 30 | { 31 | return (mEmptyView != null || mEmptyLayoutId != 0) && mInnerAdapter.getItemCount() == 0; 32 | } 33 | 34 | @Override 35 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) 36 | { 37 | if (isEmpty()) 38 | { 39 | ViewHolder holder; 40 | if (mEmptyView != null) 41 | { 42 | holder = ViewHolder.createViewHolder(parent.getContext(), mEmptyView); 43 | } else 44 | { 45 | holder = ViewHolder.createViewHolder(parent.getContext(), parent, mEmptyLayoutId); 46 | } 47 | return holder; 48 | } 49 | return mInnerAdapter.onCreateViewHolder(parent, viewType); 50 | } 51 | 52 | @Override 53 | public void onAttachedToRecyclerView(RecyclerView recyclerView) 54 | { 55 | WrapperUtils.onAttachedToRecyclerView(mInnerAdapter, recyclerView, new WrapperUtils.SpanSizeCallback() 56 | { 57 | @Override 58 | public int getSpanSize(GridLayoutManager gridLayoutManager, GridLayoutManager.SpanSizeLookup oldLookup, int position) 59 | { 60 | if (isEmpty()) 61 | { 62 | return gridLayoutManager.getSpanCount(); 63 | } 64 | if (oldLookup != null) 65 | { 66 | return oldLookup.getSpanSize(position); 67 | } 68 | return 1; 69 | } 70 | }); 71 | 72 | 73 | } 74 | 75 | @Override 76 | public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) 77 | { 78 | mInnerAdapter.onViewAttachedToWindow(holder); 79 | if (isEmpty()) 80 | { 81 | WrapperUtils.setFullSpan(holder); 82 | } 83 | } 84 | 85 | 86 | @Override 87 | public int getItemViewType(int position) 88 | { 89 | if (isEmpty()) 90 | { 91 | return ITEM_TYPE_EMPTY; 92 | } 93 | return mInnerAdapter.getItemViewType(position); 94 | } 95 | 96 | @Override 97 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) 98 | { 99 | if (isEmpty()) 100 | { 101 | return; 102 | } 103 | mInnerAdapter.onBindViewHolder(holder, position); 104 | } 105 | 106 | @Override 107 | public int getItemCount() 108 | { 109 | if (isEmpty()) return 1; 110 | return mInnerAdapter.getItemCount(); 111 | } 112 | 113 | 114 | 115 | public void setEmptyView(View emptyView) 116 | { 117 | mEmptyView = emptyView; 118 | } 119 | 120 | public void setEmptyView(int layoutId) 121 | { 122 | mEmptyLayoutId = layoutId; 123 | } 124 | 125 | } 126 | -------------------------------------------------------------------------------- /baseadapter-recyclerview/src/main/java/com/zhy/adapter/recyclerview/wrapper/HeaderAndFooterWrapper.java: -------------------------------------------------------------------------------- 1 | package com.zhy.adapter.recyclerview.wrapper; 2 | 3 | import android.support.v4.util.SparseArrayCompat; 4 | import android.support.v7.widget.GridLayoutManager; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import com.zhy.adapter.recyclerview.base.ViewHolder; 10 | import com.zhy.adapter.recyclerview.utils.WrapperUtils; 11 | 12 | 13 | /** 14 | * Created by zhy on 16/6/23. 15 | */ 16 | public class HeaderAndFooterWrapper extends RecyclerView.Adapter 17 | { 18 | private static final int BASE_ITEM_TYPE_HEADER = 100000; 19 | private static final int BASE_ITEM_TYPE_FOOTER = 200000; 20 | 21 | private SparseArrayCompat mHeaderViews = new SparseArrayCompat<>(); 22 | private SparseArrayCompat mFootViews = new SparseArrayCompat<>(); 23 | 24 | private RecyclerView.Adapter mInnerAdapter; 25 | 26 | public HeaderAndFooterWrapper(RecyclerView.Adapter adapter) 27 | { 28 | mInnerAdapter = adapter; 29 | } 30 | 31 | @Override 32 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) 33 | { 34 | if (mHeaderViews.get(viewType) != null) 35 | { 36 | ViewHolder holder = ViewHolder.createViewHolder(parent.getContext(), mHeaderViews.get(viewType)); 37 | return holder; 38 | 39 | } else if (mFootViews.get(viewType) != null) 40 | { 41 | ViewHolder holder = ViewHolder.createViewHolder(parent.getContext(), mFootViews.get(viewType)); 42 | return holder; 43 | } 44 | return mInnerAdapter.onCreateViewHolder(parent, viewType); 45 | } 46 | 47 | @Override 48 | public int getItemViewType(int position) 49 | { 50 | if (isHeaderViewPos(position)) 51 | { 52 | return mHeaderViews.keyAt(position); 53 | } else if (isFooterViewPos(position)) 54 | { 55 | return mFootViews.keyAt(position - getHeadersCount() - getRealItemCount()); 56 | } 57 | return mInnerAdapter.getItemViewType(position - getHeadersCount()); 58 | } 59 | 60 | private int getRealItemCount() 61 | { 62 | return mInnerAdapter.getItemCount(); 63 | } 64 | 65 | 66 | @Override 67 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) 68 | { 69 | if (isHeaderViewPos(position)) 70 | { 71 | return; 72 | } 73 | if (isFooterViewPos(position)) 74 | { 75 | return; 76 | } 77 | mInnerAdapter.onBindViewHolder(holder, position - getHeadersCount()); 78 | } 79 | 80 | @Override 81 | public int getItemCount() 82 | { 83 | return getHeadersCount() + getFootersCount() + getRealItemCount(); 84 | } 85 | 86 | @Override 87 | public void onAttachedToRecyclerView(RecyclerView recyclerView) 88 | { 89 | WrapperUtils.onAttachedToRecyclerView(mInnerAdapter, recyclerView, new WrapperUtils.SpanSizeCallback() 90 | { 91 | @Override 92 | public int getSpanSize(GridLayoutManager layoutManager, GridLayoutManager.SpanSizeLookup oldLookup, int position) 93 | { 94 | int viewType = getItemViewType(position); 95 | if (mHeaderViews.get(viewType) != null) 96 | { 97 | return layoutManager.getSpanCount(); 98 | } else if (mFootViews.get(viewType) != null) 99 | { 100 | return layoutManager.getSpanCount(); 101 | } 102 | if (oldLookup != null) 103 | return oldLookup.getSpanSize(position); 104 | return 1; 105 | } 106 | }); 107 | } 108 | 109 | @Override 110 | public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) 111 | { 112 | mInnerAdapter.onViewAttachedToWindow(holder); 113 | int position = holder.getLayoutPosition(); 114 | if (isHeaderViewPos(position) || isFooterViewPos(position)) 115 | { 116 | WrapperUtils.setFullSpan(holder); 117 | } 118 | } 119 | 120 | private boolean isHeaderViewPos(int position) 121 | { 122 | return position < getHeadersCount(); 123 | } 124 | 125 | private boolean isFooterViewPos(int position) 126 | { 127 | return position >= getHeadersCount() + getRealItemCount(); 128 | } 129 | 130 | 131 | public void addHeaderView(View view) 132 | { 133 | mHeaderViews.put(mHeaderViews.size() + BASE_ITEM_TYPE_HEADER, view); 134 | } 135 | 136 | public void addFootView(View view) 137 | { 138 | mFootViews.put(mFootViews.size() + BASE_ITEM_TYPE_FOOTER, view); 139 | } 140 | 141 | public int getHeadersCount() 142 | { 143 | return mHeaderViews.size(); 144 | } 145 | 146 | public int getFootersCount() 147 | { 148 | return mFootViews.size(); 149 | } 150 | 151 | 152 | } 153 | -------------------------------------------------------------------------------- /baseadapter-recyclerview/src/main/java/com/zhy/adapter/recyclerview/wrapper/LoadMoreWrapper.java: -------------------------------------------------------------------------------- 1 | package com.zhy.adapter.recyclerview.wrapper; 2 | 3 | import android.support.v7.widget.GridLayoutManager; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.support.v7.widget.StaggeredGridLayoutManager; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import com.zhy.adapter.recyclerview.base.ViewHolder; 10 | import com.zhy.adapter.recyclerview.utils.WrapperUtils; 11 | 12 | /** 13 | * Created by DongJr on 2017/1/16. 14 | */ 15 | 16 | public class LoadMoreWrapper extends RecyclerView.Adapter { 17 | public static final int ITEM_TYPE_LOAD_MORE = Integer.MAX_VALUE - 2; 18 | 19 | private RecyclerView.Adapter mInnerAdapter; 20 | private View mLoadMoreView; 21 | private int mLoadMoreLayoutId; 22 | private boolean mShouldLoadMore = true; 23 | 24 | public LoadMoreWrapper(RecyclerView.Adapter adapter) { 25 | mInnerAdapter = adapter; 26 | } 27 | 28 | private boolean hasLoadMore() { 29 | return mLoadMoreView != null || mLoadMoreLayoutId != 0; 30 | } 31 | 32 | protected boolean isShowLoadMore(int position) { 33 | return hasLoadMore() && (position >= mInnerAdapter.getItemCount()); 34 | } 35 | 36 | @Override 37 | public int getItemViewType(int position) { 38 | if (isShowLoadMore(position)) { 39 | return ITEM_TYPE_LOAD_MORE; 40 | } 41 | return mInnerAdapter.getItemViewType(position); 42 | } 43 | 44 | @Override 45 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 46 | if (viewType == ITEM_TYPE_LOAD_MORE) { 47 | ViewHolder holder; 48 | if (mLoadMoreView != null) { 49 | holder = ViewHolder.createViewHolder(parent.getContext(), mLoadMoreView); 50 | } else { 51 | holder = ViewHolder.createViewHolder(parent.getContext(), parent, mLoadMoreLayoutId); 52 | } 53 | return holder; 54 | } 55 | return mInnerAdapter.onCreateViewHolder(parent, viewType); 56 | } 57 | 58 | @Override 59 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 60 | if (isShowLoadMore(position)) { 61 | if (mOnLoadMoreListener != null && mShouldLoadMore) { 62 | mOnLoadMoreListener.onLoadMoreRequested(); 63 | } 64 | return; 65 | } 66 | mInnerAdapter.onBindViewHolder(holder, position); 67 | } 68 | 69 | public void setShouldLoadMore(boolean shouldLoadMore) { 70 | this.mShouldLoadMore = shouldLoadMore; 71 | } 72 | 73 | @Override 74 | public void onAttachedToRecyclerView(RecyclerView recyclerView) { 75 | WrapperUtils.onAttachedToRecyclerView(mInnerAdapter, recyclerView, new WrapperUtils.SpanSizeCallback() { 76 | @Override 77 | public int getSpanSize(GridLayoutManager layoutManager, GridLayoutManager.SpanSizeLookup oldLookup, int position) { 78 | if (isShowLoadMore(position)) { 79 | return layoutManager.getSpanCount(); 80 | } 81 | if (oldLookup != null) { 82 | return oldLookup.getSpanSize(position); 83 | } 84 | return 1; 85 | } 86 | }); 87 | } 88 | 89 | 90 | @Override 91 | public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { 92 | mInnerAdapter.onViewAttachedToWindow(holder); 93 | 94 | if (isShowLoadMore(holder.getLayoutPosition())) { 95 | setFullSpan(holder); 96 | } 97 | } 98 | 99 | private void setFullSpan(RecyclerView.ViewHolder holder) { 100 | ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); 101 | 102 | if (lp != null 103 | && lp instanceof StaggeredGridLayoutManager.LayoutParams) { 104 | StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp; 105 | 106 | p.setFullSpan(true); 107 | } 108 | } 109 | 110 | @Override 111 | public int getItemCount() { 112 | if (mInnerAdapter.getItemCount()==0){ 113 | return 0; 114 | } 115 | return mInnerAdapter.getItemCount() + (hasLoadMore() ? 1 : 0); 116 | } 117 | 118 | 119 | public interface OnLoadMoreListener { 120 | void onLoadMoreRequested(); 121 | } 122 | 123 | private OnLoadMoreListener mOnLoadMoreListener; 124 | 125 | public com.zhy.adapter.recyclerview.wrapper.LoadMoreWrapper setOnLoadMoreListener(OnLoadMoreListener loadMoreListener) { 126 | if (loadMoreListener != null) { 127 | mOnLoadMoreListener = loadMoreListener; 128 | } 129 | return this; 130 | } 131 | 132 | public com.zhy.adapter.recyclerview.wrapper.LoadMoreWrapper setLoadMoreView(View loadMoreView) { 133 | mLoadMoreView = loadMoreView; 134 | return this; 135 | } 136 | 137 | public com.zhy.adapter.recyclerview.wrapper.LoadMoreWrapper setLoadMoreView(int layoutId) { 138 | mLoadMoreLayoutId = layoutId; 139 | return this; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /baseadapter-recyclerview/src/test/java/com/zhy/baseadapter_recyclerview/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.zhy.baseadapter_recyclerview; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest 11 | { 12 | @Test 13 | public void addition_isCorrect() throws Exception 14 | { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.3' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | ## Project-wide Gradle settings. 2 | # 3 | # For more details on how to configure your build environment visit 4 | # http://www.gradle.org/docs/current/userguide/build_environment.html 5 | # 6 | # Specifies the JVM arguments used for the daemon process. 7 | # The setting is particularly useful for tweaking memory settings. 8 | # Default value: -Xmx1024m -XX:MaxPermSize=256m 9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 10 | # 11 | # When configured, Gradle will run in incubating parallel mode. 12 | # This option should only be used with decoupled projects. More details, visit 13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 14 | # org.gradle.parallel=true 15 | #Thu Jan 05 20:46:19 CST 2017 16 | systemProp.http.proxyHost=127.0.0.1 17 | systemProp.http.proxyPort=1080 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Jan 14 19:16:27 CST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /image/sloth_drawerlayout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/image/sloth_drawerlayout.png -------------------------------------------------------------------------------- /image/sloth_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/image/sloth_home.png -------------------------------------------------------------------------------- /image/sloth_image_preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/image/sloth_image_preview.png -------------------------------------------------------------------------------- /image/sloth_me.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/image/sloth_me.png -------------------------------------------------------------------------------- /image/sloth_meizi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JrDong/Android-Material-Sloth/7dcad2a8a34c72db955034a55a8186cefbbfa4b5/image/sloth_meizi.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':baseadapter-recyclerview' 2 | --------------------------------------------------------------------------------