├── .gitignore
├── .idea
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── gradle.xml
├── misc.xml
├── modules.xml
└── runConfigurations.xml
├── Gank.iml
├── README.md
├── app
├── .gitignore
├── app.iml
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── jin
│ │ └── gank
│ │ └── ApplicationTest.java
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── jin
│ │ └── gank
│ │ ├── BaseActivity.java
│ │ ├── GankActivity.java
│ │ ├── MainActivity.java
│ │ ├── PictureActivity.java
│ │ ├── WebActivity.java
│ │ ├── adapter
│ │ ├── AnimRecyclerViewAdapter.java
│ │ └── GankListAdapter.java
│ │ ├── application
│ │ └── MyApplication.java
│ │ ├── data
│ │ ├── Constant.java
│ │ ├── DataBinder.java
│ │ ├── GankCategory.java
│ │ ├── GankDay.java
│ │ └── GankRandom.java
│ │ ├── decoration
│ │ ├── DividerGridItemDecoration.java
│ │ └── DividerLinearItemDecoration.java
│ │ ├── fragment
│ │ ├── GankFragment.java
│ │ ├── MyFragment.java
│ │ └── MyImgFragment.java
│ │ ├── network
│ │ ├── RESTApi.java
│ │ └── RetrofitHelp.java
│ │ ├── util
│ │ ├── DateUtils.java
│ │ ├── ImageUtils.java
│ │ ├── LoveStringUtils.java
│ │ ├── Once.java
│ │ ├── ShareUtils.java
│ │ ├── StringStyleUtils.java
│ │ ├── TaskUtils.java
│ │ └── ToastUtils.java
│ │ └── view
│ │ ├── GoodAppBarLayout.java
│ │ ├── LoveVideoView.java
│ │ ├── PLAImageView.java
│ │ ├── RatioImageView.java
│ │ └── VideoImageView.java
│ └── res
│ ├── anim
│ └── slide_in_right.xml
│ ├── drawable
│ ├── gride_divider.xml
│ └── line_divider.xml
│ ├── layout
│ ├── activity_gank.xml
│ ├── activity_main.xml
│ ├── activity_picture.xml
│ ├── activity_web.xml
│ ├── common_main_toolbar.xml
│ ├── common_toolbar.xml
│ ├── common_toolbar_with_indicator.xml
│ ├── common_toolbar_with_title_view.xml
│ ├── fragment_category.xml
│ ├── fragment_gank.xml
│ ├── fragment_img.xml
│ ├── item_category.xml
│ ├── item_gank.xml
│ ├── item_img.xml
│ ├── view_empty.xml
│ ├── view_more_progress.xml
│ └── view_video.xml
│ ├── menu
│ ├── menu_gank.xml
│ ├── menu_main.xml
│ └── menu_picture.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ ├── dropdown.png
│ ├── ic_launcher.png
│ ├── ic_play.png
│ └── ic_share_white_24dp.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── values-v21
│ └── styles.xml
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── android_material_design_colours.xml
│ ├── arrays.xml
│ ├── attrs.xml
│ ├── colors.xml
│ ├── dimens.xml
│ ├── ids.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── imgs
├── big.png
├── category.png
└── girl.png
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | /.gradle
2 | /local.properties
3 | /.idea
4 | /gradle
5 | /build
6 | /Gank.iml
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | 1.8
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Gank.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # gank
2 | 该项目是工作之余做得一个小项目 其中接口采用了干活集中营api开发 详情:http://gank.io/api 其中有些功能参考了https://github.com/drakeet/Meizhi项目
3 |
4 | 项目功能:提供各类开发所需的资料 包括开源项目的github地址
5 |
6 | 整体框架采用 lambda+retrofit+okhttp+rxandroid+Glide+DataBinding 并编写网络请求api 基本上符合material design设计
7 |
8 | 2015-08-25 新增ToolBar 和 TabLayout选项卡
9 |
10 | 2015-08-26 新增SuperRecyclerView瀑布流图片加载
11 |
12 | 2015-08-27 首页福利妹子图片加载模块功能完成 点击展示大图
13 |
14 | 2015-08-28 完成分类模块数据展示
15 |
16 | 2015-08-31 新增点击妹子item进入每日详情页面
17 |
18 | 2015-09-09 将Retrofit切换到2.0版本
19 |
20 | 2015-10-29 新增Android DataBinding
21 |
22 | 现在只完成了1.0版本 接下来有空还会添加新功能 如果你们有好的想法可以直接fork直接更新
23 |
24 | 下面直接上图
25 |
26 | 
27 | 
28 | 
29 |
30 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /app.iml
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | generateDebugSources
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'me.tatarka.retrolambda'//lambda表达式插件
3 | //apply plugin: 'jsonschema2pojo'
4 | //apply plugin: 'com.android.databinding'
5 | android {
6 | compileSdkVersion 23
7 | buildToolsVersion '23.0.3'
8 |
9 | defaultConfig {
10 | applicationId "com.jin.gank"
11 | minSdkVersion 14
12 | targetSdkVersion 23
13 | versionCode 1
14 | versionName "1.0"
15 | }
16 |
17 | dataBinding {
18 | enabled = true
19 | }
20 |
21 | buildTypes {
22 | release {
23 | minifyEnabled false
24 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
25 | }
26 | }
27 |
28 | compileOptions {
29 | sourceCompatibility JavaVersion.VERSION_1_8
30 | targetCompatibility JavaVersion.VERSION_1_8
31 | }
32 |
33 | packagingOptions {
34 | exclude 'META-INF/DEPENDENCIES.txt'
35 | exclude 'META-INF/LICENSE.txt'
36 | exclude 'META-INF/NOTICE.txt'
37 | exclude 'META-INF/NOTICE'
38 | exclude 'META-INF/LICENSE'
39 | exclude 'META-INF/DEPENDENCIES'
40 | exclude 'META-INF/notice.txt'
41 | exclude 'META-INF/license.txt'
42 | exclude 'META-INF/dependencies.txt'
43 | exclude 'META-INF/LGPL2.1'
44 | }
45 | }
46 |
47 | dependencies {
48 | compile fileTree(include: ['*.jar'], dir: 'libs')
49 | compile 'com.android.support:design:23.2.1'
50 | compile 'com.android.support:cardview-v7:23.2.1'
51 | //网络访问框架
52 | compile 'com.squareup.retrofit2:retrofit:2.0.0'
53 | compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0'
54 | compile 'com.squareup.retrofit2:converter-gson:2.0.0'
55 | //网络请求框架
56 | compile 'com.squareup.okhttp3:okhttp:3.2.0'
57 | compile 'com.squareup.okhttp3:okhttp-urlconnection:3.2.0'
58 | //响应式编程
59 | compile 'io.reactivex:rxandroid:1.0.1'
60 | //注解框架
61 | compile 'com.jakewharton:butterknife:7.0.1'
62 | //图片加载框架
63 | compile 'com.github.bumptech.glide:glide:3.6.1'
64 | //compile 'com.squareup.picasso:picasso:2.5.2'
65 | //一个高效的TabLayout库
66 | compile 'com.ogaclejapan.smarttablayout:library:1.3.0'
67 | //TabLayout帮助库
68 | compile 'com.ogaclejapan.smarttablayout:utils-v4:1.3.0@aar'
69 | //activity帮助类库
70 | compile 'com.vlonjatg.android:progress-activity:1.1.1'
71 | compile 'com.malinskiy:superrecyclerview:1.1.1'
72 | compile 'jp.wasabeef:recyclerview-animators:2.0.1'
73 | compile 'com.commit451:PhotoView:1.2.4'
74 | //进度条
75 | compile 'com.daimajia.numberprogressbar:library:1.2@aar'
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\Program Files (x86)\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/com/jin/gank/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.jin.gank;
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 |
10 |
11 |
12 |
18 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jin/gank/BaseActivity.java:
--------------------------------------------------------------------------------
1 | package com.jin.gank;
2 |
3 | import android.os.Bundle;
4 | import android.support.design.widget.AppBarLayout;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.support.v7.widget.Toolbar;
7 | import android.view.animation.DecelerateInterpolator;
8 |
9 | import butterknife.Bind;
10 | import butterknife.ButterKnife;
11 |
12 | /**
13 | * Created by Administrator on 2015/8/27.
14 | */
15 | public abstract class BaseActivity extends AppCompatActivity {
16 | public String[] getmCategoryArray() {
17 | return mCategoryArray;
18 | }
19 |
20 | private String[] mCategoryArray;
21 | @Bind(R.id.AppBarLayout)
22 | AppBarLayout mAppBarLayout;
23 | @Bind(R.id.common_toolbar)
24 | Toolbar mToolbar;
25 |
26 | protected boolean mIsHiddenToolBar = false;
27 |
28 | abstract protected int provideContentViewId();
29 |
30 | @Override
31 | public void onCreate(Bundle savedInstanceState) {
32 | super.onCreate(savedInstanceState);
33 | setContentView(provideContentViewId());
34 | mCategoryArray = getResources().getStringArray(R.array.category_list);
35 | ButterKnife.bind(this);
36 | setToolBar();
37 | }
38 |
39 | private void setToolBar() {
40 | if (null != mToolbar) {
41 | setSupportActionBar(mToolbar);
42 | getSupportActionBar().setHomeButtonEnabled(false);//决定左上角的图标是否可以点击
43 | getSupportActionBar().setDisplayHomeAsUpEnabled(false);//给左上角图标的左边加上一个返回的图标
44 | mToolbar.setTitle(R.string.app_name);
45 | }
46 | }
47 |
48 |
49 | protected void setAppBar(float alpha) {
50 | getSupportActionBar().setHomeButtonEnabled(true);//决定左上角的图标是否可以点击
51 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);//给左上角图标的左边加上一个返回的图标
52 | mAppBarLayout.setAlpha(alpha);
53 | mToolbar.setNavigationOnClickListener(v -> finish());
54 | }
55 |
56 | protected void hideOrShowToolbar() {
57 | mAppBarLayout.animate()
58 | .translationY(mIsHiddenToolBar ? 0 : -mAppBarLayout.getHeight())
59 | .setInterpolator(new DecelerateInterpolator(2))
60 | .start();
61 |
62 | mIsHiddenToolBar = !mIsHiddenToolBar;
63 | }
64 |
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jin/gank/GankActivity.java:
--------------------------------------------------------------------------------
1 | package com.jin.gank;
2 |
3 | import android.content.res.Configuration;
4 | import android.os.Bundle;
5 | import android.support.design.widget.TabLayout;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v4.app.FragmentManager;
8 | import android.support.v4.app.FragmentPagerAdapter;
9 | import android.support.v4.view.ViewPager;
10 | import android.view.Menu;
11 | import android.view.MenuItem;
12 | import android.view.View;
13 | import android.view.animation.DecelerateInterpolator;
14 |
15 | import com.jin.gank.fragment.GankFragment;
16 |
17 | import java.text.DateFormat;
18 | import java.text.SimpleDateFormat;
19 | import java.util.List;
20 |
21 | import butterknife.Bind;
22 | import butterknife.ButterKnife;
23 |
24 |
25 | public class GankActivity extends BaseActivity implements ViewPager.OnPageChangeListener {
26 | private static final String TAG = "GankActivity";
27 | public static final String EXTRA_GANK_DATA = "gank_data";
28 |
29 | @Bind(R.id.pager)
30 | ViewPager mViewPager;
31 | @Bind(R.id.tabLayout)
32 | TabLayout mTabLayout;
33 | GankPagerAdapter mPagerAdapter;
34 | List mDates;
35 |
36 |
37 | @Override
38 | protected int provideContentViewId() {
39 | return R.layout.activity_gank;
40 | }
41 |
42 |
43 | @Override
44 | public void onCreate(Bundle savedInstanceState) {
45 | super.onCreate(savedInstanceState);
46 | ButterKnife.bind(this);
47 | mDates = getIntent().getStringArrayListExtra(EXTRA_GANK_DATA);
48 |
49 | setTitle(mDates.get(0));
50 | setAppBar(1.0f);
51 | initViewPager();
52 | initTabLayout();
53 | }
54 |
55 | private void initViewPager() {
56 | mPagerAdapter = new GankPagerAdapter(getSupportFragmentManager(), mDates);
57 | mViewPager.setAdapter(mPagerAdapter);
58 | mViewPager.setOffscreenPageLimit(5);//缓存ViewPager页面数
59 | mViewPager.addOnPageChangeListener(this);
60 | }
61 |
62 | private void initTabLayout() {
63 | for (int i = 0; i < mPagerAdapter.getCount(); i++) {
64 | mTabLayout.addTab(mTabLayout.newTab());
65 | }
66 | mTabLayout.setupWithViewPager(mViewPager);
67 | }
68 |
69 | @Override
70 | public void onConfigurationChanged(Configuration newConfig) {
71 | super.onConfigurationChanged(newConfig);
72 | if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
73 | hideOrShowToolbar();
74 | } else {
75 | hideOrShowToolbar();
76 | }
77 | }
78 |
79 | @Override
80 | protected void hideOrShowToolbar() {
81 | View toolbar = findViewById(R.id.toolbar_with_indicator);
82 | toolbar.animate()
83 | .translationY(mIsHiddenToolBar ? 0 : -mToolbar.getHeight())
84 | .setInterpolator(new DecelerateInterpolator(2))
85 | .start();
86 | mIsHiddenToolBar = !mIsHiddenToolBar;
87 | if (mIsHiddenToolBar) {
88 | mViewPager.setTag(mViewPager.getPaddingTop());
89 | mViewPager.setPadding(0, 0, 0, 0);
90 | } else {
91 | mViewPager.setPadding(0, (int) mViewPager.getTag(), 0, 0);
92 | mViewPager.setTag(null);
93 | }
94 | }
95 |
96 |
97 | @Override
98 | public boolean onCreateOptionsMenu(Menu menu) {
99 | getMenuInflater().inflate(R.menu.menu_main, menu);
100 | return true;
101 | }
102 |
103 | @Override
104 | public boolean onOptionsItemSelected(MenuItem item) {
105 | int id = item.getItemId();
106 | switch (id) {
107 | case R.id.action_about:
108 | // startActivity(new Intent(this, AboutActivity.class));
109 | return true;
110 |
111 | }
112 | return super.onOptionsItemSelected(item);
113 | }
114 |
115 |
116 | @Override
117 | protected void onDestroy() {
118 | mViewPager.removeOnPageChangeListener(this);
119 | super.onDestroy();
120 | ButterKnife.unbind(this);
121 | }
122 |
123 | @Override
124 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
125 |
126 | }
127 |
128 | @Override
129 | public void onPageSelected(int position) {
130 | setTitle(mDates.get(position));
131 | }
132 |
133 | @Override
134 | public void onPageScrollStateChanged(int state) {
135 |
136 | }
137 |
138 | public class GankPagerAdapter extends FragmentPagerAdapter {
139 | List mDates;
140 | DateFormat dfm;
141 |
142 | public GankPagerAdapter(FragmentManager fm, List dates) {
143 | super(fm);
144 | mDates = dates;
145 | dfm = new SimpleDateFormat("yyyy-MM-dd");
146 | }
147 |
148 | @Override
149 | public Fragment getItem(int position) {
150 | String[] date = mDates.get(position).split("-");
151 | return GankFragment.newInstance(Integer.parseInt(date[0]), Integer.parseInt(date[1]), Integer.parseInt(date[2]));
152 | }
153 |
154 | @Override
155 | public int getCount() {
156 | return mDates.size();
157 | }
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jin/gank/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.jin.gank;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.view.ViewPager;
5 | import android.view.Menu;
6 | import android.view.MenuItem;
7 | import com.jin.gank.fragment.MyFragment;
8 | import com.jin.gank.fragment.MyImgFragment;
9 | import com.ogaclejapan.smarttablayout.SmartTabLayout;
10 | import com.ogaclejapan.smarttablayout.utils.v4.FragmentPagerItemAdapter;
11 | import com.ogaclejapan.smarttablayout.utils.v4.FragmentPagerItems;
12 |
13 | import butterknife.Bind;
14 | import butterknife.ButterKnife;
15 |
16 | public class MainActivity extends BaseActivity {
17 | private static final String TAG = "MainActivity";
18 | @Bind(R.id.smartTabLayout)
19 | SmartTabLayout mSmartTabLayout;
20 | @Bind(R.id.viewpager)
21 | ViewPager mViewpager;
22 |
23 |
24 | @Override
25 | protected int provideContentViewId() {
26 | return R.layout.activity_main;
27 | }
28 |
29 | @Override
30 | public void onCreate(Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 | ButterKnife.bind(this);
33 | FragmentPagerItemAdapter adapter = new FragmentPagerItemAdapter(
34 | getSupportFragmentManager(), FragmentPagerItems.with(this)
35 | .add(getmCategoryArray()[0], MyImgFragment.class)
36 | .add(getmCategoryArray()[1], MyFragment.class)
37 | .add(getmCategoryArray()[2], MyFragment.class)
38 | .add(getmCategoryArray()[3], MyFragment.class)
39 | .add(getmCategoryArray()[4], MyFragment.class)
40 | .add(getmCategoryArray()[5], MyFragment.class)
41 | .add(getmCategoryArray()[6], MyFragment.class)
42 | .create());
43 | mViewpager.setAdapter(adapter);
44 | mViewpager.setOffscreenPageLimit(adapter.getCount());//设置ViewPager缓存个数
45 | mSmartTabLayout.setViewPager(mViewpager);
46 | }
47 |
48 |
49 | @Override
50 | public boolean onCreateOptionsMenu(Menu menu) {
51 | getMenuInflater().inflate(R.menu.menu_main, menu);
52 | return true;
53 | }
54 |
55 | @Override
56 | public boolean onOptionsItemSelected(MenuItem item) {
57 | if (item.getItemId() == R.id.action_about) {
58 | return true;
59 | } else {
60 | return super.onOptionsItemSelected(item);
61 | }
62 | }
63 |
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jin/gank/PictureActivity.java:
--------------------------------------------------------------------------------
1 | package com.jin.gank;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.view.ViewCompat;
5 | import android.support.v7.app.AlertDialog;
6 | import android.view.Menu;
7 | import android.view.MenuItem;
8 | import android.widget.ImageView;
9 |
10 | import com.bumptech.glide.Glide;
11 | import com.jin.gank.util.ImageUtils;
12 | import com.jin.gank.util.ShareUtils;
13 |
14 | import butterknife.Bind;
15 | import butterknife.ButterKnife;
16 | import uk.co.senab.photoview.PhotoViewAttacher;
17 |
18 | public class PictureActivity extends BaseActivity {
19 |
20 | public static final String EXTRA_IMAGE_URL = "image_url";
21 | public static final String EXTRA_IMAGE_TITLE = "image_title";
22 | public static final String TRANSIT_PIC = "picture";
23 |
24 | @Bind(R.id.picture) ImageView mImageView;
25 |
26 | PhotoViewAttacher mPhotoViewAttacher;
27 | String mImageUrl, mImageTitle;
28 |
29 | private void parseIntent() {
30 | mImageUrl = getIntent().getStringExtra(EXTRA_IMAGE_URL);
31 | mImageTitle = getIntent().getStringExtra(EXTRA_IMAGE_TITLE);
32 | }
33 |
34 |
35 | @Override
36 | protected int provideContentViewId() {
37 | return R.layout.activity_picture;
38 | }
39 |
40 | @Override public void onCreate(Bundle savedInstanceState) {
41 | super.onCreate(savedInstanceState);
42 | ButterKnife.bind(this);
43 | parseIntent();
44 |
45 | // init image view
46 | ViewCompat.setTransitionName(mImageView, TRANSIT_PIC);
47 | Glide.with(this).load(mImageUrl).into(mImageView);
48 |
49 | setAppBar(0.7f);
50 | setTitle(mImageTitle);
51 |
52 | setUpPhotoAttacher();
53 | }
54 |
55 | private void setUpPhotoAttacher() {
56 | mPhotoViewAttacher = new PhotoViewAttacher(mImageView);
57 | mPhotoViewAttacher.setOnViewTapListener((view, v, v1) -> hideOrShowToolbar());
58 | mPhotoViewAttacher.setOnLongClickListener(v -> {
59 | new AlertDialog.Builder(PictureActivity.this).setMessage(
60 | getString(R.string.saving_picture))
61 | .setNegativeButton(android.R.string.cancel, (dialog, which) -> {
62 | dialog.dismiss();
63 | })
64 | .setPositiveButton(android.R.string.ok, (dialog, which) -> {
65 | saveImageToGallery();
66 | dialog.dismiss();
67 | })
68 | .show();
69 | return true;
70 | });
71 | }
72 |
73 | private void saveImageToGallery() {
74 | ImageUtils.saveImageToSdCard(this, mImageUrl, mImageTitle);
75 | }
76 |
77 | @Override public boolean onCreateOptionsMenu(Menu menu) {
78 | getMenuInflater().inflate(R.menu.menu_picture, menu);
79 | return true;
80 | }
81 |
82 | @Override public boolean onOptionsItemSelected(MenuItem item) {
83 | int id = item.getItemId();
84 | switch (id) {
85 | case R.id.action_share:
86 | ShareUtils.share(this);
87 | return true;
88 | }
89 |
90 | return super.onOptionsItemSelected(item);
91 | }
92 |
93 | @Override protected void onDestroy() {
94 | super.onDestroy();
95 | ButterKnife.unbind(this);
96 | }
97 |
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jin/gank/WebActivity.java:
--------------------------------------------------------------------------------
1 | package com.jin.gank;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 | import android.text.TextUtils;
6 | import android.view.KeyEvent;
7 | import android.webkit.WebChromeClient;
8 | import android.webkit.WebSettings;
9 | import android.webkit.WebView;
10 | import android.webkit.WebViewClient;
11 | import android.widget.TextSwitcher;
12 | import android.widget.TextView;
13 |
14 | import com.daimajia.numberprogressbar.NumberProgressBar;
15 |
16 | import butterknife.Bind;
17 | import butterknife.ButterKnife;
18 |
19 | public class WebActivity extends BaseActivity {
20 |
21 | public static final String EXTRA_URL = "extra_url";
22 | public static final String EXTRA_TITLE = "extra_title";
23 |
24 | @Bind(R.id.progressbar) NumberProgressBar mProgressbar;
25 | @Bind(R.id.webView) WebView mWebView;
26 | @Bind(R.id.tv_title) TextSwitcher mTextSwitcher;
27 |
28 | Context mContext;
29 | String mUrl, mTitle;
30 |
31 | @Override protected int provideContentViewId() {
32 | return R.layout.activity_web;
33 | }
34 |
35 |
36 |
37 | @Override public void onCreate(Bundle savedInstanceState) {
38 | super.onCreate(savedInstanceState);
39 | ButterKnife.bind(this);
40 | mContext = this;
41 | mUrl = getIntent().getStringExtra(EXTRA_URL);
42 | mTitle = getIntent().getStringExtra(EXTRA_TITLE);
43 | setAppBar(1.0f);
44 | WebSettings settings = mWebView.getSettings();
45 | settings.setJavaScriptEnabled(true);
46 | settings.setLoadWithOverviewMode(true);
47 | settings.setAppCacheEnabled(true);
48 | settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
49 | settings.setSupportZoom(true);
50 | mWebView.setWebChromeClient(new ChromeClient());
51 | mWebView.setWebViewClient(new LoveClient());
52 |
53 | mWebView.loadUrl(mUrl);
54 |
55 | mTextSwitcher.setFactory(() -> {
56 | TextView textView = new TextView(this);
57 | textView.setTextAppearance(this, R.style.WebTitle);
58 | textView.setSingleLine(true);
59 | textView.setEllipsize(TextUtils.TruncateAt.MARQUEE);
60 | textView.postDelayed(() -> textView.setSelected(true), 1738);
61 | return textView;
62 | });
63 | mTextSwitcher.setInAnimation(this, android.R.anim.fade_in);
64 | mTextSwitcher.setOutAnimation(this, android.R.anim.fade_out);
65 | if (mTitle != null) setTitle(mTitle);
66 | }
67 |
68 | @Override public void setTitle(CharSequence title) {
69 | super.setTitle(title);
70 | mTextSwitcher.setText(title);
71 | }
72 |
73 | @Override public boolean onKeyDown(int keyCode, KeyEvent event) {
74 | if (event.getAction() == KeyEvent.ACTION_DOWN) {
75 | switch (keyCode) {
76 | case KeyEvent.KEYCODE_BACK:
77 | if (mWebView.canGoBack()) {
78 | mWebView.goBack();
79 | }
80 | else {
81 | finish();
82 | }
83 | return true;
84 | }
85 | }
86 | return super.onKeyDown(keyCode, event);
87 | }
88 |
89 | @Override protected void onDestroy() {
90 | super.onDestroy();
91 | if (mWebView != null) mWebView.destroy();
92 | ButterKnife.unbind(this);
93 | }
94 |
95 | @Override protected void onPause() {
96 | if (mWebView != null) mWebView.onPause();
97 | super.onPause();
98 | }
99 |
100 | @Override protected void onResume() {
101 | super.onResume();
102 | if (mWebView != null) mWebView.onResume();
103 | }
104 |
105 | private class ChromeClient extends WebChromeClient {
106 |
107 | @Override public void onProgressChanged(WebView view, int newProgress) {
108 | super.onProgressChanged(view, newProgress);
109 | mProgressbar.setProgress(newProgress);
110 | }
111 |
112 | @Override public void onReceivedTitle(WebView view, String title) {
113 | super.onReceivedTitle(view, title);
114 | setTitle(title);
115 | }
116 | }
117 |
118 | private class LoveClient extends WebViewClient {
119 |
120 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
121 | if (url != null) view.loadUrl(url);
122 | return true;
123 | }
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jin/gank/adapter/AnimRecyclerViewAdapter.java:
--------------------------------------------------------------------------------
1 | package com.jin.gank.adapter;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.view.animation.Animation;
8 | import android.view.animation.AnimationUtils;
9 |
10 | import com.jin.gank.R;
11 |
12 |
13 |
14 | public class AnimRecyclerViewAdapter
15 | extends RecyclerView.Adapter {
16 |
17 | private static final int DELAY = 138;
18 | private int mLastPosition = -1;
19 |
20 | @Override public T onCreateViewHolder(ViewGroup parent, int viewType) {
21 | return null;
22 | }
23 |
24 | @Override public void onBindViewHolder(T holder, int position) {}
25 |
26 | @Override public int getItemCount() {return 0;}
27 |
28 | public void showItemAnim(final View view, final int position) {
29 | Context context = view.getContext();
30 | if (position > mLastPosition) {
31 | view.setAlpha(0);
32 | view.postDelayed(() -> {
33 | Animation animation = AnimationUtils.loadAnimation(context, R.anim.slide_in_right);
34 | animation.setAnimationListener(new Animation.AnimationListener() {
35 | @Override public void onAnimationStart(Animation animation) {
36 | view.setAlpha(1);
37 | }
38 |
39 | @Override public void onAnimationEnd(Animation animation) {}
40 |
41 | @Override public void onAnimationRepeat(Animation animation) {}
42 | });
43 | view.startAnimation(animation);
44 | }, DELAY * position);
45 | mLastPosition = position;
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jin/gank/adapter/GankListAdapter.java:
--------------------------------------------------------------------------------
1 | package com.jin.gank.adapter;
2 |
3 | import android.content.Intent;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.text.SpannableStringBuilder;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.TextView;
10 |
11 | import com.jin.gank.R;
12 | import com.jin.gank.WebActivity;
13 | import com.jin.gank.data.GankCategory;
14 | import com.jin.gank.util.StringStyleUtils;
15 |
16 | import java.util.List;
17 |
18 | import butterknife.Bind;
19 | import butterknife.ButterKnife;
20 | import butterknife.OnClick;
21 |
22 |
23 | public class GankListAdapter extends AnimRecyclerViewAdapter {
24 |
25 | private List mGankList;
26 |
27 | public GankListAdapter(List gankList) {
28 | mGankList = gankList;
29 | }
30 |
31 | @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
32 | View v =
33 | LayoutInflater.from(parent.getContext()).inflate(R.layout.item_gank, parent, false);
34 | return new ViewHolder(v);
35 | }
36 |
37 | @Override public void onBindViewHolder(ViewHolder holder, int position) {
38 | GankCategory.ResultsEntity gank = mGankList.get(position);
39 | if (position == 0) {
40 | showCategory(holder);
41 | }
42 | else {
43 | boolean doesLastAndThis =
44 | mGankList.get(position - 1).getType().equals(mGankList.get(position).getType());
45 | if (!doesLastAndThis) {
46 | showCategory(holder);
47 | }
48 | else if (holder.category.isShown()) holder.category.setVisibility(View.GONE);
49 | }
50 | holder.category.setText(gank.getType());
51 | if (holder.gank.getTag() == null) {
52 | SpannableStringBuilder builder = new SpannableStringBuilder(gank.getDesc()).append(
53 | StringStyleUtils.format(holder.gank.getContext(), " (via. " + gank.getWho() + ")",
54 | R.style.ViaTextAppearance));
55 | CharSequence gankText = builder.subSequence(0, builder.length());
56 | holder.gank.setTag(gankText);
57 | }
58 | CharSequence text = (CharSequence) holder.gank.getTag();
59 | holder.gank.setText(text);
60 | showItemAnim(holder.gank, position);
61 | }
62 |
63 | @Override public int getItemCount() {
64 | return mGankList.size();
65 | }
66 |
67 | private void showCategory(ViewHolder holder) {
68 | if (!holder.category.isShown()) holder.category.setVisibility(View.VISIBLE);
69 | }
70 |
71 | class ViewHolder extends RecyclerView.ViewHolder {
72 |
73 | @Bind(R.id.tv_category) TextView category;
74 | @Bind(R.id.tv_title) TextView gank;
75 |
76 | public ViewHolder(View itemView) {
77 | super(itemView);
78 | ButterKnife.bind(this, itemView);
79 | }
80 |
81 | @OnClick(R.id.ll_gank_parent) void onGank(View v) {
82 | GankCategory.ResultsEntity gank = mGankList.get(getLayoutPosition());
83 | Intent intent = new Intent(v.getContext(), WebActivity.class);
84 | intent.putExtra(WebActivity.EXTRA_TITLE, gank.getDesc());
85 | intent.putExtra(WebActivity.EXTRA_URL, gank.getUrl());
86 | v.getContext().startActivity(intent);
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jin/gank/application/MyApplication.java:
--------------------------------------------------------------------------------
1 | package com.jin.gank.application;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 |
6 | /**
7 | * Created by Administrator on 2015/8/31.
8 | */
9 | public class MyApplication extends Application {
10 | public static Context sContext;
11 | @Override
12 | public void onCreate() {
13 | super.onCreate();
14 | sContext = this;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jin/gank/data/Constant.java:
--------------------------------------------------------------------------------
1 | package com.jin.gank.data;
2 |
3 | /**
4 | * Created by Administrator on 2015/8/21.
5 | */
6 | public class Constant {
7 | public static final String ROOT_PATH = "http://gank.io/api/";
8 |
9 | public static final int API_COUNT = 10;
10 |
11 | public static final int VIEWPAGE_COUNT = 5;
12 |
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jin/gank/data/DataBinder.java:
--------------------------------------------------------------------------------
1 | package com.jin.gank.data;
2 |
3 | import android.content.Context;
4 | import android.databinding.BindingAdapter;
5 | import android.widget.ImageView;
6 |
7 | import com.bumptech.glide.Glide;
8 | import com.bumptech.glide.load.engine.DiskCacheStrategy;
9 |
10 | public final class DataBinder {
11 |
12 | private DataBinder() {
13 | //NO-OP
14 | }
15 |
16 | @BindingAdapter("imageUrl")
17 | public static void setImageUrl(ImageView imageView, String url) {
18 | Context context = imageView.getContext();
19 | Glide.with(context)
20 | .load(url)
21 | .centerCrop()
22 | .diskCacheStrategy(DiskCacheStrategy.ALL)
23 | .into(imageView);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jin/gank/data/GankCategory.java:
--------------------------------------------------------------------------------
1 | package com.jin.gank.data;
2 |
3 | import java.io.Serializable;
4 | import java.util.List;
5 |
6 | /**
7 | * Created by Administrator on 2015/8/24.
8 | */
9 | public class GankCategory {
10 |
11 | /**
12 | * error : false
13 | * results : [{"createdAt":"2015-08-24T03:53:33.486Z","publishedAt":"2015-08-24T04:06:07.602Z","used":true,"type":"休息视频","url":"http://v.youku.com/v_show/id_XMTMxMDA3MTEzNg==.html?from=s1.8-1-1.2","objectId":"55da953d00b04a634990f1c8","who":"代码家","desc":"从海龟鼻子里取出吸管儿(看的我要哭了","updatedAt":"2015-08-24T04:06:07.986Z"},{"createdAt":"2015-08-24T02:56:43.287Z","publishedAt":"2015-08-24T04:06:07.601Z","used":true,"type":"Android","url":"https://github.com/cesarferreira/dryrun","objectId":"55da87eb00b04a63498dee53","who":"mthli","desc":"快速尝试各种lib的demo","updatedAt":"2015-08-24T04:06:08.249Z"},{"createdAt":"2015-08-24T02:27:40.869Z","publishedAt":"2015-08-24T04:06:07.600Z","used":true,"type":"Android","url":"https://github.com/ashishb/android-security-awesome","objectId":"55da811c60b296e567e04ae4","who":"andyiac","desc":"一些android安全相关收集","updatedAt":"2015-08-24T04:06:07.992Z"},{"createdAt":"2015-08-24T02:26:06.138Z","publishedAt":"2015-08-24T04:06:07.600Z","used":true,"type":"Android","url":"https://github.com/PkmX/lcamera","objectId":"55da80be60b296e567e0364d","who":"mthli","desc":"一个使用新的Camera2 API的相机App","updatedAt":"2015-08-24T04:06:07.979Z"},{"createdAt":"2015-08-24T02:10:00.994Z","publishedAt":"2015-08-24T04:06:07.599Z","used":true,"type":"iOS","url":"https://github.com/likumb/SimpleMemo","objectId":"55da7cf800b04a63498b413f","who":"鲍永章","desc":"已上架的便签App源码,Swift编写,支持AppleWatch。","updatedAt":"2015-08-24T04:06:07.983Z"},{"createdAt":"2015-08-24T01:46:55.914Z","publishedAt":"2015-08-24T04:06:07.598Z","used":true,"type":"Android","url":"https://github.com/venmo/tooltip-view","objectId":"55da778f60b2ce30313cbcea","who":"有时放纵","desc":"一个android的工具提示view","updatedAt":"2015-08-24T04:06:07.995Z"},{"createdAt":"2015-08-24T01:37:37.406Z","publishedAt":"2015-08-24T04:06:07.597Z","used":true,"type":"Android","url":"http://zuimeia.com/app/3252/?category=15&platform=2","objectId":"55da756160b27e6c78cde002","who":"lxxself","desc":"设计师利器,安卓程序员好好学","updatedAt":"2015-08-24T04:06:07.996Z"},{"createdAt":"2015-08-24T01:39:50.174Z","publishedAt":"2015-08-24T04:06:07.597Z","used":true,"type":"Android","url":"https://github.com/hitherejoe/Android-Boilerplate","objectId":"55da75e600b05bb7664709ec","who":"有时放纵","desc":"一个用了Espresso和Robolectric的android样板","updatedAt":"2015-08-24T04:06:08.012Z"},{"createdAt":"2015-08-24T01:34:58.737Z","publishedAt":"2015-08-24T04:06:07.594Z","used":true,"type":"福利","url":"http://ww1.sinaimg.cn/large/7a8aed7bgw1evdga4dimoj20qo0hsmzf.jpg","objectId":"55da74c200b0a527148167f8","who":"张涵宇","desc":"8.24","updatedAt":"2015-08-24T04:06:08.796Z"},{"createdAt":"2015-08-23T13:18:19.102Z","publishedAt":"2015-08-24T04:06:07.593Z","used":true,"type":"拓展资源","url":"http://json.parser.online.fr/","objectId":"55d9c81b60b26a528474478e","who":"lxxself","desc":"Json Parser Online","updatedAt":"2015-08-24T04:06:08.010Z"}]
14 | */
15 | private boolean error;
16 | private List results;
17 |
18 | public void setError(boolean error) {
19 | this.error = error;
20 | }
21 |
22 | public void setResults(List results) {
23 | this.results = results;
24 | }
25 |
26 | public boolean isError() {
27 | return error;
28 | }
29 |
30 | public List getResults() {
31 | return results;
32 | }
33 |
34 | public static class ResultsEntity implements Serializable {
35 | /**
36 | * createdAt : 2015-08-24T03:53:33.486Z
37 | * publishedAt : 2015-08-24T04:06:07.602Z
38 | * used : true
39 | * type : 休息视频
40 | * url : http://v.youku.com/v_show/id_XMTMxMDA3MTEzNg==.html?from=s1.8-1-1.2
41 | * objectId : 55da953d00b04a634990f1c8
42 | * who : 代码家
43 | * desc : 从海龟鼻子里取出吸管儿(看的我要哭了
44 | * updatedAt : 2015-08-24T04:06:07.986Z
45 | */
46 | private String createdAt;
47 | private String publishedAt;
48 | private boolean used;
49 | private String type;
50 | private String url;
51 | private String objectId;
52 | private String who;
53 | private String desc;
54 | private String updatedAt;
55 |
56 | public void setCreatedAt(String createdAt) {
57 | this.createdAt = createdAt;
58 | }
59 |
60 | public void setPublishedAt(String publishedAt) {
61 | this.publishedAt = publishedAt;
62 | }
63 |
64 | public void setUsed(boolean used) {
65 | this.used = used;
66 | }
67 |
68 | public void setType(String type) {
69 | this.type = type;
70 | }
71 |
72 | public void setUrl(String url) {
73 | this.url = url;
74 | }
75 |
76 | public void setObjectId(String objectId) {
77 | this.objectId = objectId;
78 | }
79 |
80 | public void setWho(String who) {
81 | this.who = who;
82 | }
83 |
84 | public void setDesc(String desc) {
85 | this.desc = desc;
86 | }
87 |
88 | public void setUpdatedAt(String updatedAt) {
89 | this.updatedAt = updatedAt;
90 | }
91 |
92 | public String getCreatedAt() {
93 | return createdAt;
94 | }
95 |
96 | public String getPublishedAt() {
97 | return publishedAt;
98 | }
99 |
100 | public boolean isUsed() {
101 | return used;
102 | }
103 |
104 | public String getType() {
105 | return type;
106 | }
107 |
108 | public String getUrl() {
109 | return url;
110 | }
111 |
112 | public String getObjectId() {
113 | return objectId;
114 | }
115 |
116 | public String getWho() {
117 | return who;
118 | }
119 |
120 | public String getDesc() {
121 | return desc;
122 | }
123 |
124 | public String getUpdatedAt() {
125 | return updatedAt;
126 | }
127 |
128 |
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jin/gank/data/GankDay.java:
--------------------------------------------------------------------------------
1 | package com.jin.gank.data;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * Created by Administrator on 2015/8/24.
7 | */
8 | public class GankDay {
9 |
10 | /**
11 | * error : false
12 | * category : ["iOS","Android","瞎推荐","拓展资源","福利","休息视频"]
13 | * results : {"福利":[{"createdAt":"2015-08-07T01:21:06.112Z","publishedAt":"2015-08-07T03:57:47.310Z","used":true,"type":"福利","url":"http://ww2.sinaimg.cn/large/7a8aed7bgw1eutscfcqtcj20dw0i0q4l.jpg","objectId":"55c4080240ac7d0a9507905e","who":"张涵宇","desc":"8.7\u2014\u2014(1)","updatedAt":"2015-08-15T03:15:54.765Z"},{"createdAt":"2015-08-07T01:21:33.518Z","publishedAt":"2015-08-07T03:57:47.229Z","used":true,"type":"福利","url":"http://ww2.sinaimg.cn/large/7a8aed7bgw1eutsd0pgiwj20go0p0djn.jpg","objectId":"55c4081d60b2c9d32a67a92e","who":"张涵宇","desc":"8.7\u2014\u2014(2)","updatedAt":"2015-08-15T03:15:54.843Z"}],"休息视频":[{"createdAt":"2015-08-06T13:06:17.211Z","publishedAt":"2015-08-07T03:57:48.104Z","used":true,"type":"休息视频","url":"http://www.zhihu.com/question/21778055/answer/19905413?utm_source=weibo&utm_medium=weibo_share&utm_content=share_answer&utm_campaign=share_button","objectId":"55c35bc960b2750766954ec3","who":"lxxself","desc":"听到就心情大好的歌,简直妖魔哈哈哈哈哈,原地址 http://v.youku.com/v_show/id_XMTQxODA5NDM2.html","updatedAt":"2015-08-15T03:15:54.872Z"}],"拓展资源":[{"createdAt":"2015-08-07T01:36:06.932Z","publishedAt":"2015-08-07T03:57:48.081Z","used":true,"type":"拓展资源","url":"https://github.com/buunguyen/octotree","objectId":"55c40b8600b08484a7f3a032","who":"lxxself","desc":"Display GitHub code in tree format","updatedAt":"2015-08-15T03:15:54.382Z"}],"瞎推荐":[{"createdAt":"2015-08-07T01:52:30.267Z","publishedAt":"2015-08-07T03:57:48.084Z","used":true,"type":"瞎推荐","url":"https://cmd.fm/","objectId":"55c40f5e00b00045334934b4","who":"lxxself","desc":"程序员的电台FmM,这个页面chrome插件有问题啊哭,我写了回删除不了啊","updatedAt":"2015-08-15T03:15:54.383Z"}],"iOS":[{"createdAt":"2015-08-07T01:32:51.588Z","publishedAt":"2015-08-07T03:57:48.070Z","used":true,"type":"iOS","url":"http://adriansampson.net/blog/llvm.html","objectId":"55c40ac360b2c9d32a67ca25","who":"CallMeWhy","desc":"LLVM 简介","updatedAt":"2015-08-15T03:15:54.384Z"},{"createdAt":"2015-08-06T14:45:18.733Z","publishedAt":"2015-08-07T03:57:47.242Z","used":true,"type":"iOS","url":"https://github.com/molon/MLLabel","objectId":"55c372fe60b2f809e41eb388","who":"鲍永章","desc":"基于TextKit的UILabel,支持超链接和自定义表达式。","updatedAt":"2015-08-15T03:15:54.536Z"},{"createdAt":"2015-08-07T01:33:30.871Z","publishedAt":"2015-08-07T03:57:48.083Z","used":true,"type":"iOS","url":"http://chris.eidhof.nl/posts/swift-c-interop.html","objectId":"55c40aea00b025867b19c9af","who":"CallMeWhy","desc":"Swift 和 C 函数","updatedAt":"2015-08-15T03:15:54.408Z"},{"createdAt":"2015-08-07T01:34:00.984Z","publishedAt":"2015-08-07T03:57:48.174Z","used":true,"type":"iOS","url":"http://airspeedvelocity.net/2015/08/03/arrays-linked-lists-and-performance/","objectId":"55c40b0800b0fac2c2809acc","who":"CallMeWhy","desc":"Arrays Linked Lists 和性能比较","updatedAt":"2015-08-15T03:15:55.105Z"}],"Android":[{"createdAt":"2015-08-06T07:15:52.065Z","publishedAt":"2015-08-07T03:57:48.045Z","used":true,"type":"Android","url":"https://github.com/recruit-lifestyle/FloatingView","objectId":"55c309a800b00045333db517","who":"mthli","desc":"类似Link Bubble的悬浮式操作设计","updatedAt":"2015-08-15T03:15:55.098Z"},{"createdAt":"2015-08-07T01:33:07.815Z","publishedAt":"2015-08-07T03:57:47.317Z","used":true,"type":"Android","url":"http://www.zhihu.com/question/33636939","objectId":"55c40ad340ac7d0a9507b324","who":"lxxself","desc":"Android开发中,有哪些让你觉得相见恨晚的方法、类或接口?","updatedAt":"2015-08-15T03:15:54.407Z"},{"createdAt":"2015-08-06T15:00:38.350Z","publishedAt":"2015-08-07T03:57:48.076Z","used":true,"type":"Android","url":"https://github.com/tom91136/Akatsuki","objectId":"55c3769660b2750766971ce6","who":"鲍永章","desc":"使用注解来处理Activity的状态恢复","updatedAt":"2015-08-15T03:15:54.866Z"},{"createdAt":"2015-08-07T02:19:44.342Z","publishedAt":"2015-08-07T03:57:48.142Z","used":true,"type":"Android","url":"https://git.oschina.net/way/PinnedHeaderListView","objectId":"55c415c060b2d140ca882eac","who":"有时放纵","desc":"Android Lollipop联系人之PinnedListView简单使用","updatedAt":"2015-08-15T03:15:55.020Z"},{"createdAt":"2015-08-06T14:58:28.171Z","publishedAt":"2015-08-07T03:57:48.073Z","used":true,"type":"Android","url":"https://github.com/Q42/AndroidScrollingImageView","objectId":"55c3761400b00045334480d2","who":"鲍永章","desc":"图片可以自动滚动的ImageView,可以实现视差效果。","updatedAt":"2015-08-15T03:15:55.123Z"}]}
14 | */
15 | private boolean error;
16 | private List category;
17 | private ResultsEntity results;
18 |
19 | public void setError(boolean error) {
20 | this.error = error;
21 | }
22 |
23 | public void setCategory(List category) {
24 | this.category = category;
25 | }
26 |
27 | public void setResults(ResultsEntity results) {
28 | this.results = results;
29 | }
30 |
31 | public boolean isError() {
32 | return error;
33 | }
34 |
35 | public List getCategory() {
36 | return category;
37 | }
38 |
39 | public ResultsEntity getResults() {
40 | return results;
41 | }
42 |
43 | public static class ResultsEntity {
44 | /**
45 | * 福利 : [{"createdAt":"2015-08-07T01:21:06.112Z","publishedAt":"2015-08-07T03:57:47.310Z","used":true,"type":"福利","url":"http://ww2.sinaimg.cn/large/7a8aed7bgw1eutscfcqtcj20dw0i0q4l.jpg","objectId":"55c4080240ac7d0a9507905e","who":"张涵宇","desc":"8.7\u2014\u2014(1)","updatedAt":"2015-08-15T03:15:54.765Z"},{"createdAt":"2015-08-07T01:21:33.518Z","publishedAt":"2015-08-07T03:57:47.229Z","used":true,"type":"福利","url":"http://ww2.sinaimg.cn/large/7a8aed7bgw1eutsd0pgiwj20go0p0djn.jpg","objectId":"55c4081d60b2c9d32a67a92e","who":"张涵宇","desc":"8.7\u2014\u2014(2)","updatedAt":"2015-08-15T03:15:54.843Z"}]
46 | * 休息视频 : [{"createdAt":"2015-08-06T13:06:17.211Z","publishedAt":"2015-08-07T03:57:48.104Z","used":true,"type":"休息视频","url":"http://www.zhihu.com/question/21778055/answer/19905413?utm_source=weibo&utm_medium=weibo_share&utm_content=share_answer&utm_campaign=share_button","objectId":"55c35bc960b2750766954ec3","who":"lxxself","desc":"听到就心情大好的歌,简直妖魔哈哈哈哈哈,原地址 http://v.youku.com/v_show/id_XMTQxODA5NDM2.html","updatedAt":"2015-08-15T03:15:54.872Z"}]
47 | * 拓展资源 : [{"createdAt":"2015-08-07T01:36:06.932Z","publishedAt":"2015-08-07T03:57:48.081Z","used":true,"type":"拓展资源","url":"https://github.com/buunguyen/octotree","objectId":"55c40b8600b08484a7f3a032","who":"lxxself","desc":"Display GitHub code in tree format","updatedAt":"2015-08-15T03:15:54.382Z"}]
48 | * 瞎推荐 : [{"createdAt":"2015-08-07T01:52:30.267Z","publishedAt":"2015-08-07T03:57:48.084Z","used":true,"type":"瞎推荐","url":"https://cmd.fm/","objectId":"55c40f5e00b00045334934b4","who":"lxxself","desc":"程序员的电台FmM,这个页面chrome插件有问题啊哭,我写了回删除不了啊","updatedAt":"2015-08-15T03:15:54.383Z"}]
49 | * iOS : [{"createdAt":"2015-08-07T01:32:51.588Z","publishedAt":"2015-08-07T03:57:48.070Z","used":true,"type":"iOS","url":"http://adriansampson.net/blog/llvm.html","objectId":"55c40ac360b2c9d32a67ca25","who":"CallMeWhy","desc":"LLVM 简介","updatedAt":"2015-08-15T03:15:54.384Z"},{"createdAt":"2015-08-06T14:45:18.733Z","publishedAt":"2015-08-07T03:57:47.242Z","used":true,"type":"iOS","url":"https://github.com/molon/MLLabel","objectId":"55c372fe60b2f809e41eb388","who":"鲍永章","desc":"基于TextKit的UILabel,支持超链接和自定义表达式。","updatedAt":"2015-08-15T03:15:54.536Z"},{"createdAt":"2015-08-07T01:33:30.871Z","publishedAt":"2015-08-07T03:57:48.083Z","used":true,"type":"iOS","url":"http://chris.eidhof.nl/posts/swift-c-interop.html","objectId":"55c40aea00b025867b19c9af","who":"CallMeWhy","desc":"Swift 和 C 函数","updatedAt":"2015-08-15T03:15:54.408Z"},{"createdAt":"2015-08-07T01:34:00.984Z","publishedAt":"2015-08-07T03:57:48.174Z","used":true,"type":"iOS","url":"http://airspeedvelocity.net/2015/08/03/arrays-linked-lists-and-performance/","objectId":"55c40b0800b0fac2c2809acc","who":"CallMeWhy","desc":"Arrays Linked Lists 和性能比较","updatedAt":"2015-08-15T03:15:55.105Z"}]
50 | * Android : [{"createdAt":"2015-08-06T07:15:52.065Z","publishedAt":"2015-08-07T03:57:48.045Z","used":true,"type":"Android","url":"https://github.com/recruit-lifestyle/FloatingView","objectId":"55c309a800b00045333db517","who":"mthli","desc":"类似Link Bubble的悬浮式操作设计","updatedAt":"2015-08-15T03:15:55.098Z"},{"createdAt":"2015-08-07T01:33:07.815Z","publishedAt":"2015-08-07T03:57:47.317Z","used":true,"type":"Android","url":"http://www.zhihu.com/question/33636939","objectId":"55c40ad340ac7d0a9507b324","who":"lxxself","desc":"Android开发中,有哪些让你觉得相见恨晚的方法、类或接口?","updatedAt":"2015-08-15T03:15:54.407Z"},{"createdAt":"2015-08-06T15:00:38.350Z","publishedAt":"2015-08-07T03:57:48.076Z","used":true,"type":"Android","url":"https://github.com/tom91136/Akatsuki","objectId":"55c3769660b2750766971ce6","who":"鲍永章","desc":"使用注解来处理Activity的状态恢复","updatedAt":"2015-08-15T03:15:54.866Z"},{"createdAt":"2015-08-07T02:19:44.342Z","publishedAt":"2015-08-07T03:57:48.142Z","used":true,"type":"Android","url":"https://git.oschina.net/way/PinnedHeaderListView","objectId":"55c415c060b2d140ca882eac","who":"有时放纵","desc":"Android Lollipop联系人之PinnedListView简单使用","updatedAt":"2015-08-15T03:15:55.020Z"},{"createdAt":"2015-08-06T14:58:28.171Z","publishedAt":"2015-08-07T03:57:48.073Z","used":true,"type":"Android","url":"https://github.com/Q42/AndroidScrollingImageView","objectId":"55c3761400b00045334480d2","who":"鲍永章","desc":"图片可以自动滚动的ImageView,可以实现视差效果。","updatedAt":"2015-08-15T03:15:55.123Z"}]
51 | */
52 | private List 福利;
53 | private List 休息视频;
54 | private List 拓展资源;
55 | private List 瞎推荐;
56 | private List iOS;
57 | private List Android;
58 |
59 | public void set福利(List 福利) {
60 | this.福利 = 福利;
61 | }
62 |
63 | public void set休息视频(List 休息视频) {
64 | this.休息视频 = 休息视频;
65 | }
66 |
67 | public void set拓展资源(List 拓展资源) {
68 | this.拓展资源 = 拓展资源;
69 | }
70 |
71 | public void set瞎推荐(List 瞎推荐) {
72 | this.瞎推荐 = 瞎推荐;
73 | }
74 |
75 | public void setIOS(List iOS) {
76 | this.iOS = iOS;
77 | }
78 |
79 | public void setAndroid(List Android) {
80 | this.Android = Android;
81 | }
82 |
83 | public List get福利() {
84 | return 福利;
85 | }
86 |
87 | public List get休息视频() {
88 | return 休息视频;
89 | }
90 |
91 | public List get拓展资源() {
92 | return 拓展资源;
93 | }
94 |
95 | public List get瞎推荐() {
96 | return 瞎推荐;
97 | }
98 |
99 | public List getIOS() {
100 | return iOS;
101 | }
102 |
103 | public List getAndroid() {
104 | return Android;
105 | }
106 |
107 |
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jin/gank/data/GankRandom.java:
--------------------------------------------------------------------------------
1 | package com.jin.gank.data;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * Created by Administrator on 2015/8/24.
7 | */
8 | public class GankRandom {
9 |
10 | /**
11 | * error : false
12 | * results : [{"createdAt":"2015-05-28T11:18:58.168Z","publishedAt":"2015-05-29T03:36:51.888Z","used":true,"type":"Android","url":"https://github.com/romannurik/AndroidSDKSearchExtension","objectId":"5566f9a2e4b0aec39bf9b10b","who":"mthli","desc":"快速搜索Android SDK文档的Chrome扩展","updatedAt":"2015-08-15T03:09:57.714Z"},{"createdAt":"2015-08-18T15:24:36.747Z","publishedAt":"2015-08-19T03:56:32.551Z","used":true,"type":"Android","url":"https://github.com/SkillCollege/SimplifyReader","objectId":"55d34e3400b0de09f8fb0532","who":"Jason","desc":"一款基于Google Material Design设计开发的Android客户端,包括新闻简读,图片浏览,视频爽看 ,音乐轻听以及二维码扫描五个子模块,项目采取的是MVP架构开发。","updatedAt":"2015-08-19T03:56:34.075Z"},{"createdAt":"2015-06-07T11:00:27.934Z","publishedAt":"2015-06-09T03:30:27.469Z","used":true,"type":"Android","url":"https://github.com/JorgeCastilloPrz/FABProgressCircle","objectId":"5574244be4b029ae5fd0f298","who":"mthli","desc":"在FloatingActionButton上显示环形进度条","updatedAt":"2015-08-15T03:09:57.923Z"},{"createdAt":"2015-05-18T02:25:10.936Z","publishedAt":"2015-05-19T08:40:35.957Z","used":true,"type":"Android","url":"https://github.com/dmytrodanylyk/circular-progress-button","objectId":"55594d86e4b0b8cd3b7aefcc","who":"Jason","desc":"带进度显示的Button","updatedAt":"2015-08-15T03:09:57.704Z"},{"createdAt":"2015-06-02T15:38:30.156Z","publishedAt":"2015-06-04T05:01:40.057Z","used":true,"type":"Android","url":"https://github.com/yaa110/Piclice","objectId":"556dcdf6e4b005426cf9e94d","who":"Jason","desc":"一款将图片切片与分享的应用","updatedAt":"2015-08-15T03:09:57.802Z"},{"createdAt":"2015-07-13T02:02:11.196Z","publishedAt":"2015-07-13T03:33:29.420Z","used":true,"type":"Android","url":"https://github.com/worker8/TourGuide","objectId":"55a31c23e4b031b0057bb3ff","who":"有时放纵","desc":"一个用于你的android app引导功能的库","updatedAt":"2015-08-15T03:09:59.286Z"},{"createdAt":"2015-07-27T04:51:14.289Z","publishedAt":"2015-07-29T03:32:59.575Z","used":true,"type":"Android","url":"https://github.com/code-mc/material-icon-lib","objectId":"55b5b8c200b0c43f5b1de3c8","who":"Jason","desc":"包含1000多个material矢量图标的安卓图标库","updatedAt":"2015-08-15T03:15:54.746Z"},{"createdAt":"2015-06-05T04:24:39.142Z","publishedAt":"2015-06-09T03:38:06.063Z","used":true,"type":"Android","url":"https://github.com/PaoloRotolo/AppIntro","objectId":"55712487e4b0ba4266fa223e","who":"mthli","desc":"一个漂亮的App功能介绍库","updatedAt":"2015-08-15T03:09:57.927Z"},{"createdAt":"2015-08-10T22:47:04.910Z","publishedAt":"2015-08-11T03:28:03.108Z","used":true,"type":"Android","url":"https://github.com/kingideayou/SlideBottomPanel","objectId":"55c929e860b20fc9a88711bf","who":"代码家","desc":"底部划出菜单,滑动时背景图透明度渐变,支持嵌套 LiewView 或 ScrollView。","updatedAt":"2015-08-15T03:15:54.387Z"},{"createdAt":"2015-06-16T16:00:11.974Z","publishedAt":"2015-06-17T04:09:49.084Z","used":true,"type":"Android","url":"http://blog.csdn.net/garybook/article/details/7925728","objectId":"5580480be4b02f99238c9596","who":"LHF","desc":"Android中的签名机制","updatedAt":"2015-08-15T03:09:57.814Z"}]
13 | */
14 | private boolean error;
15 | private List results;
16 |
17 | public void setError(boolean error) {
18 | this.error = error;
19 | }
20 |
21 | public void setResults(List results) {
22 | this.results = results;
23 | }
24 |
25 | public boolean isError() {
26 | return error;
27 | }
28 |
29 | public List getResults() {
30 | return results;
31 | }
32 |
33 | public static class ResultsEntity {
34 | /**
35 | * createdAt : 2015-05-28T11:18:58.168Z
36 | * publishedAt : 2015-05-29T03:36:51.888Z
37 | * used : true
38 | * type : Android
39 | * url : https://github.com/romannurik/AndroidSDKSearchExtension
40 | * objectId : 5566f9a2e4b0aec39bf9b10b
41 | * who : mthli
42 | * desc : 快速搜索Android SDK文档的Chrome扩展
43 | * updatedAt : 2015-08-15T03:09:57.714Z
44 | */
45 | private String createdAt;
46 | private String publishedAt;
47 | private boolean used;
48 | private String type;
49 | private String url;
50 | private String objectId;
51 | private String who;
52 | private String desc;
53 | private String updatedAt;
54 |
55 | public void setCreatedAt(String createdAt) {
56 | this.createdAt = createdAt;
57 | }
58 |
59 | public void setPublishedAt(String publishedAt) {
60 | this.publishedAt = publishedAt;
61 | }
62 |
63 | public void setUsed(boolean used) {
64 | this.used = used;
65 | }
66 |
67 | public void setType(String type) {
68 | this.type = type;
69 | }
70 |
71 | public void setUrl(String url) {
72 | this.url = url;
73 | }
74 |
75 | public void setObjectId(String objectId) {
76 | this.objectId = objectId;
77 | }
78 |
79 | public void setWho(String who) {
80 | this.who = who;
81 | }
82 |
83 | public void setDesc(String desc) {
84 | this.desc = desc;
85 | }
86 |
87 | public void setUpdatedAt(String updatedAt) {
88 | this.updatedAt = updatedAt;
89 | }
90 |
91 | public String getCreatedAt() {
92 | return createdAt;
93 | }
94 |
95 | public String getPublishedAt() {
96 | return publishedAt;
97 | }
98 |
99 | public boolean isUsed() {
100 | return used;
101 | }
102 |
103 | public String getType() {
104 | return type;
105 | }
106 |
107 | public String getUrl() {
108 | return url;
109 | }
110 |
111 | public String getObjectId() {
112 | return objectId;
113 | }
114 |
115 | public String getWho() {
116 | return who;
117 | }
118 |
119 | public String getDesc() {
120 | return desc;
121 | }
122 |
123 | public String getUpdatedAt() {
124 | return updatedAt;
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jin/gank/decoration/DividerGridItemDecoration.java:
--------------------------------------------------------------------------------
1 | package com.jin.gank.decoration;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Rect;
6 | import android.graphics.drawable.Drawable;
7 | import android.support.v7.widget.GridLayoutManager;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.support.v7.widget.RecyclerView.LayoutManager;
10 | import android.support.v7.widget.RecyclerView.State;
11 | import android.support.v7.widget.StaggeredGridLayoutManager;
12 | import android.view.View;
13 |
14 | import com.jin.gank.R;
15 |
16 |
17 |
18 | public class DividerGridItemDecoration extends RecyclerView.ItemDecoration {
19 | private Drawable mDivider;
20 | public DividerGridItemDecoration(Context context) {
21 | mDivider = context.getResources().getDrawable(R.drawable.gride_divider);
22 |
23 | }
24 |
25 | @Override
26 | public void onDraw(Canvas c, RecyclerView parent, State state) {
27 | drawHorizontal(c, parent);
28 | drawVertical(c, parent);
29 | }
30 |
31 | private int getSpanCount(RecyclerView parent) {
32 | // 列数
33 | int spanCount = -1;
34 | LayoutManager layoutManager = parent.getLayoutManager();
35 | if (layoutManager instanceof GridLayoutManager) {
36 |
37 | spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
38 | } else if (layoutManager instanceof StaggeredGridLayoutManager) {
39 | spanCount = ((StaggeredGridLayoutManager) layoutManager)
40 | .getSpanCount();
41 | }
42 | return spanCount;
43 | }
44 |
45 | public void drawHorizontal(Canvas c, RecyclerView parent) {
46 | int childCount = parent.getChildCount();
47 | for (int i = 0; i < childCount; i++) {
48 | final View child = parent.getChildAt(i);
49 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
50 | .getLayoutParams();
51 | final int left = child.getLeft() - params.leftMargin;
52 | final int right = child.getRight() + params.rightMargin
53 | + mDivider.getIntrinsicWidth();
54 | final int top = child.getBottom() + params.bottomMargin;
55 | final int bottom = top + mDivider.getIntrinsicHeight();
56 | mDivider.setBounds(left, top, right, bottom);
57 | mDivider.draw(c);
58 | }
59 | }
60 |
61 | public void drawVertical(Canvas c, RecyclerView parent) {
62 | int childCount = parent.getChildCount();
63 | for (int i = 0; i < childCount; i++) {
64 | final View child = parent.getChildAt(i);
65 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
66 | .getLayoutParams();
67 | final int top = child.getTop() - params.topMargin;
68 | final int bottom = child.getBottom() + params.bottomMargin;
69 | final int left = child.getRight() + params.rightMargin;
70 | final int right = left + mDivider.getIntrinsicWidth();
71 | mDivider.setBounds(left, top, right, bottom);
72 | mDivider.draw(c);
73 | }
74 | }
75 |
76 | private boolean isLastColum(RecyclerView parent, int pos, int spanCount,
77 | int childCount) {
78 | LayoutManager layoutManager = parent.getLayoutManager();
79 | if (layoutManager instanceof GridLayoutManager) {
80 | if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
81 | {
82 | return true;
83 | }
84 | } else if (layoutManager instanceof StaggeredGridLayoutManager) {
85 | int orientation = ((StaggeredGridLayoutManager) layoutManager)
86 | .getOrientation();
87 | if (orientation == StaggeredGridLayoutManager.VERTICAL) {
88 | if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
89 | {
90 | return true;
91 | }
92 | } else {
93 | childCount = childCount - childCount % spanCount;
94 | if (pos >= childCount)// 如果是最后一列,则不需要绘制右边
95 | return true;
96 | }
97 | }
98 | return false;
99 | }
100 |
101 | private boolean isLastRaw(RecyclerView parent, int pos, int spanCount,
102 | int childCount) {
103 | LayoutManager layoutManager = parent.getLayoutManager();
104 | if (layoutManager instanceof GridLayoutManager) {
105 | childCount = childCount - childCount % spanCount;
106 | if (pos >= childCount)// 如果是最后一行,则不需要绘制底部
107 | return true;
108 | } else if (layoutManager instanceof StaggeredGridLayoutManager) {
109 | int orientation = ((StaggeredGridLayoutManager) layoutManager)
110 | .getOrientation();
111 | // StaggeredGridLayoutManager 且纵向滚动
112 | if (orientation == StaggeredGridLayoutManager.VERTICAL) {
113 | childCount = childCount - childCount % spanCount;
114 | // 如果是最后一行,则不需要绘制底部
115 | if (pos >= childCount)
116 | return true;
117 | } else
118 | // StaggeredGridLayoutManager 且横向滚动
119 | {
120 | // 如果是最后一行,则不需要绘制底部
121 | if ((pos + 1) % spanCount == 0) {
122 | return true;
123 | }
124 | }
125 | }
126 | return false;
127 | }
128 |
129 |
130 | @Override
131 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
132 | super.getItemOffsets(outRect, view, parent, state);
133 | int itemPosition = parent.getChildAdapterPosition(view);
134 | int spanCount = getSpanCount(parent);
135 | int childCount = parent.getAdapter().getItemCount();
136 | if (isLastRaw(parent, itemPosition, spanCount, childCount))// 如果是最后一行,则不需要绘制底部
137 | {
138 | outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
139 | } else if (isLastColum(parent, itemPosition, spanCount, childCount))// 如果是最后一列,则不需要绘制右边
140 | {
141 | outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
142 | } else {
143 | outRect.set(0, 0, mDivider.getIntrinsicWidth(),
144 | mDivider.getIntrinsicHeight());
145 | }
146 |
147 | }
148 | }
149 |
150 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jin/gank/decoration/DividerLinearItemDecoration.java:
--------------------------------------------------------------------------------
1 | package com.jin.gank.decoration;
2 | /*
3 | * Copyright (C) 2014 The Android Open Source Project
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * limitations under the License.
7 | */
8 |
9 | import android.content.Context;
10 | import android.graphics.Canvas;
11 | import android.graphics.Rect;
12 | import android.graphics.drawable.Drawable;
13 | import android.support.v7.widget.LinearLayoutManager;
14 | import android.support.v7.widget.RecyclerView;
15 | import android.view.View;
16 |
17 | import com.jin.gank.R;
18 |
19 |
20 |
21 | public class DividerLinearItemDecoration extends RecyclerView.ItemDecoration {
22 | private static final String TAG = "DividerItemDecoration";
23 | public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
24 |
25 | public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
26 |
27 | private Drawable mDivider;
28 |
29 | private int mOrientation;
30 |
31 | public DividerLinearItemDecoration(Context context, int orientation) {
32 | mDivider = context.getResources().getDrawable(R.drawable.line_divider);
33 | setOrientation(orientation);
34 | }
35 |
36 | public void setOrientation(int orientation) {
37 | if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
38 | throw new IllegalArgumentException("invalid orientation");
39 | }
40 | mOrientation = orientation;
41 | }
42 |
43 |
44 | public void drawVertical(Canvas c, RecyclerView parent) {
45 | final int left = parent.getPaddingLeft();
46 | final int right = parent.getWidth() - parent.getPaddingRight();
47 |
48 | final int childCount = parent.getChildCount();
49 | for (int i = 0; i < childCount; i++) {
50 | final View child = parent.getChildAt(i);
51 | android.support.v7.widget.RecyclerView v = new android.support.v7.widget.RecyclerView(parent.getContext());
52 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
53 | .getLayoutParams();
54 | final int top = child.getBottom() + params.bottomMargin;
55 | final int bottom = top + mDivider.getIntrinsicHeight();
56 | mDivider.setBounds(left, top, right, bottom);
57 | mDivider.draw(c);
58 | }
59 | }
60 |
61 | public void drawHorizontal(Canvas c, RecyclerView parent) {
62 | final int top = parent.getPaddingTop();
63 | final int bottom = parent.getHeight() - parent.getPaddingBottom();
64 |
65 | final int childCount = parent.getChildCount();
66 | for (int i = 0; i < childCount; i++) {
67 | final View child = parent.getChildAt(i);
68 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
69 | .getLayoutParams();
70 | final int left = child.getRight() + params.rightMargin;
71 | final int right = left + mDivider.getIntrinsicHeight();
72 | mDivider.setBounds(left, top, right, bottom);
73 | mDivider.draw(c);
74 | }
75 | }
76 |
77 |
78 | @Override
79 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
80 | super.onDraw(c, parent, state);
81 | if (mOrientation == VERTICAL_LIST) {
82 | drawVertical(c, parent);
83 | } else {
84 | drawHorizontal(c, parent);
85 | }
86 | }
87 |
88 | @Override
89 | public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
90 | super.onDrawOver(c, parent, state);
91 | }
92 |
93 | @Override
94 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
95 | super.getItemOffsets(outRect, view, parent, state);
96 | if (mOrientation == VERTICAL_LIST) {
97 | outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
98 | } else {
99 | outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jin/gank/fragment/GankFragment.java:
--------------------------------------------------------------------------------
1 | package com.jin.gank.fragment;
2 |
3 | import android.content.Intent;
4 | import android.content.pm.ActivityInfo;
5 | import android.content.res.Configuration;
6 | import android.os.Bundle;
7 | import android.support.design.widget.CoordinatorLayout;
8 | import android.support.v4.app.Fragment;
9 | import android.support.v7.widget.LinearLayoutManager;
10 | import android.support.v7.widget.RecyclerView;
11 | import android.util.Log;
12 | import android.view.LayoutInflater;
13 | import android.view.MenuItem;
14 | import android.view.View;
15 | import android.view.ViewGroup;
16 | import android.view.ViewStub;
17 |
18 | import com.bumptech.glide.Glide;
19 | import com.jin.gank.R;
20 | import com.jin.gank.WebActivity;
21 | import com.jin.gank.adapter.GankListAdapter;
22 | import com.jin.gank.data.GankCategory;
23 | import com.jin.gank.data.GankDay;
24 | import com.jin.gank.network.RetrofitHelp;
25 | import com.jin.gank.util.Once;
26 | import com.jin.gank.util.ShareUtils;
27 | import com.jin.gank.util.ToastUtils;
28 | import com.jin.gank.view.GoodAppBarLayout;
29 | import com.jin.gank.view.LoveVideoView;
30 | import com.jin.gank.view.VideoImageView;
31 |
32 | import java.util.ArrayList;
33 | import java.util.List;
34 |
35 | import butterknife.Bind;
36 | import butterknife.ButterKnife;
37 | import butterknife.OnClick;
38 | import rx.Subscription;
39 | import rx.android.schedulers.AndroidSchedulers;
40 | import rx.schedulers.Schedulers;
41 |
42 |
43 | public class GankFragment extends Fragment {
44 |
45 | private final String TAG = "GankFragment";
46 | private static final String ARG_YEAR = "year";
47 | private static final String ARG_MONTH = "month";
48 | private static final String ARG_DAY = "day";
49 |
50 | @Bind(R.id.rv_gank)
51 | RecyclerView mRecyclerView;
52 | @Bind(R.id.stub_empty_view)
53 | ViewStub mEmptyViewStub;
54 | @Bind(R.id.stub_video_view)
55 | ViewStub mVideoViewStub;
56 | @Bind(R.id.iv_video)
57 | VideoImageView mVideoImageView;
58 | @Bind(R.id.header_appbar)
59 | GoodAppBarLayout mAppBarLayout;
60 | @Bind(R.id.cl_content)
61 | CoordinatorLayout mLayout;
62 | LoveVideoView mVideoView;
63 |
64 | int mYear, mMonth, mDay;
65 | List mGankList;
66 | String mVideoPreviewUrl;
67 | boolean mIsVideoViewInflated = false;
68 | Subscription mSubscription;
69 | GankListAdapter mAdapter;
70 |
71 | /**
72 | * Returns a new instance of this fragment for the given section
73 | * number.
74 | */
75 | public static GankFragment newInstance(int year, int month, int day) {
76 | GankFragment fragment = new GankFragment();
77 | Bundle args = new Bundle();
78 | args.putInt(ARG_YEAR, year);
79 | args.putInt(ARG_MONTH, month);
80 | args.putInt(ARG_DAY, day);
81 | fragment.setArguments(args);
82 | return fragment;
83 | }
84 |
85 | public GankFragment() {
86 |
87 | }
88 |
89 | @Override
90 | public void onCreate(Bundle savedInstanceState) {
91 | super.onCreate(savedInstanceState);
92 | mGankList = new ArrayList<>();
93 | mAdapter = new GankListAdapter(mGankList);
94 | parseArguments();
95 | setRetainInstance(true);
96 | setHasOptionsMenu(true);
97 | }
98 |
99 | private void parseArguments() {
100 | Bundle bundle = getArguments();
101 | mYear = bundle.getInt(ARG_YEAR);
102 | mMonth = bundle.getInt(ARG_MONTH);
103 | mDay = bundle.getInt(ARG_DAY);
104 | }
105 |
106 | @Override
107 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
108 | Bundle savedInstanceState) {
109 | View rootView = inflater.inflate(R.layout.fragment_gank, container, false);
110 | ButterKnife.bind(this, rootView);
111 | initRecyclerView();
112 | setVideoViewPosition(getResources().getConfiguration());
113 | return rootView;
114 | }
115 |
116 | @Override
117 | public void onViewCreated(View view, Bundle savedInstanceState) {
118 | super.onViewCreated(view, savedInstanceState);
119 | if (mGankList.size() == 0) getData();
120 | if (mVideoPreviewUrl != null) {
121 | Glide.with(this).load(mVideoPreviewUrl).into(mVideoImageView);
122 | }
123 | }
124 |
125 | private void initRecyclerView() {
126 | LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
127 | mRecyclerView.setLayoutManager(layoutManager);
128 | mRecyclerView.setAdapter(mAdapter);
129 | }
130 |
131 | private void getData() {
132 |
133 | mSubscription = RetrofitHelp.getApi().listGankDay(mYear, mMonth, mDay)
134 | .subscribeOn(Schedulers.newThread())
135 | .observeOn(AndroidSchedulers.mainThread())
136 | .map(data -> data.getResults())
137 | .map(this::addAllResults)
138 | .subscribe(list -> {
139 | if (list.isEmpty()) {
140 | showEmptyView();
141 | } else {
142 | mAdapter.notifyDataSetChanged();
143 | }
144 | }, e -> {
145 | Log.e(TAG, e.getMessage());
146 | });
147 | getAndParseVideoPreview();
148 |
149 | }
150 |
151 | private void getAndParseVideoPreview() {
152 | mVideoImageView.post(() -> Glide.with(mVideoImageView.getContext())
153 | .load(mVideoPreviewUrl)
154 | .into(mVideoImageView));
155 |
156 |
157 | /*OkHttpClient client = new OkHttpClient();
158 | String url = getString(R.string.url_gank_io) + String.format("%s/%s/%s", mYear, mMonth, mDay);
159 | Request request = new Request.Builder().url(url).build();
160 | client.newCall(request).enqueue(new Callback() {
161 | @Override
162 | public void onFailure(Call call, IOException e) {
163 | ToastUtils.showShort(e.getMessage());
164 | }
165 |
166 | @Override
167 | public void onResponse(Call call, Response response) throws IOException {
168 | String body = response.body().string();
169 | mVideoPreviewUrl = LoveStringUtils.getVideoPreviewImageUrl(body);
170 | if (mVideoPreviewUrl != null && mVideoImageView != null) {
171 | mVideoImageView.post(() -> Glide.with(mVideoImageView.getContext())
172 | .load(mVideoPreviewUrl)
173 | .into(mVideoImageView));
174 | }
175 | }
176 | });*/
177 | }
178 |
179 | private void showEmptyView() {
180 | mEmptyViewStub.inflate();
181 | }
182 |
183 | private List addAllResults(GankDay.ResultsEntity results) {
184 | //初始化视频图片
185 | if (results.get福利() != null) {
186 | mVideoImageView.post(() -> Glide.with(mVideoImageView.getContext())
187 | .load(results.get福利().get(0).getUrl())
188 | .into(mVideoImageView));
189 | }
190 |
191 | if (results.getAndroid() != null) mGankList.addAll(results.getAndroid());
192 | if (results.getIOS() != null) mGankList.addAll(results.getIOS());
193 | if (results.get拓展资源() != null) mGankList.addAll(results.get拓展资源());
194 | if (results.get瞎推荐() != null) mGankList.addAll(results.get瞎推荐());
195 | if (results.get休息视频() != null) mGankList.addAll(0, results.get休息视频());
196 | return mGankList;
197 | }
198 |
199 | @OnClick(R.id.header_appbar)
200 | void onPlayVideo() {
201 | getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
202 | }
203 |
204 | private void setVideoViewPosition(Configuration newConfig) {
205 | switch (newConfig.orientation) {
206 | case Configuration.ORIENTATION_LANDSCAPE: {
207 | if (mIsVideoViewInflated) {
208 | mVideoViewStub.setVisibility(View.VISIBLE);
209 | } else {
210 | mVideoView = (LoveVideoView) mVideoViewStub.inflate();
211 | mIsVideoViewInflated = true;
212 | String tip = getString(R.string.tip_video_play);
213 | new Once(mVideoView.getContext()).show(tip, () -> ToastUtils.showLongLongLong(tip));
214 | }
215 | if (mGankList.size() > 0 && mGankList.get(0).getType().equals("休息视频")) {
216 | mVideoView.loadUrl(mGankList.get(0).getUrl());
217 | }
218 | break;
219 | }
220 | case Configuration.ORIENTATION_PORTRAIT:
221 | case Configuration.ORIENTATION_UNDEFINED:
222 | default: {
223 | mVideoViewStub.setVisibility(View.GONE);
224 | break;
225 | }
226 | }
227 | }
228 |
229 | void closePlayer() {
230 | getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
231 | ToastUtils.showShort(getString(R.string.daimajia_has_gone));
232 | }
233 |
234 | @Override
235 | public void onConfigurationChanged(Configuration newConfig) {
236 | setVideoViewPosition(newConfig);
237 | super.onConfigurationChanged(newConfig);
238 | }
239 |
240 | /*@Subscribe public void onKeyBackClick(OnKeyBackClickEvent event) {
241 | if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
242 | getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
243 | }
244 | }*/
245 |
246 | @Override
247 | public boolean onOptionsItemSelected(MenuItem item) {
248 | int id = item.getItemId();
249 | switch (id) {
250 | case R.id.action_share:
251 | if (mGankList.size() != 0) {
252 | GankCategory.ResultsEntity gank = mGankList.get(0);
253 | String shareText = gank.getDesc() + gank.getUrl() + getString(R.string.share_from);
254 | ShareUtils.share(getActivity(), shareText);
255 | } else {
256 | ShareUtils.share(getActivity());
257 | }
258 | return true;
259 |
260 | case R.id.action_subject:
261 | openTodaySubject();
262 | return true;
263 | }
264 | return super.onOptionsItemSelected(item);
265 | }
266 |
267 | private void openTodaySubject() {
268 | String url = getString(R.string.url_gank_io) + String.format("%s/%s/%s", mYear, mMonth, mDay);
269 | Intent intent = new Intent(getActivity(), WebActivity.class);
270 | intent.putExtra(WebActivity.EXTRA_URL, url);
271 | intent.putExtra(WebActivity.EXTRA_TITLE, getString(R.string.action_subject));
272 | startActivity(intent);
273 | }
274 |
275 | @Override
276 | public void onResume() {
277 | super.onResume();
278 | if (mVideoView != null) mVideoView.resumeTimers();
279 | }
280 |
281 | @Override
282 | public void onPause() {
283 | super.onPause();
284 | if (mVideoView != null) mVideoView.pauseTimers();
285 | }
286 |
287 | @Override
288 | public void onDestroyView() {
289 | super.onDestroyView();
290 | ButterKnife.unbind(this);
291 | }
292 |
293 | @Override
294 | public void onDestroy() {
295 | super.onDestroy();
296 | if (mSubscription != null) mSubscription.unsubscribe();
297 | if (mVideoView != null) mVideoView.destroy();
298 | }
299 | }
300 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jin/gank/fragment/MyFragment.java:
--------------------------------------------------------------------------------
1 | package com.jin.gank.fragment;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v4.widget.SwipeRefreshLayout;
8 | import android.support.v7.widget.LinearLayoutManager;
9 | import android.support.v7.widget.RecyclerView;
10 | import android.view.LayoutInflater;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 |
14 | import com.jin.gank.R;
15 | import com.jin.gank.data.Constant;
16 | import com.jin.gank.data.GankCategory;
17 | import com.jin.gank.databinding.ItemCategoryBinding;
18 | import com.jin.gank.network.RetrofitHelp;
19 | import com.malinskiy.superrecyclerview.OnMoreListener;
20 | import com.malinskiy.superrecyclerview.SuperRecyclerView;
21 | import com.ogaclejapan.smarttablayout.utils.v4.FragmentPagerItem;
22 | import com.vlonjatg.progressactivity.ProgressActivity;
23 |
24 | import java.util.List;
25 |
26 | import butterknife.Bind;
27 | import butterknife.ButterKnife;
28 | import jp.wasabeef.recyclerview.animators.OvershootInLeftAnimator;
29 | import rx.Observable;
30 | import rx.android.schedulers.AndroidSchedulers;
31 | import rx.schedulers.Schedulers;
32 |
33 | /**
34 | * Created by Administrator on 2015/8/25.
35 | */
36 | public class MyFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener, OnMoreListener {
37 | private static final String TAG = "MyFragment";
38 | @Bind(R.id.progressActivity)
39 | ProgressActivity mProgressActivity;
40 | @Bind(R.id.superRecyclerView_category)
41 | SuperRecyclerView mSuperRecyclerViewCategory;
42 |
43 |
44 | private List mCategorys;
45 | private String[] mCategoryArray;
46 | private LayoutInflater mInflater;
47 | private MyAdapter mAdapter;
48 | private boolean isLoadMore = true;
49 | private int position;
50 |
51 | @Override
52 | public void onCreate(@Nullable Bundle savedInstanceState) {
53 | super.onCreate(savedInstanceState);
54 | mInflater = LayoutInflater.from(getActivity());
55 | mCategoryArray = getResources().getStringArray(R.array.category_list);
56 | }
57 |
58 | @Override
59 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
60 | super.onViewCreated(view, savedInstanceState);
61 | position = FragmentPagerItem.getPosition(getArguments());
62 |
63 | mSuperRecyclerViewCategory.setLayoutManager(new LinearLayoutManager(getActivity()));
64 | mSuperRecyclerViewCategory.getRecyclerView().setItemAnimator(new OvershootInLeftAnimator());
65 | mSuperRecyclerViewCategory.setRefreshListener(this);
66 | mSuperRecyclerViewCategory.setupMoreListener(this, 10);
67 | mSuperRecyclerViewCategory.setRefreshingColorResources(android.R.color.holo_orange_light, android.R.color.holo_blue_light, android.R.color.holo_green_light, android.R.color.holo_red_light);
68 | if (mCategorys == null || mCategorys.size() == 0) {
69 | loadCategoryData(mCategoryArray[position], Constant.API_COUNT, 1, true);
70 | } else {
71 | mAdapter.notifyDataSetChanged();
72 | }
73 |
74 | }
75 |
76 | //下载数据信息
77 | private void loadCategoryData(String category, int count, int page, boolean firstLoad) {
78 | if (firstLoad) {
79 | mProgressActivity.showLoading();
80 | if (mCategorys != null)
81 | mCategorys.clear();
82 | }
83 |
84 | RetrofitHelp.getApi().listGankCategory(category, count, page)
85 | .subscribeOn(Schedulers.io())
86 | .observeOn(AndroidSchedulers.mainThread())
87 | .flatMap(Categorys -> {
88 | //判断是否已经加载到最后一页
89 | if (Categorys.getResults().size() < 10)
90 | isLoadMore = false;
91 | return Observable.just(Categorys.getResults());
92 | })
93 | .subscribe(Categorys -> {
94 | mProgressActivity.showContent();
95 | if (mAdapter == null) {
96 | mCategorys = Categorys;
97 | mAdapter = new MyAdapter(Categorys);
98 | mSuperRecyclerViewCategory.setAdapter(mAdapter);
99 | } else {
100 | if (!firstLoad)
101 | mCategorys.addAll(mCategorys.size(), Categorys);
102 |
103 | mAdapter.setCategorys(mCategorys);
104 | mAdapter.notifyDataSetChanged();
105 | }
106 |
107 | mSuperRecyclerViewCategory.hideMoreProgress();
108 | mSuperRecyclerViewCategory.getSwipeToRefresh().setRefreshing(false);
109 | },
110 | err -> mProgressActivity.showError(null, "错误", err.toString(), "重试", v -> loadCategoryData(category, Constant.API_COUNT, 1, true)));
111 | }
112 |
113 | @Override
114 | public void onMoreAsked(int numberOfItems, int numberBeforeMore, int currentItemPos) {
115 | if (isLoadMore) {
116 | loadCategoryData(mCategoryArray[position], Constant.API_COUNT, numberOfItems / Constant.API_COUNT + 1, false);
117 | } else {
118 | mSuperRecyclerViewCategory.hideMoreProgress();
119 | }
120 | }
121 |
122 | @Override
123 | public void onRefresh() {
124 | isLoadMore = true;
125 | loadCategoryData(mCategoryArray[position], Constant.API_COUNT, 1, true);
126 | }
127 |
128 |
129 | private class MyAdapter extends RecyclerView.Adapter {
130 |
131 | public void setCategorys(List Categorys) {
132 | this.Categorys = Categorys;
133 | }
134 |
135 | private List Categorys;
136 |
137 | public MyAdapter(List Categorys) {
138 | super();
139 | this.Categorys = Categorys;
140 | }
141 |
142 | @Override
143 | public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
144 | View contentView = mInflater.inflate(R.layout.item_category, parent, false);
145 | MyViewHolder holder = new MyViewHolder(contentView);
146 | return holder;
147 | }
148 |
149 | @Override
150 | public void onBindViewHolder(MyViewHolder holder, final int position) {
151 | GankCategory.ResultsEntity Category = Categorys.get(position);
152 | holder.bind(Category);
153 | }
154 |
155 | @Override
156 | public int getItemCount() {
157 | return Categorys.size();
158 | }
159 |
160 |
161 | class MyViewHolder extends RecyclerView.ViewHolder {
162 | private ItemCategoryBinding mCategoryBinding;
163 |
164 | public MyViewHolder(View convertView) {
165 | super(convertView);
166 | mCategoryBinding = DataBindingUtil.bind(convertView);
167 |
168 | }
169 |
170 | public void bind(GankCategory.ResultsEntity Category) {
171 | mCategoryBinding.setCategory(Category);
172 | }
173 | }
174 |
175 | }
176 |
177 |
178 | @Nullable
179 | @Override
180 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
181 | container = (ViewGroup) inflater.inflate(R.layout.fragment_category, null, false);
182 | ButterKnife.bind(this, container);
183 | return container;
184 | }
185 |
186 | @Override
187 | public void onDestroyView() {
188 | super.onDestroyView();
189 | ButterKnife.unbind(this);
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jin/gank/fragment/MyImgFragment.java:
--------------------------------------------------------------------------------
1 | package com.jin.gank.fragment;
2 |
3 | import android.content.Intent;
4 | import android.databinding.DataBindingUtil;
5 | import android.os.Bundle;
6 | import android.support.annotation.Nullable;
7 | import android.support.v4.app.ActivityCompat;
8 | import android.support.v4.app.ActivityOptionsCompat;
9 | import android.support.v4.app.Fragment;
10 | import android.support.v4.widget.SwipeRefreshLayout;
11 | import android.support.v7.widget.RecyclerView;
12 | import android.support.v7.widget.StaggeredGridLayoutManager;
13 | import android.view.LayoutInflater;
14 | import android.view.View;
15 | import android.view.ViewGroup;
16 |
17 | import com.jin.gank.GankActivity;
18 | import com.jin.gank.PictureActivity;
19 | import com.jin.gank.R;
20 | import com.jin.gank.data.Constant;
21 | import com.jin.gank.data.GankCategory;
22 | import com.jin.gank.databinding.ItemImgBinding;
23 | import com.jin.gank.network.RetrofitHelp;
24 | import com.malinskiy.superrecyclerview.OnMoreListener;
25 | import com.malinskiy.superrecyclerview.SuperRecyclerView;
26 | import com.vlonjatg.progressactivity.ProgressActivity;
27 |
28 | import java.util.ArrayList;
29 | import java.util.List;
30 |
31 | import butterknife.Bind;
32 | import butterknife.ButterKnife;
33 | import jp.wasabeef.recyclerview.animators.OvershootInLeftAnimator;
34 | import rx.Observable;
35 | import rx.android.schedulers.AndroidSchedulers;
36 | import rx.schedulers.Schedulers;
37 |
38 | /**
39 | * Created by Administrator on 2015/8/25.
40 | */
41 | public class MyImgFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener, OnMoreListener {
42 | private static final String TAG = "MyImgFragment";
43 | @Bind(R.id.progressActivity)
44 | ProgressActivity mProgressActivity;
45 | @Bind(R.id.superRecyclerView_img)
46 | SuperRecyclerView mSuperRecyclerViewImg;
47 |
48 |
49 | private List mGirls;
50 | private String[] mCategoryArray;
51 | private LayoutInflater mInflater;
52 | private MyAdapter mAdapter;
53 | private boolean isLoadMore = true;
54 |
55 | @Override
56 | public void onCreate(@Nullable Bundle savedInstanceState) {
57 | super.onCreate(savedInstanceState);
58 | mCategoryArray = getResources().getStringArray(R.array.category_list);
59 | mInflater = LayoutInflater.from(getActivity());
60 |
61 | }
62 |
63 | @Nullable
64 | @Override
65 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
66 | container = (ViewGroup) inflater.inflate(R.layout.fragment_img, null, false);
67 | ButterKnife.bind(this, container);
68 | return container;
69 | }
70 |
71 | @Override
72 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
73 | super.onViewCreated(view, savedInstanceState);
74 | mSuperRecyclerViewImg.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
75 | mSuperRecyclerViewImg.getRecyclerView().setItemAnimator(new OvershootInLeftAnimator());
76 | mSuperRecyclerViewImg.setRefreshListener(this);
77 | mSuperRecyclerViewImg.setupMoreListener(this, 10);
78 | mSuperRecyclerViewImg.setRefreshingColorResources(android.R.color.holo_orange_light, android.R.color.holo_blue_light, android.R.color.holo_green_light, android.R.color.holo_red_light);
79 | if (mGirls == null || mGirls.size() == 0) {
80 | loadGirlData(mCategoryArray[0], Constant.API_COUNT, 1, true);
81 | } else {
82 | mAdapter.notifyDataSetChanged();
83 | }
84 | }
85 |
86 |
87 | //加载数据
88 | private void loadGirlData(String category, int count, int page, boolean firstLoad) {
89 | if (firstLoad) {
90 | mProgressActivity.showLoading();
91 | if (mGirls != null)
92 | mGirls.clear();
93 | }
94 | Observable.zip(RetrofitHelp.getApi().listGankCategory(category, count, page)
95 | , RetrofitHelp.getApi().listGankCategory(mCategoryArray[5], count, page), (Girls, Videos) ->
96 | createGirlDataWithgetFreeVideoDesc(Girls, Videos)
97 | ).subscribeOn(Schedulers.io())
98 | .observeOn(AndroidSchedulers.mainThread())
99 | .flatMap(Girls -> {
100 | //判断是否已经加载到最后一页
101 | if (Girls.getResults().size() < 10)
102 | isLoadMore = false;
103 |
104 | return Observable.just(Girls.getResults());
105 | })
106 | .subscribe(Girls -> {
107 | mProgressActivity.showContent();
108 |
109 | if (mAdapter == null) {
110 | mGirls = Girls;
111 | mAdapter = new MyAdapter(mGirls);
112 | mSuperRecyclerViewImg.setAdapter(mAdapter);
113 | } else {
114 | if (!firstLoad)
115 | mGirls.addAll(mGirls.size(), Girls);
116 |
117 | mAdapter.setGirls(mGirls);
118 | mAdapter.notifyDataSetChanged();
119 | }
120 |
121 | mSuperRecyclerViewImg.hideMoreProgress();
122 | mSuperRecyclerViewImg.getSwipeToRefresh().setRefreshing(false);
123 | },
124 | err -> mProgressActivity.showError(null, "错误", err.toString(), "重试", v -> loadGirlData(category, Constant.API_COUNT, 1, true)));
125 | }
126 |
127 | private GankCategory createGirlDataWithgetFreeVideoDesc(GankCategory girls, GankCategory loves) {
128 | for (int i = 0; i < girls.getResults().size(); i++) {
129 | GankCategory.ResultsEntity girl = girls.getResults().get(i);
130 | if (loves.getResults() != null && loves.getResults().size() > i)
131 | girl.setDesc(girl.getDesc() + " " + loves.getResults().get(i).getDesc());
132 | }
133 | return girls;
134 | }
135 |
136 |
137 | @Override
138 | public void onMoreAsked(int numberOfItems, int numberBeforeMore, int currentItemPos) {
139 | if (isLoadMore) {
140 | loadGirlData(mCategoryArray[0], Constant.API_COUNT, numberOfItems / Constant.API_COUNT + 1, false);
141 | } else {
142 | mSuperRecyclerViewImg.hideMoreProgress();
143 | }
144 | }
145 |
146 | @Override
147 | public void onRefresh() {
148 | isLoadMore = true;
149 | loadGirlData(mCategoryArray[0], Constant.API_COUNT, 1, true);
150 | }
151 |
152 |
153 | private class MyAdapter extends RecyclerView.Adapter implements View.OnClickListener {
154 |
155 | public void setGirls(List girls) {
156 | this.girls = girls;
157 | }
158 |
159 | private List girls;
160 |
161 | public MyAdapter(List girls) {
162 | super();
163 | this.girls = girls;
164 | }
165 |
166 | @Override
167 | public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
168 | View contentView = mInflater.inflate(R.layout.item_img, parent, false);
169 | MyViewHolder holder = new MyViewHolder(contentView);
170 | return holder;
171 | }
172 |
173 | @Override
174 | public void onBindViewHolder(MyViewHolder holder, final int position) {
175 | GankCategory.ResultsEntity gril = girls.get(position);
176 | holder.bind(gril);
177 | holder.mImgBinding.welfareImg.setOriginalSize(50, 50);
178 | holder.mImgBinding.welfareImg.setTag(R.id.image_tag, gril);
179 | holder.mImgBinding.welfareImg.setOnClickListener(this);
180 | holder.mImgBinding.welfareDesc.setTag(R.id.image_tag, gril);
181 | holder.mImgBinding.welfareDesc.setOnClickListener(this);
182 |
183 | }
184 |
185 | @Override
186 | public int getItemCount() {
187 | return girls.size();
188 | }
189 |
190 | @Override
191 | public void onClick(View v) {
192 | startPictureActivity((GankCategory.ResultsEntity) v.getTag(R.id.image_tag), v);
193 | }
194 |
195 |
196 | class MyViewHolder extends RecyclerView.ViewHolder {
197 | private ItemImgBinding mImgBinding;
198 |
199 | public MyViewHolder(View convertView) {
200 | super(convertView);
201 | mImgBinding = DataBindingUtil.bind(convertView);
202 |
203 | }
204 |
205 | public void bind(GankCategory.ResultsEntity Gril) {
206 | mImgBinding.setGirl(Gril);
207 | }
208 | }
209 |
210 | private void startPictureActivity(GankCategory.ResultsEntity girl, View sharedView) {
211 | if (sharedView.getId() == R.id.welfare_img) {
212 | Intent intent = new Intent(getActivity(), PictureActivity.class);
213 | intent.putExtra(PictureActivity.EXTRA_IMAGE_URL, girl.getUrl());
214 | intent.putExtra(PictureActivity.EXTRA_IMAGE_TITLE, girl.getDesc());
215 | //打开activity 动画
216 | ActivityOptionsCompat optionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity(), sharedView,
217 | PictureActivity.TRANSIT_PIC);
218 | ActivityCompat.startActivity(getActivity(), intent, optionsCompat.toBundle());
219 | } else {
220 | Intent intent = new Intent(getActivity(), GankActivity.class);
221 | int position = mGirls.indexOf(girl);
222 | List dates = new ArrayList<>();
223 | //判断是否超出最大list大小
224 | if (position + 5 > mGirls.size()) {
225 | for (int i = position; i < mGirls.size(); i++) {
226 | String PublishedAt = mGirls.get(i).getPublishedAt().split("T")[0];
227 | dates.add(PublishedAt);
228 | }
229 | } else {
230 | for (int i = position; i < position + 5; i++) {
231 | String PublishedAt = mGirls.get(i).getPublishedAt().split("T")[0];
232 | dates.add(PublishedAt);
233 | }
234 | }
235 | // String PublishedAt = girl.getPublishedAt().split("T")[0];
236 | intent.putStringArrayListExtra(GankActivity.EXTRA_GANK_DATA, (ArrayList) dates);
237 | startActivity(intent);
238 | }
239 |
240 | }
241 |
242 | }
243 |
244 |
245 | @Override
246 | public void onDestroyView() {
247 | super.onDestroyView();
248 | ButterKnife.unbind(this);
249 | }
250 |
251 | }
252 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jin/gank/network/RESTApi.java:
--------------------------------------------------------------------------------
1 | package com.jin.gank.network;
2 |
3 | import com.jin.gank.data.GankCategory;
4 | import com.jin.gank.data.GankDay;
5 | import com.jin.gank.data.GankRandom;
6 |
7 | import retrofit2.http.GET;
8 | import retrofit2.http.Path;
9 | import rx.Observable;
10 |
11 | /**
12 | * Created by Administrator on 2015/8/21.
13 | * 干货集中营 API
14 | */
15 | public interface RESTApi {
16 | @GET("data/{category}/{count}/{page}")
17 | Observable listGankCategory(@Path("category") String category, @Path("count") int count, @Path("page") int page);
18 |
19 |
20 | @GET("day/{year}/{month}/{day}")
21 | Observable listGankDay(@Path("year") int year, @Path("month") int month, @Path("day") int day);
22 |
23 | @GET("random/data/{category}/{count}")
24 | Observable listGankRandom(@Path("category") String category, @Path("count") int count);
25 |
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jin/gank/network/RetrofitHelp.java:
--------------------------------------------------------------------------------
1 | package com.jin.gank.network;
2 |
3 | import com.jin.gank.data.Constant;
4 |
5 | import java.util.concurrent.TimeUnit;
6 |
7 | import okhttp3.OkHttpClient;
8 | import retrofit2.Retrofit;
9 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
10 | import retrofit2.converter.gson.GsonConverterFactory;
11 |
12 |
13 | /**
14 | * Created by Administrator on 2015/8/21.
15 | */
16 | public class RetrofitHelp {
17 | private static RESTApi api;
18 |
19 | public static RESTApi getApi() {
20 | if (api == null) {
21 | OkHttpClient client = new OkHttpClient.Builder()
22 | .connectTimeout(10, TimeUnit.SECONDS)
23 | .readTimeout(10, TimeUnit.SECONDS)
24 | .writeTimeout(10, TimeUnit.SECONDS)
25 | .retryOnConnectionFailure(true)
26 | .build();
27 |
28 | Retrofit retrofit = new Retrofit.Builder().client(client)
29 | .baseUrl(Constant.ROOT_PATH)
30 | .addConverterFactory(GsonConverterFactory.create())
31 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
32 | .build();
33 | api = retrofit.create(RESTApi.class);
34 | }
35 |
36 | return api;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jin/gank/util/DateUtils.java:
--------------------------------------------------------------------------------
1 | package com.jin.gank.util;
2 |
3 | import java.text.DateFormat;
4 | import java.text.SimpleDateFormat;
5 | import java.util.Calendar;
6 | import java.util.Date;
7 |
8 |
9 | public class DateUtils {
10 |
11 | public static String toDate(Date date) {
12 | DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
13 | return dateFormat.format(date);
14 | }
15 |
16 |
17 |
18 | public static String toDate(Date date, int add) {
19 | Calendar calendar = Calendar.getInstance();
20 | calendar.setTime(date);
21 | calendar.add(Calendar.DATE, add);
22 | return toDate(calendar.getTime());
23 | }
24 |
25 | public static Date getLastdayDate(Date date) {
26 | Calendar calendar = Calendar.getInstance();
27 | calendar.setTime(date);
28 | calendar.add(Calendar.DATE, -1);
29 | return calendar.getTime();
30 | }
31 |
32 | public static Date getNextdayDate(Date date) {
33 | Calendar calendar = Calendar.getInstance();
34 | calendar.setTime(date);
35 | calendar.add(Calendar.DATE, 1);
36 | return calendar.getTime();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jin/gank/util/ImageUtils.java:
--------------------------------------------------------------------------------
1 | package com.jin.gank.util;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.graphics.Bitmap;
6 | import android.net.Uri;
7 | import android.os.AsyncTask;
8 | import android.os.Environment;
9 | import android.provider.MediaStore;
10 | import com.bumptech.glide.Glide;
11 | import com.jin.gank.R;
12 | import java.io.File;
13 | import java.io.FileNotFoundException;
14 | import java.io.FileOutputStream;
15 | import java.io.IOException;
16 | import java.util.concurrent.ExecutionException;
17 |
18 |
19 |
20 | public class ImageUtils {
21 |
22 | public static void saveImageToSdCard(Context context, String url, String title) {
23 | TaskUtils.executeAsyncTask(new AsyncTask