├── .gitignore
├── README.md
├── app
├── .gitignore
├── build.gradle
├── outputs
│ ├── SHLV.apk
│ └── output.json
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ └── about.html
│ ├── java
│ └── com
│ │ └── sunfusheng
│ │ └── StickyHeaderListView
│ │ ├── AboutActivity.java
│ │ ├── MainActivity.java
│ │ ├── adapter
│ │ ├── BaseListAdapter.java
│ │ ├── FilterLeftAdapter.java
│ │ ├── FilterOneAdapter.java
│ │ ├── FilterRightAdapter.java
│ │ ├── HeaderBannerAdapter.java
│ │ ├── HeaderChannelAdapter.java
│ │ ├── HeaderOperationAdapter.java
│ │ └── TravelingAdapter.java
│ │ ├── model
│ │ ├── ChannelEntity.java
│ │ ├── FilterData.java
│ │ ├── FilterEntity.java
│ │ ├── FilterTwoEntity.java
│ │ ├── OperationEntity.java
│ │ ├── TravelingEntity.java
│ │ └── TravelingEntityComparator.java
│ │ ├── util
│ │ ├── ColorUtil.java
│ │ ├── DensityUtil.java
│ │ ├── ModelUtil.java
│ │ ├── StatusBarUtil.java
│ │ └── ToastUtil.java
│ │ └── view
│ │ ├── AbsHeaderView.java
│ │ ├── FilterView.java
│ │ ├── FixedGridView.java
│ │ ├── FixedSpeedScroller.java
│ │ ├── HeaderBannerView.java
│ │ ├── HeaderChannelView.java
│ │ ├── HeaderDividerView.java
│ │ ├── HeaderFilterView.java
│ │ ├── HeaderOperationView.java
│ │ └── SmoothListView
│ │ ├── SmoothListView.java
│ │ ├── SmoothListViewFooter.java
│ │ └── SmoothListViewHeader.java
│ └── res
│ ├── drawable-v21
│ ├── drawable_rectangle_shape.xml
│ ├── ripple_item_clicked.xml
│ └── ripple_item_clicked_with_mask.xml
│ ├── drawable
│ ├── bg_full_mask.9.png
│ ├── ripple_item_clicked.xml
│ ├── ripple_item_clicked_with_mask.xml
│ ├── xml_oval_half_transparent_bg.xml
│ ├── xml_oval_orange_icon.xml
│ ├── xml_round_grey_icon.xml
│ ├── xml_round_orange_grey_sel.xml
│ └── xml_round_orange_icon.xml
│ ├── layout
│ ├── activity_about.xml
│ ├── activity_main.xml
│ ├── app_toolbar.xml
│ ├── header_banner_layout.xml
│ ├── header_channel_layout.xml
│ ├── header_divider_layout.xml
│ ├── header_filter_layout.xml
│ ├── header_operation_layout.xml
│ ├── item_channel.xml
│ ├── item_filter_left.xml
│ ├── item_filter_one.xml
│ ├── item_filter_right.xml
│ ├── item_no_data_layout.xml
│ ├── item_operation.xml
│ ├── item_travel.xml
│ ├── smoothlistview_footer.xml
│ ├── smoothlistview_header.xml
│ ├── view_filter_layout.xml
│ └── view_full_mask_layout.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ ├── home_banner_index_mask.png
│ ├── home_down_arrow.png
│ ├── home_down_arrow_red.png
│ ├── ic_action_more.png
│ ├── ic_launcher.png
│ ├── ic_no_data.png
│ └── smoothlistview_arrow.png
│ ├── mipmap-xxhdpi
│ ├── home_banner_index_mask.png
│ ├── home_down_arrow.png
│ ├── home_down_arrow_red.png
│ ├── ic_action_more.png
│ ├── ic_launcher.png
│ └── ic_no_data.png
│ ├── mipmap-xxxhdpi
│ └── ic_launcher.png
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── resources
├── fir.im.png
├── res.png
├── stickyheader.gif
└── stickyheader2.gif
├── settings.gradle
└── signings
├── keystore.jks
└── signing.properties
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /build
4 | /.idea
5 | /*.iml
6 | /app/build
7 | /app/*.iml
8 |
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## StickyHeaderListView
3 |
4 | StickyHeaderListView是基于实际需求做出的灵活可变的UI视图,具体实现了如下功能:
5 | 一、支持下拉刷新和上拉加载更多功能。
6 | 二、支持无限循环的广告位。
7 | 三、使用GridView实现可动态配置的频道位、运营位。
8 | 四、自定义FilterView实现筛选功能,同时支持动画显示与动画隐藏。
9 | 五、支持FilterView滑动到顶部后吸附悬浮。
10 | 六、支持标题栏背景颜色渐变和字体颜色渐变。
11 | 七、实现了数据不足一屏动态添加空数据占位。
12 | 八、数据为空时ListView多type加载暂无数据视图。
13 |
14 |
15 |
16 | ### 应用截图
17 |
18 |
19 |
20 |
21 |
22 | ### 动态效果图
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | ### [实现思路参考简书文章](http://www.jianshu.com/p/3bf26722c489)
33 |
34 |
35 |
36 | ### 扫一扫[Fir.im](https://fir.im/StickyListView)二维码下载APK
37 |
38 |
39 |
40 |
41 |
42 | ### 个人微信公众号
43 |
44 |
45 |
46 |
47 |
48 | ### 打点赏给作者加点油^_^
49 |
50 |
51 |
52 |
53 |
54 | ### 关于我
55 |
56 | [GitHub: sunfusheng](https://github.com/sunfusheng)
57 |
58 | [个人邮箱: sfsheng0322@126.com](https://mail.126.com/)
59 |
60 | [个人博客: sunfusheng.com](http://sunfusheng.com/)
61 |
62 | [简书主页](http://www.jianshu.com/users/88509e7e2ed1/latest_articles)
63 |
64 | [新浪微博](http://weibo.com/u/3852192525)
65 |
66 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'com.jakewharton.butterknife'
3 |
4 | Properties signingProperties = new Properties()
5 | signingProperties.load(new FileInputStream(file("../signings/signing.properties")))
6 |
7 | android {
8 | compileSdkVersion gradle.compileSdkVersion
9 | defaultConfig {
10 | applicationId "com.sunfusheng.StickyHeaderListView"
11 | minSdkVersion gradle.minSdkVersion
12 | targetSdkVersion gradle.targetSdkVersion
13 | versionCode gradle.versionCode
14 | versionName gradle.versionName
15 | }
16 |
17 | compileOptions {
18 | sourceCompatibility JavaVersion.VERSION_1_8
19 | targetCompatibility JavaVersion.VERSION_1_8
20 | }
21 |
22 | lintOptions {
23 | quiet true
24 | abortOnError false
25 | ignoreWarnings true
26 | }
27 |
28 | signingConfigs {
29 | release {
30 | storeFile file(signingProperties['KEYSTORE_FILEPATH'])
31 | storePassword signingProperties['STORE_PASSWORD']
32 | keyAlias signingProperties['KEY_ALIAS']
33 | keyPassword signingProperties['KEY_PASSWORD']
34 | }
35 | }
36 |
37 | buildTypes {
38 | release {
39 | buildConfigField "boolean", "debugMode", "false"
40 | signingConfig signingConfigs.release
41 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
42 | applicationVariants.all {
43 | variant -> generateApk(variant)
44 | }
45 | }
46 |
47 | debug {
48 | buildConfigField "boolean", "debugMode", "true"
49 | signingConfig signingConfigs.release
50 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
51 | applicationVariants.all {
52 | variant -> generateApk(variant)
53 | }
54 | }
55 | }
56 | }
57 |
58 | def generateApk(variant) {
59 | if (variant.buildType.name == "release") {
60 | variant.getPackageApplication().outputDirectory = new File(project.rootDir.absolutePath + "/app/outputs")
61 | variant.getPackageApplication().outputScope.apkDatas.forEach { apkData ->
62 | apkData.outputFileName = "SHLV.apk"
63 | }
64 | }
65 | }
66 |
67 | dependencies {
68 | implementation fileTree(dir: 'libs', include: ['*.jar'])
69 | implementation 'com.android.support:appcompat-v7:' + gradle.supportLibraryVersion
70 | implementation 'com.android.support:design:' + gradle.supportLibraryVersion
71 | implementation 'com.jakewharton:butterknife:8.4.0'
72 | annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
73 |
74 | implementation 'com.sunfusheng:FirUpdater:1.0.7'
75 | implementation 'com.sunfusheng:glideimageview:1.2.0'
76 | }
77 |
--------------------------------------------------------------------------------
/app/outputs/SHLV.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sunfusheng/StickyHeaderListView/3ccece97636b15bc38e19d086fa1b3d890f738ce/app/outputs/SHLV.apk
--------------------------------------------------------------------------------
/app/outputs/output.json:
--------------------------------------------------------------------------------
1 | [{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":9},"path":"SHLV.apk","properties":{"packageId":"com.sunfusheng.StickyHeaderListView","split":"","minSdkVersion":"14"}}]
--------------------------------------------------------------------------------
/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 /Users/sunfusheng/Android/Studio/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
22 |
23 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/assets/about.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
155 | 关注我吧
156 |
157 |
158 |
159 | 关注我吧
160 |
161 | 项目开源地址:https://github.com/sfsheng0322/StickyHeaderListView
162 |
163 | GitHub主页
164 |
165 | 简书主页
166 |
167 | 个人博客
168 |
169 | 新浪微博
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/AboutActivity.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView;
2 |
3 | import android.content.Context;
4 | import android.content.pm.PackageInfo;
5 | import android.content.pm.PackageManager;
6 | import android.os.Build;
7 | import android.os.Bundle;
8 | import android.support.v7.app.ActionBar;
9 | import android.support.v7.app.AppCompatActivity;
10 | import android.support.v7.widget.Toolbar;
11 | import android.text.TextUtils;
12 | import android.view.KeyEvent;
13 | import android.view.Menu;
14 | import android.view.MenuItem;
15 | import android.view.View;
16 | import android.webkit.WebSettings;
17 | import android.webkit.WebView;
18 | import android.webkit.WebViewClient;
19 |
20 | import butterknife.BindView;
21 | import butterknife.ButterKnife;
22 |
23 | /**
24 | * Created by sunfusheng on 16/4/24.
25 | */
26 | public class AboutActivity extends AppCompatActivity {
27 |
28 | @BindView(R.id.toolbar)
29 | Toolbar toolbar;
30 | @BindView(R.id.webView)
31 | WebView webView;
32 |
33 | private WebSettings settings;
34 |
35 | @Override
36 | protected void onCreate(Bundle savedInstanceState) {
37 | super.onCreate(savedInstanceState);
38 | setContentView(R.layout.activity_about);
39 | ButterKnife.bind(this);
40 |
41 | initView();
42 | }
43 |
44 | private void initView() {
45 | initToolBar(toolbar, true, "关于 (V" + getVersionName(this) + ")");
46 |
47 | settings = webView.getSettings();
48 | settings.setJavaScriptEnabled(true); //如果访问的页面中有Javascript,则WebView必须设置支持Javascript
49 | settings.setJavaScriptCanOpenWindowsAutomatically(true);
50 | settings.setSupportZoom(true); //支持缩放
51 | settings.setBuiltInZoomControls(true); //支持手势缩放
52 | settings.setDisplayZoomControls(false); //是否显示缩放按钮
53 |
54 | // >= 19(SDK4.4)启动硬件加速,否则启动软件加速
55 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
56 | webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
57 | settings.setLoadsImagesAutomatically(true); //支持自动加载图片
58 | } else {
59 | webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
60 | settings.setLoadsImagesAutomatically(false);
61 | }
62 |
63 | settings.setUseWideViewPort(true); //将图片调整到适合WebView的大小
64 | settings.setLoadWithOverviewMode(true); //自适应屏幕
65 | settings.setDomStorageEnabled(true);
66 | settings.setSaveFormData(true);
67 | settings.setSupportMultipleWindows(true);
68 | settings.setAppCacheEnabled(true);
69 | settings.setCacheMode(WebSettings.LOAD_DEFAULT); //优先使用缓存
70 |
71 | webView.setHorizontalScrollbarOverlay(true);
72 | webView.setHorizontalScrollBarEnabled(false);
73 | webView.setOverScrollMode(View.OVER_SCROLL_NEVER); // 取消WebView中滚动或拖动到顶部、底部时的阴影
74 | webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY); // 取消滚动条白边效果
75 | webView.requestFocus();
76 |
77 | webView.loadUrl("file:///android_asset/about.html");
78 | webView.setWebViewClient(new WebViewClient() {
79 | @Override
80 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
81 | view.loadUrl(url);
82 | return true;
83 | }
84 | });
85 | }
86 |
87 | // 获取当前应用的版本号
88 | public static String getVersionName(Context context) {
89 | try {
90 | PackageManager packageManager = context.getPackageManager();
91 | PackageInfo packInfo = packageManager.getPackageInfo(context.getPackageName(),0);
92 | String version = packInfo.versionName;
93 | if (!TextUtils.isEmpty(version)) {
94 | return version;
95 | }
96 | } catch (Exception e) {
97 | e.printStackTrace();
98 | }
99 | return "";
100 | }
101 |
102 | public void initToolBar(Toolbar toolbar, boolean homeAsUpEnabled, String title) {
103 | toolbar.setTitle(title);
104 | setSupportActionBar(toolbar);
105 | ActionBar actionBar = getSupportActionBar();
106 | if (actionBar != null) {
107 | actionBar.setDisplayHomeAsUpEnabled(homeAsUpEnabled);
108 | }
109 | }
110 |
111 | @Override
112 | public boolean onCreateOptionsMenu(Menu menu) {
113 | return super.onCreateOptionsMenu(menu);
114 | }
115 |
116 | @Override
117 | public boolean onOptionsItemSelected(MenuItem item) {
118 | switch (item.getItemId()) {
119 | case android.R.id.home:
120 | finish();
121 | return true;
122 | default:
123 | return super.onOptionsItemSelected(item);
124 | }
125 | }
126 |
127 | @Override
128 | public boolean onKeyDown(int keyCode, KeyEvent event) {
129 | if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
130 | webView.goBack();//返回上一页面
131 | return true;
132 | }
133 | return super.onKeyDown(keyCode, event);
134 | }
135 |
136 | }
137 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.os.Handler;
8 | import android.support.v7.app.AppCompatActivity;
9 | import android.view.View;
10 | import android.widget.AbsListView;
11 | import android.widget.FrameLayout;
12 | import android.widget.RelativeLayout;
13 | import android.widget.TextView;
14 |
15 | import com.sunfusheng.FirUpdater;
16 | import com.sunfusheng.StickyHeaderListView.adapter.TravelingAdapter;
17 | import com.sunfusheng.StickyHeaderListView.model.ChannelEntity;
18 | import com.sunfusheng.StickyHeaderListView.model.FilterData;
19 | import com.sunfusheng.StickyHeaderListView.model.FilterEntity;
20 | import com.sunfusheng.StickyHeaderListView.model.FilterTwoEntity;
21 | import com.sunfusheng.StickyHeaderListView.model.OperationEntity;
22 | import com.sunfusheng.StickyHeaderListView.model.TravelingEntity;
23 | import com.sunfusheng.StickyHeaderListView.util.ColorUtil;
24 | import com.sunfusheng.StickyHeaderListView.util.DensityUtil;
25 | import com.sunfusheng.StickyHeaderListView.util.ModelUtil;
26 | import com.sunfusheng.StickyHeaderListView.util.StatusBarUtil;
27 | import com.sunfusheng.StickyHeaderListView.view.FilterView;
28 | import com.sunfusheng.StickyHeaderListView.view.HeaderBannerView;
29 | import com.sunfusheng.StickyHeaderListView.view.HeaderChannelView;
30 | import com.sunfusheng.StickyHeaderListView.view.HeaderDividerView;
31 | import com.sunfusheng.StickyHeaderListView.view.HeaderFilterView;
32 | import com.sunfusheng.StickyHeaderListView.view.HeaderOperationView;
33 | import com.sunfusheng.StickyHeaderListView.view.SmoothListView.SmoothListView;
34 |
35 | import java.util.ArrayList;
36 | import java.util.List;
37 |
38 | import butterknife.BindView;
39 | import butterknife.ButterKnife;
40 |
41 | /**
42 | * 作者:孙福生
43 | *
44 | * 个人博客:sunfusheng.com
45 | */
46 | public class MainActivity extends AppCompatActivity implements SmoothListView.ISmoothListViewListener {
47 |
48 | @BindView(R.id.listView)
49 | SmoothListView smoothListView;
50 | @BindView(R.id.real_filterView)
51 | FilterView realFilterView;
52 | @BindView(R.id.rl_bar)
53 | RelativeLayout rlBar;
54 | @BindView(R.id.tv_title)
55 | TextView tvTitle;
56 | @BindView(R.id.view_title_bg)
57 | View viewTitleBg;
58 | @BindView(R.id.view_action_more_bg)
59 | View viewActionMoreBg;
60 | @BindView(R.id.fl_action_more)
61 | FrameLayout flActionMore;
62 |
63 | private Context mContext;
64 | private Activity mActivity;
65 | private int mScreenHeight; // 屏幕高度
66 |
67 | private List bannerList = new ArrayList<>(); // 广告数据
68 | private List channelList = new ArrayList<>(); // 频道数据
69 | private List operationList = new ArrayList<>(); // 运营数据
70 | private List travelingList = new ArrayList<>(); // ListView数据
71 |
72 | private HeaderBannerView headerBannerView; // 广告视图
73 | private HeaderChannelView headerChannelView; // 频道视图
74 | private HeaderOperationView headerOperationView; // 运营视图
75 | private HeaderDividerView headerDividerView; // 分割线占位图
76 | private HeaderFilterView headerFilterView; // 分类筛选视图
77 | private FilterData filterData; // 筛选数据
78 | private TravelingAdapter mAdapter;
79 |
80 | private int titleViewHeight = 65; // 标题栏的高度
81 |
82 | private View itemHeaderBannerView; // 从ListView获取的广告子View
83 | private int bannerViewHeight = 180; // 广告视图的高度
84 | private int bannerViewTopMargin; // 广告视图距离顶部的距离
85 |
86 | private View itemHeaderFilterView; // 从ListView获取的筛选子View
87 | private int filterViewPosition = 4; // 筛选视图的位置
88 | private int filterViewTopMargin; // 筛选视图距离顶部的距离
89 | private boolean isScrollIdle = true; // ListView是否在滑动
90 | private boolean isStickyTop = false; // 是否吸附在顶部
91 | private boolean isSmooth = false; // 没有吸附的前提下,是否在滑动
92 | private int filterPosition = -1; // 点击FilterView的位置:分类(0)、排序(1)、筛选(2)
93 |
94 | @Override
95 | protected void onCreate(Bundle savedInstanceState) {
96 | super.onCreate(savedInstanceState);
97 | setContentView(R.layout.activity_main);
98 | ButterKnife.bind(this);
99 | StatusBarUtil.setStatusBarTranslucent(this, true);
100 |
101 | new FirUpdater(this, "3c57fb226edf7facf821501e4eba08d2", "571dd00b00fc74312e00001f").checkVersion();
102 |
103 | initData();
104 | initView();
105 | initListener();
106 | }
107 |
108 | private void initData() {
109 | mContext = this;
110 | mActivity = this;
111 | mScreenHeight = DensityUtil.getWindowHeight(this);
112 |
113 | // 筛选数据
114 | filterData = new FilterData();
115 | filterData.setCategory(ModelUtil.getCategoryData());
116 | filterData.setSorts(ModelUtil.getSortData());
117 | filterData.setFilters(ModelUtil.getFilterData());
118 | // 广告数据
119 | bannerList = ModelUtil.getBannerData();
120 | // 频道数据
121 | channelList = ModelUtil.getChannelData();
122 | // 运营数据
123 | operationList = ModelUtil.getOperationData();
124 | // ListView数据
125 | travelingList = ModelUtil.getTravelingData();
126 | }
127 |
128 | private void initView() {
129 | // 设置广告数据
130 | headerBannerView = new HeaderBannerView(this);
131 | headerBannerView.fillView(bannerList, smoothListView);
132 |
133 | // 设置频道数据
134 | headerChannelView = new HeaderChannelView(this);
135 | headerChannelView.fillView(channelList, smoothListView);
136 |
137 | // 设置运营数据
138 | headerOperationView = new HeaderOperationView(this);
139 | headerOperationView.fillView(operationList, smoothListView);
140 |
141 | // 设置分割线
142 | headerDividerView = new HeaderDividerView(this);
143 | headerDividerView.fillView("", smoothListView);
144 |
145 | // 设置假FilterView数据
146 | headerFilterView = new HeaderFilterView(this);
147 | headerFilterView.fillView(new Object(), smoothListView);
148 |
149 | // 设置真FilterView数据
150 | realFilterView.setFilterData(mActivity, filterData);
151 | realFilterView.setVisibility(View.GONE);
152 |
153 | // 设置ListView数据
154 | mAdapter = new TravelingAdapter(this, travelingList);
155 | smoothListView.setAdapter(mAdapter);
156 |
157 | filterViewPosition = smoothListView.getHeaderViewsCount() - 1;
158 | }
159 |
160 | private void initListener() {
161 | // 关于
162 | flActionMore.setOnClickListener(new View.OnClickListener() {
163 | @Override
164 | public void onClick(View v) {
165 | startActivity(new Intent(mActivity, AboutActivity.class));
166 | }
167 | });
168 |
169 | // (假的ListView头部展示的)筛选视图点击
170 | headerFilterView.getFilterView().setOnFilterClickListener(new FilterView.OnFilterClickListener() {
171 | @Override
172 | public void onFilterClick(int position) {
173 | filterPosition = position;
174 | isSmooth = true;
175 | smoothListView.smoothScrollToPositionFromTop(filterViewPosition, DensityUtil.dip2px(mContext, titleViewHeight));
176 | }
177 | });
178 |
179 | // (真正的)筛选视图点击
180 | realFilterView.setOnFilterClickListener(new FilterView.OnFilterClickListener() {
181 | @Override
182 | public void onFilterClick(int position) {
183 | filterPosition = position;
184 | realFilterView.show(position);
185 | smoothListView.smoothScrollToPositionFromTop(filterViewPosition, DensityUtil.dip2px(mContext, titleViewHeight));
186 | }
187 | });
188 |
189 | // 分类Item点击
190 | realFilterView.setOnItemCategoryClickListener(new FilterView.OnItemCategoryClickListener() {
191 | @Override
192 | public void onItemCategoryClick(FilterTwoEntity leftEntity, FilterEntity rightEntity) {
193 | fillAdapter(ModelUtil.getCategoryTravelingData(leftEntity, rightEntity));
194 | }
195 | });
196 |
197 | // 排序Item点击
198 | realFilterView.setOnItemSortClickListener(new FilterView.OnItemSortClickListener() {
199 | @Override
200 | public void onItemSortClick(FilterEntity entity) {
201 | fillAdapter(ModelUtil.getSortTravelingData(entity));
202 | }
203 | });
204 |
205 | // 筛选Item点击
206 | realFilterView.setOnItemFilterClickListener(new FilterView.OnItemFilterClickListener() {
207 | @Override
208 | public void onItemFilterClick(FilterEntity entity) {
209 | fillAdapter(ModelUtil.getFilterTravelingData(entity));
210 | }
211 | });
212 |
213 | smoothListView.setRefreshEnable(true);
214 | smoothListView.setLoadMoreEnable(true);
215 | smoothListView.setSmoothListViewListener(this);
216 | smoothListView.setOnScrollListener(new SmoothListView.OnSmoothScrollListener() {
217 | @Override
218 | public void onSmoothScrolling(View view) {
219 | }
220 |
221 | @Override
222 | public void onScrollStateChanged(AbsListView view, int scrollState) {
223 | isScrollIdle = (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE);
224 | }
225 |
226 | @Override
227 | public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
228 | if (isScrollIdle && bannerViewTopMargin < 0) return;
229 |
230 | // 获取广告头部View、自身的高度、距离顶部的高度
231 | if (itemHeaderBannerView == null) {
232 | itemHeaderBannerView = smoothListView.getChildAt(1);
233 | }
234 | if (itemHeaderBannerView != null) {
235 | bannerViewTopMargin = DensityUtil.px2dip(mContext, itemHeaderBannerView.getTop());
236 | bannerViewHeight = DensityUtil.px2dip(mContext, itemHeaderBannerView.getHeight());
237 | }
238 |
239 | // 获取筛选View、距离顶部的高度
240 | if (itemHeaderFilterView == null) {
241 | itemHeaderFilterView = smoothListView.getChildAt(filterViewPosition - firstVisibleItem);
242 | }
243 | if (itemHeaderFilterView != null) {
244 | filterViewTopMargin = DensityUtil.px2dip(mContext, itemHeaderFilterView.getTop());
245 | }
246 |
247 | // 处理筛选是否吸附在顶部
248 | if (filterViewTopMargin <= titleViewHeight || firstVisibleItem > filterViewPosition) {
249 | isStickyTop = true; // 吸附在顶部
250 | realFilterView.setVisibility(View.VISIBLE);
251 | } else {
252 | isStickyTop = false; // 没有吸附在顶部
253 | realFilterView.setVisibility(View.GONE);
254 | }
255 |
256 | if (isSmooth && isStickyTop) {
257 | isSmooth = false;
258 | realFilterView.show(filterPosition);
259 | }
260 |
261 | // 处理标题栏颜色渐变
262 | handleTitleBarColorEvaluate();
263 | }
264 | });
265 | }
266 |
267 | // 填充数据
268 | private void fillAdapter(List list) {
269 | if (list == null || list.size() == 0) {
270 | int height = mScreenHeight - DensityUtil.dip2px(mContext, 95); // 95 = 标题栏高度 + FilterView的高度
271 | mAdapter.setData(ModelUtil.getNoDataEntity(height));
272 | } else {
273 | mAdapter.setData(list);
274 | }
275 | }
276 |
277 | // 处理标题栏颜色渐变
278 | private void handleTitleBarColorEvaluate() {
279 | float fraction;
280 | if (bannerViewTopMargin > 0) {
281 | fraction = 1f - bannerViewTopMargin * 1f / 60;
282 | if (fraction < 0f) fraction = 0f;
283 | rlBar.setAlpha(fraction);
284 | return;
285 | }
286 |
287 | float space = Math.abs(bannerViewTopMargin) * 1f;
288 | fraction = space / (bannerViewHeight - titleViewHeight);
289 | if (fraction < 0f) fraction = 0f;
290 | if (fraction > 1f) fraction = 1f;
291 | rlBar.setAlpha(1f);
292 |
293 | if (fraction >= 1f || isStickyTop) {
294 | isStickyTop = true;
295 | viewTitleBg.setAlpha(0f);
296 | viewActionMoreBg.setAlpha(0f);
297 | rlBar.setBackgroundColor(mContext.getResources().getColor(R.color.colorPrimary));
298 | } else {
299 | viewTitleBg.setAlpha(1f - fraction);
300 | viewActionMoreBg.setAlpha(1f - fraction);
301 | rlBar.setBackgroundColor(ColorUtil.getNewColorByStartEndColor(mContext, fraction, R.color.transparent, R.color.colorPrimary));
302 | }
303 | }
304 |
305 | @Override
306 | protected void onResume() {
307 | super.onResume();
308 | headerBannerView.enqueueBannerLoopMessage();
309 | }
310 |
311 | @Override
312 | protected void onStop() {
313 | super.onStop();
314 | headerBannerView.removeBannerLoopMessage();
315 | }
316 |
317 | @Override
318 | public void onBackPressed() {
319 | if (realFilterView.isShowing()) {
320 | realFilterView.resetAllStatus();
321 | } else {
322 | super.onBackPressed();
323 | }
324 | }
325 |
326 | @Override
327 | public void onRefresh() {
328 | new Handler().postDelayed(new Runnable() {
329 | @Override
330 | public void run() {
331 | smoothListView.stopRefresh();
332 | smoothListView.setRefreshTime("刚刚");
333 | }
334 | }, 2000);
335 | }
336 |
337 | @Override
338 | public void onLoadMore() {
339 | new Handler().postDelayed(new Runnable() {
340 | @Override
341 | public void run() {
342 | smoothListView.stopLoadMore();
343 | }
344 | }, 2000);
345 | }
346 |
347 | }
348 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/adapter/BaseListAdapter.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.adapter;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.widget.BaseAdapter;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | public abstract class BaseListAdapter extends BaseAdapter {
11 |
12 | protected Context mContext;
13 | private List mList = new ArrayList();
14 | protected LayoutInflater mInflater;
15 |
16 | public BaseListAdapter(Context context) {
17 | mContext = context;
18 | mInflater = LayoutInflater.from(context);
19 | }
20 |
21 | public BaseListAdapter(Context context, List list) {
22 | this(context);
23 | mList = list;
24 | }
25 |
26 | @Override
27 | public int getCount() {
28 | return mList.size();
29 | }
30 |
31 | public void clearAll() {
32 | mList.clear();
33 | }
34 |
35 | public List getData() {
36 | return mList;
37 | }
38 |
39 | public void addALL(List list){
40 | if(list==null||list.size()==0) return;
41 | mList.addAll(list);
42 | }
43 | public void add(E item){
44 | mList.add(item);
45 | }
46 |
47 | @Override
48 | public E getItem(int position) {
49 | return (E) mList.get(position);
50 | }
51 |
52 | @Override
53 | public long getItemId(int position) {
54 | return position;
55 | }
56 |
57 | public void removeEntity(E e){
58 | mList.remove(e);
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/adapter/FilterLeftAdapter.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.adapter;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.widget.LinearLayout;
7 | import android.widget.TextView;
8 |
9 | import com.sunfusheng.StickyHeaderListView.R;
10 | import com.sunfusheng.StickyHeaderListView.model.FilterTwoEntity;
11 |
12 | import java.util.List;
13 |
14 | import butterknife.BindView;
15 | import butterknife.ButterKnife;
16 |
17 | /**
18 | * Created by sunfusheng on 16/4/23.
19 | */
20 | public class FilterLeftAdapter extends BaseListAdapter {
21 |
22 | public FilterLeftAdapter(Context context) {
23 | super(context);
24 | }
25 |
26 | public FilterLeftAdapter(Context context, List list) {
27 | super(context, list);
28 | }
29 |
30 | public void setSelectedEntity(FilterTwoEntity filterEntity) {
31 | for (FilterTwoEntity entity : getData()) {
32 | entity.setSelected(filterEntity != null && entity.getType().equals(filterEntity.getType()));
33 | }
34 | notifyDataSetChanged();
35 | }
36 |
37 | @Override
38 | public View getView(int position, View convertView, ViewGroup parent) {
39 | final ViewHolder holder;
40 | if (convertView == null) {
41 | convertView = mInflater.inflate(R.layout.item_filter_left, null);
42 | holder = new ViewHolder(convertView);
43 | convertView.setTag(holder);
44 | } else {
45 | holder = (ViewHolder) convertView.getTag();
46 | }
47 |
48 | FilterTwoEntity entity = getItem(position);
49 |
50 | holder.tvTitle.setText(entity.getType());
51 | if (entity.isSelected()) {
52 | holder.tvTitle.setTextColor(mContext.getResources().getColor(R.color.colorPrimary));
53 | holder.llRootView.setBackgroundColor(mContext.getResources().getColor(R.color.white));
54 | } else {
55 | holder.tvTitle.setTextColor(mContext.getResources().getColor(R.color.font_black_2));
56 | holder.llRootView.setBackgroundColor(mContext.getResources().getColor(R.color.font_black_6));
57 | }
58 |
59 | return convertView;
60 | }
61 |
62 | static class ViewHolder {
63 | @BindView(R.id.tv_title)
64 | TextView tvTitle;
65 | @BindView(R.id.ll_root_view)
66 | LinearLayout llRootView;
67 |
68 | ViewHolder(View view) {
69 | ButterKnife.bind(this, view);
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/adapter/FilterOneAdapter.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.adapter;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.widget.ImageView;
7 | import android.widget.TextView;
8 |
9 | import com.sunfusheng.StickyHeaderListView.R;
10 | import com.sunfusheng.StickyHeaderListView.model.FilterEntity;
11 |
12 | import java.util.List;
13 |
14 | import butterknife.BindView;
15 | import butterknife.ButterKnife;
16 |
17 | /**
18 | * Created by sunfusheng on 16/4/23.
19 | */
20 | public class FilterOneAdapter extends BaseListAdapter {
21 |
22 | public FilterOneAdapter(Context context) {
23 | super(context);
24 | }
25 |
26 | public FilterOneAdapter(Context context, List list) {
27 | super(context, list);
28 | }
29 |
30 | public void setSelectedEntity(FilterEntity filterEntity) {
31 | for (FilterEntity entity : getData()) {
32 | entity.setSelected(filterEntity != null && entity.getKey().equals(filterEntity.getKey()));
33 | }
34 | notifyDataSetChanged();
35 | }
36 |
37 | @Override
38 | public View getView(int position, View convertView, ViewGroup parent) {
39 | final ViewHolder holder;
40 | if (convertView == null) {
41 | convertView = mInflater.inflate(R.layout.item_filter_one, null);
42 | holder = new ViewHolder(convertView);
43 | convertView.setTag(holder);
44 | } else {
45 | holder = (ViewHolder) convertView.getTag();
46 | }
47 |
48 | FilterEntity entity = getItem(position);
49 |
50 | holder.tvTitle.setText(entity.getKey());
51 | if (entity.isSelected()) {
52 | holder.tvTitle.setTextColor(mContext.getResources().getColor(R.color.colorPrimary));
53 | } else {
54 | holder.tvTitle.setTextColor(mContext.getResources().getColor(R.color.font_black_3));
55 | }
56 |
57 | return convertView;
58 | }
59 |
60 | static class ViewHolder {
61 | @BindView(R.id.iv_image)
62 | ImageView ivImage;
63 | @BindView(R.id.tv_title)
64 | TextView tvTitle;
65 |
66 | ViewHolder(View view) {
67 | ButterKnife.bind(this, view);
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/adapter/FilterRightAdapter.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.adapter;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.widget.ImageView;
7 | import android.widget.TextView;
8 |
9 | import com.sunfusheng.StickyHeaderListView.R;
10 | import com.sunfusheng.StickyHeaderListView.model.FilterEntity;
11 |
12 | import java.util.List;
13 |
14 | import butterknife.BindView;
15 | import butterknife.ButterKnife;
16 |
17 | /**
18 | * Created by sunfusheng on 16/4/23.
19 | */
20 | public class FilterRightAdapter extends BaseListAdapter {
21 |
22 | public FilterRightAdapter(Context context, List list) {
23 | super(context, list);
24 | }
25 |
26 | public void setSelectedEntity(FilterEntity filterEntity) {
27 | for (FilterEntity entity : getData()) {
28 | entity.setSelected(filterEntity != null && entity.getKey().equals(filterEntity.getKey()));
29 | }
30 | notifyDataSetChanged();
31 | }
32 |
33 | @Override
34 | public View getView(int position, View convertView, ViewGroup parent) {
35 | final ViewHolder holder;
36 | if (convertView == null) {
37 | convertView = mInflater.inflate(R.layout.item_filter_one, null);
38 | holder = new ViewHolder(convertView);
39 | convertView.setTag(holder);
40 | } else {
41 | holder = (ViewHolder) convertView.getTag();
42 | }
43 |
44 | FilterEntity entity = getItem(position);
45 |
46 | holder.tvTitle.setText(entity.getKey());
47 | if (entity.isSelected()) {
48 | holder.tvTitle.setTextColor(mContext.getResources().getColor(R.color.colorPrimary));
49 | } else {
50 | holder.tvTitle.setTextColor(mContext.getResources().getColor(R.color.font_black_3));
51 | }
52 |
53 | return convertView;
54 | }
55 |
56 | static class ViewHolder {
57 | @BindView(R.id.iv_image)
58 | ImageView ivImage;
59 | @BindView(R.id.tv_title)
60 | TextView tvTitle;
61 |
62 | ViewHolder(View view) {
63 | ButterKnife.bind(this, view);
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/adapter/HeaderBannerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.adapter;
2 |
3 | import android.support.v4.view.PagerAdapter;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.widget.ImageView;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Created by sunfusheng on 16/4/20.
12 | */
13 | public class HeaderBannerAdapter extends PagerAdapter {
14 |
15 | private List ivList; // ImageView的集合
16 | private int count; // 广告的数量
17 |
18 | public HeaderBannerAdapter(List ivList) {
19 | super();
20 | this.ivList = ivList;
21 | if(ivList != null){
22 | count = ivList.size();
23 | }
24 | }
25 |
26 | @Override
27 | public int getCount() {
28 | return Integer.MAX_VALUE;
29 | }
30 |
31 | @Override
32 | public boolean isViewFromObject(View arg0, Object arg1) {
33 | return arg0 == arg1;
34 | }
35 |
36 | @Override
37 | public void destroyItem(ViewGroup container, int position, Object object) {
38 | }
39 |
40 | @Override
41 | public Object instantiateItem(ViewGroup container, int position) {
42 | int newPosition = position % count;
43 | // 先移除再添加,更新图片在container中的位置(把iv放至container末尾)
44 | ImageView iv = ivList.get(newPosition);
45 | container.removeView(iv);
46 | container.addView(iv);
47 | return iv;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/adapter/HeaderChannelAdapter.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.adapter;
2 |
3 | import android.content.Context;
4 | import android.text.TextUtils;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.TextView;
8 |
9 | import com.sunfusheng.StickyHeaderListView.R;
10 | import com.sunfusheng.StickyHeaderListView.model.ChannelEntity;
11 | import com.sunfusheng.glideimageview.GlideImageView;
12 |
13 | import java.util.List;
14 |
15 | import butterknife.BindView;
16 | import butterknife.ButterKnife;
17 |
18 | /**
19 | * Created by sunfusheng on 16/4/20.
20 | */
21 | public class HeaderChannelAdapter extends BaseListAdapter {
22 |
23 | public HeaderChannelAdapter(Context context, List list) {
24 | super(context, list);
25 | }
26 |
27 | @Override
28 | public View getView(int position, View convertView, ViewGroup parent) {
29 | final ViewHolder holder;
30 | if (convertView == null) {
31 | convertView = mInflater.inflate(R.layout.item_channel, null);
32 | holder = new ViewHolder(convertView);
33 | convertView.setTag(holder);
34 | } else {
35 | holder = (ViewHolder) convertView.getTag();
36 | }
37 |
38 | ChannelEntity entity = getItem(position);
39 |
40 | holder.tvTitle.setText(entity.getTitle());
41 | holder.givImage.loadImage(entity.getImage_url(), R.color.font_black_6);
42 |
43 | if (TextUtils.isEmpty(entity.getTips())) {
44 | holder.tvTips.setVisibility(View.INVISIBLE);
45 | } else {
46 | holder.tvTips.setVisibility(View.VISIBLE);
47 | holder.tvTips.setText(entity.getTips());
48 | }
49 |
50 | return convertView;
51 | }
52 |
53 | static class ViewHolder {
54 | @BindView(R.id.giv_image)
55 | GlideImageView givImage;
56 | @BindView(R.id.tv_title)
57 | TextView tvTitle;
58 | @BindView(R.id.tv_tips)
59 | TextView tvTips;
60 |
61 | ViewHolder(View view) {
62 | ButterKnife.bind(this, view);
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/adapter/HeaderOperationAdapter.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.adapter;
2 |
3 | import android.content.Context;
4 | import android.text.TextUtils;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.TextView;
8 |
9 | import com.sunfusheng.StickyHeaderListView.R;
10 | import com.sunfusheng.StickyHeaderListView.model.OperationEntity;
11 | import com.sunfusheng.glideimageview.GlideImageView;
12 |
13 | import java.util.List;
14 |
15 | import butterknife.BindView;
16 | import butterknife.ButterKnife;
17 |
18 | /**
19 | * Created by sunfusheng on 16/4/20.
20 | */
21 | public class HeaderOperationAdapter extends BaseListAdapter {
22 |
23 | public HeaderOperationAdapter(Context context) {
24 | super(context);
25 | }
26 |
27 | public HeaderOperationAdapter(Context context, List list) {
28 | super(context, list);
29 | }
30 |
31 | @Override
32 | public View getView(int position, View convertView, ViewGroup parent) {
33 | final ViewHolder holder;
34 | if (convertView == null) {
35 | convertView = mInflater.inflate(R.layout.item_operation, null);
36 | holder = new ViewHolder(convertView);
37 | convertView.setTag(holder);
38 | } else {
39 | holder = (ViewHolder) convertView.getTag();
40 | }
41 |
42 | OperationEntity entity = getItem(position);
43 |
44 | holder.tvTitle.setText(entity.getTitle());
45 | holder.givImage.loadImage(entity.getImage_url(), R.color.font_black_6);
46 |
47 | if (TextUtils.isEmpty(entity.getSubtitle())) {
48 | holder.tvSubtitle.setVisibility(View.INVISIBLE);
49 | } else {
50 | holder.tvSubtitle.setVisibility(View.VISIBLE);
51 | holder.tvSubtitle.setText(entity.getSubtitle());
52 | }
53 |
54 | return convertView;
55 | }
56 |
57 | static class ViewHolder {
58 | @BindView(R.id.giv_image)
59 | GlideImageView givImage;
60 | @BindView(R.id.tv_title)
61 | TextView tvTitle;
62 | @BindView(R.id.tv_subtitle)
63 | TextView tvSubtitle;
64 |
65 | ViewHolder(View view) {
66 | ButterKnife.bind(this, view);
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/adapter/TravelingAdapter.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.adapter;
2 |
3 | import android.content.Context;
4 | import android.text.TextUtils;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.AbsListView;
8 | import android.widget.LinearLayout;
9 | import android.widget.RelativeLayout;
10 | import android.widget.TextView;
11 |
12 | import com.sunfusheng.StickyHeaderListView.R;
13 | import com.sunfusheng.StickyHeaderListView.model.TravelingEntity;
14 | import com.sunfusheng.StickyHeaderListView.util.ToastUtil;
15 | import com.sunfusheng.glideimageview.GlideImageView;
16 |
17 | import java.util.ArrayList;
18 | import java.util.List;
19 |
20 | import butterknife.BindView;
21 | import butterknife.ButterKnife;
22 |
23 | /**
24 | * Created by sunfusheng on 16/4/20.
25 | */
26 | public class TravelingAdapter extends BaseListAdapter {
27 |
28 | private boolean isNoData;
29 | private int mHeight;
30 | public static final int ONE_SCREEN_COUNT = 8; // 一屏能显示的个数,这个根据屏幕高度和各自的需求定
31 | public static final int ONE_REQUEST_COUNT = 10; // 一次请求的个数
32 |
33 | public TravelingAdapter(Context context) {
34 | super(context);
35 | }
36 |
37 | public TravelingAdapter(Context context, List list) {
38 | super(context, list);
39 | }
40 |
41 | // 设置数据
42 | public void setData(List list) {
43 | clearAll();
44 | addALL(list);
45 |
46 | isNoData = false;
47 | if (list.size() == 1 && list.get(0).isNoData()) {
48 | // 暂无数据布局
49 | isNoData = list.get(0).isNoData();
50 | mHeight = list.get(0).getHeight();
51 | } else {
52 | // 添加空数据
53 | if (list.size() < ONE_SCREEN_COUNT) {
54 | addALL(createEmptyList(ONE_SCREEN_COUNT - list.size()));
55 | }
56 | }
57 | notifyDataSetChanged();
58 | }
59 |
60 | // 创建不满一屏的空数据
61 | public List createEmptyList(int size) {
62 | List emptyList = new ArrayList<>();
63 | if (size <= 0) return emptyList;
64 | for (int i=0; i category;
12 | private List sorts;
13 | private List filters;
14 |
15 | public List getCategory() {
16 | return category;
17 | }
18 |
19 | public void setCategory(List category) {
20 | this.category = category;
21 | }
22 |
23 | public List getSorts() {
24 | return sorts;
25 | }
26 |
27 | public void setSorts(List sorts) {
28 | this.sorts = sorts;
29 | }
30 |
31 | public List getFilters() {
32 | return filters;
33 | }
34 |
35 | public void setFilters(List filters) {
36 | this.filters = filters;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/model/FilterEntity.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.model;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Created by sunfusheng on 16/4/23.
7 | */
8 | public class FilterEntity implements Serializable {
9 |
10 | private String key;
11 | private String value;
12 | private boolean isSelected;
13 |
14 | public FilterEntity() {
15 | }
16 |
17 | public FilterEntity(String key, String value) {
18 | this.key = key;
19 | this.value = value;
20 | }
21 |
22 | public boolean isSelected() {
23 | return isSelected;
24 | }
25 |
26 | public void setSelected(boolean selected) {
27 | isSelected = selected;
28 | }
29 |
30 | public String getKey() {
31 | return key;
32 | }
33 |
34 | public void setKey(String key) {
35 | this.key = key;
36 | }
37 |
38 | public String getValue() {
39 | return value;
40 | }
41 |
42 | public void setValue(String value) {
43 | this.value = value;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/model/FilterTwoEntity.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.model;
2 |
3 | import java.io.Serializable;
4 | import java.util.List;
5 |
6 | /**
7 | * Created by sunfusheng on 16/4/23.
8 | */
9 | public class FilterTwoEntity implements Serializable {
10 |
11 | private String type;
12 | private List list;
13 | private boolean isSelected;
14 |
15 | public FilterTwoEntity() {
16 | }
17 |
18 | public FilterTwoEntity(String type, List list) {
19 | this.type = type;
20 | this.list = list;
21 | }
22 |
23 | public String getType() {
24 | return type;
25 | }
26 |
27 | public void setType(String type) {
28 | this.type = type;
29 | }
30 |
31 | public boolean isSelected() {
32 | return isSelected;
33 | }
34 |
35 | public void setSelected(boolean selected) {
36 | isSelected = selected;
37 | }
38 |
39 | public List getList() {
40 | return list;
41 | }
42 |
43 | public void setList(List list) {
44 | this.list = list;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/model/OperationEntity.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.model;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Created by sunfusheng on 16/4/20.
7 | */
8 | public class OperationEntity implements Serializable {
9 |
10 | private String title;
11 | private String subtitle;
12 | private String image_url;
13 |
14 | public OperationEntity() {
15 | }
16 |
17 | public String getSubtitle() {
18 | return subtitle;
19 | }
20 |
21 | public void setSubtitle(String subtitle) {
22 | this.subtitle = subtitle;
23 | }
24 |
25 | public OperationEntity(String title, String subtitle, String image_url) {
26 | this.title = title;
27 | this.subtitle = subtitle;
28 | this.image_url = image_url;
29 | }
30 |
31 | public String getTitle() {
32 | return title;
33 | }
34 |
35 | public void setTitle(String title) {
36 | this.title = title;
37 | }
38 |
39 | public String getImage_url() {
40 | return image_url;
41 | }
42 |
43 | public void setImage_url(String image_url) {
44 | this.image_url = image_url;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/model/TravelingEntity.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.model;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Created by sunfusheng on 16/4/20.
7 | */
8 | public class TravelingEntity implements Serializable, Comparable {
9 |
10 | private String type; // 风景、动物、植物、建筑
11 | private String title; // 标题
12 | private String from; // 来源
13 | private int rank; // 排名
14 | private String image_url; // 图片地址
15 |
16 | // 暂无数据属性
17 | private boolean isNoData = false;
18 | private int height;
19 |
20 | public TravelingEntity() {
21 | }
22 |
23 | public TravelingEntity(String type, String title, String from, int rank, String image_url) {
24 | this.type = type;
25 | this.title = title;
26 | this.from = from;
27 | this.rank = rank;
28 | this.image_url = image_url;
29 | }
30 |
31 | public int getHeight() {
32 | return height;
33 | }
34 |
35 | public void setHeight(int height) {
36 | this.height = height;
37 | }
38 |
39 | public boolean isNoData() {
40 | return isNoData;
41 | }
42 |
43 | public void setNoData(boolean noData) {
44 | isNoData = noData;
45 | }
46 |
47 | public String getTitle() {
48 | return title;
49 | }
50 |
51 | public void setTitle(String title) {
52 | this.title = title;
53 | }
54 |
55 | public String getType() {
56 | return type;
57 | }
58 |
59 | public void setType(String type) {
60 | this.type = type;
61 | }
62 |
63 | public String getFrom() {
64 | return from;
65 | }
66 |
67 | public void setFrom(String from) {
68 | this.from = from;
69 | }
70 |
71 | public int getRank() {
72 | return rank;
73 | }
74 |
75 | public void setRank(int rank) {
76 | this.rank = rank;
77 | }
78 |
79 | public String getImage_url() {
80 | return image_url;
81 | }
82 |
83 | public void setImage_url(String image_url) {
84 | this.image_url = image_url;
85 | }
86 |
87 | @Override
88 | public int compareTo(TravelingEntity another) {
89 | return this.getRank() - another.getRank();
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/model/TravelingEntityComparator.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.model;
2 |
3 | import java.util.Comparator;
4 |
5 | /**
6 | * Created by sunfusheng on 16/4/25.
7 | */
8 | public class TravelingEntityComparator implements Comparator {
9 |
10 | @Override
11 | public int compare(TravelingEntity lhs, TravelingEntity rhs) {
12 | return rhs.getRank() - lhs.getRank();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/util/ColorUtil.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.util;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * Created by sunfusheng on 16/4/22.
7 | */
8 | public class ColorUtil {
9 |
10 | // 合成新的颜色值
11 | public static int getNewColorByStartEndColor(Context context, float fraction, int startValue, int endValue) {
12 | return evaluate(fraction, context.getResources().getColor(startValue), context.getResources().getColor(endValue));
13 | }
14 | /**
15 | * 合成新的颜色值
16 | * @param fraction 颜色取值的级别 (0.0f ~ 1.0f)
17 | * @param startValue 开始显示的颜色
18 | * @param endValue 结束显示的颜色
19 | * @return 返回生成新的颜色值
20 | */
21 | public static int evaluate(float fraction, int startValue, int endValue) {
22 | int startA = (startValue >> 24) & 0xff;
23 | int startR = (startValue >> 16) & 0xff;
24 | int startG = (startValue >> 8) & 0xff;
25 | int startB = startValue & 0xff;
26 |
27 | int endA = (endValue >> 24) & 0xff;
28 | int endR = (endValue >> 16) & 0xff;
29 | int endG = (endValue >> 8) & 0xff;
30 | int endB = endValue & 0xff;
31 |
32 | return ((startA + (int) (fraction * (endA - startA))) << 24) |
33 | ((startR + (int) (fraction * (endR - startR))) << 16) |
34 | ((startG + (int) (fraction * (endG - startG))) << 8) |
35 | ((startB + (int) (fraction * (endB - startB))));
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/util/DensityUtil.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.util;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.util.DisplayMetrics;
6 |
7 | public class DensityUtil {
8 |
9 | // 根据手机的分辨率将dp的单位转成px(像素)
10 | public static int dip2px(Context context, float dpValue) {
11 | final float scale = context.getResources().getDisplayMetrics().density;
12 | return (int) (dpValue * scale + 0.5f);
13 | }
14 |
15 | // 根据手机的分辨率将px(像素)的单位转成dp
16 | public static int px2dip(Context context, float pxValue) {
17 | final float scale = context.getResources().getDisplayMetrics().density;
18 | return (int) (pxValue / scale + 0.5f);
19 | }
20 |
21 | // 将px值转换为sp值
22 | public static int px2sp(Context context, float pxValue) {
23 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
24 | return (int) (pxValue / fontScale + 0.5f);
25 | }
26 |
27 | // 将sp值转换为px值
28 | public static int sp2px(Context context, float spValue) {
29 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
30 | return (int) (spValue * fontScale + 0.5f);
31 | }
32 |
33 | // 屏幕宽度(像素)
34 | public static int getWindowWidth(Activity context){
35 | DisplayMetrics metric = new DisplayMetrics();
36 | context.getWindowManager().getDefaultDisplay().getMetrics(metric);
37 | return metric.widthPixels;
38 | }
39 |
40 | // 屏幕高度(像素)
41 | public static int getWindowHeight(Activity activity){
42 | DisplayMetrics metric = new DisplayMetrics();
43 | activity.getWindowManager().getDefaultDisplay().getMetrics(metric);
44 | return metric.heightPixels;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/util/ModelUtil.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.util;
2 |
3 | import com.sunfusheng.StickyHeaderListView.model.ChannelEntity;
4 | import com.sunfusheng.StickyHeaderListView.model.FilterEntity;
5 | import com.sunfusheng.StickyHeaderListView.model.FilterTwoEntity;
6 | import com.sunfusheng.StickyHeaderListView.model.OperationEntity;
7 | import com.sunfusheng.StickyHeaderListView.model.TravelingEntity;
8 | import com.sunfusheng.StickyHeaderListView.model.TravelingEntityComparator;
9 |
10 | import java.util.ArrayList;
11 | import java.util.Collections;
12 | import java.util.Comparator;
13 | import java.util.List;
14 |
15 | /**
16 | * 好吧,让你找到了,这是假的数据源
17 | *
18 | * Created by sunfusheng on 16/4/22.
19 | */
20 | public class ModelUtil {
21 |
22 | public static final String type_scenery = "风景";
23 | public static final String type_building = "建筑";
24 | public static final String type_animal = "动物";
25 | public static final String type_plant = "植物";
26 |
27 | // 广告数据
28 | public static List getBannerData() {
29 | List adList = new ArrayList<>();
30 | adList.add("http://img2.imgtn.bdimg.com/it/u=2850936076,2080165544&fm=206&gp=0.jpg");
31 | adList.add("http://img3.imgtn.bdimg.com/it/u=524208507,12616758&fm=206&gp=0.jpg");
32 | adList.add("http://img3.imgtn.bdimg.com/it/u=698582197,4250615262&fm=206&gp=0.jpg");
33 | adList.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1519377816881&di=47c3c5f8f8e2010ac37d2267736a79a2&imgtype=0&src=http%3A%2F%2Fwww.fansimg.com%2Fportal%2F201406%2F10%2F105328z4xjovysf2kbkyfh.jpg.thumb.jpg");
34 | return adList;
35 | }
36 |
37 | // 频道数据
38 | public static List getChannelData() {
39 | List channelList = new ArrayList<>();
40 | channelList.add(new ChannelEntity("中国", "天安门", "http://img2.imgtn.bdimg.com/it/u=2850936076,2080165544&fm=206&gp=0.jpg"));
41 | channelList.add(new ChannelEntity("美国", "白宫", "http://img3.imgtn.bdimg.com/it/u=524208507,12616758&fm=206&gp=0.jpg"));
42 | channelList.add(new ChannelEntity("英国", "伦敦塔桥", "http://img3.imgtn.bdimg.com/it/u=698582197,4250615262&fm=206&gp=0.jpg"));
43 | channelList.add(new ChannelEntity("德国", "城堡", "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1519377816881&di=47c3c5f8f8e2010ac37d2267736a79a2&imgtype=0&src=http%3A%2F%2Fwww.fansimg.com%2Fportal%2F201406%2F10%2F105328z4xjovysf2kbkyfh.jpg.thumb.jpg"));
44 | channelList.add(new ChannelEntity("西班牙", "巴塞罗那", "http://img5.imgtn.bdimg.com/it/u=3191365283,111438732&fm=21&gp=0.jpg"));
45 | channelList.add(new ChannelEntity("意大利", "比萨斜塔", "http://img5.imgtn.bdimg.com/it/u=482494496,1350922497&fm=206&gp=0.jpg"));
46 | return channelList;
47 | }
48 |
49 | // 运营数据
50 | public static List getOperationData() {
51 | List operationList = new ArrayList<>();
52 | operationList.add(new OperationEntity("度假游", "度假的天堂", "http://img2.imgtn.bdimg.com/it/u=4081165325,36916497&fm=21&gp=0.jpg"));
53 | operationList.add(new OperationEntity("蜜月游", "浪漫的港湾", "http://img4.imgtn.bdimg.com/it/u=4141168524,78676102&fm=21&gp=0.jpg"));
54 | return operationList;
55 | }
56 |
57 | // ListView数据
58 | public static List getTravelingData() {
59 | List travelingList = new ArrayList<>();
60 | travelingList.add(new TravelingEntity(type_scenery, "大理", "中国", 1, "http://img5.imgtn.bdimg.com/it/u=2769726205,1778838650&fm=21&gp=0.jpg"));
61 | travelingList.add(new TravelingEntity(type_scenery, "", "西班牙", 20, "http://img1.imgtn.bdimg.com/it/u=1832737924,144748431&fm=21&gp=0.jpg"));
62 | travelingList.add(new TravelingEntity(type_scenery, "", "意大利", 21, "http://img5.imgtn.bdimg.com/it/u=2091366266,1524114981&fm=21&gp=0.jpg"));
63 | travelingList.add(new TravelingEntity(type_scenery, "拱门", "美国", 5, "http://img4.imgtn.bdimg.com/it/u=3673198446,2175517238&fm=206&gp=0.jpg"));
64 | travelingList.add(new TravelingEntity(type_plant, "荷花", "中国", 4, "http://img4.imgtn.bdimg.com/it/u=3052089044,3887933556&fm=21&gp=0.jpg"));
65 | travelingList.add(new TravelingEntity(type_building, "", "西班牙", 18, "http://img2.imgtn.bdimg.com/it/u=140083303,1086773509&fm=21&gp=0.jpg"));
66 | travelingList.add(new TravelingEntity(type_scenery, "", "西班牙", 19, "http://img5.imgtn.bdimg.com/it/u=1424970962,1243597989&fm=21&gp=0.jpg"));
67 | travelingList.add(new TravelingEntity(type_animal, "水貂", "美国", 7, "http://img4.imgtn.bdimg.com/it/u=1387833256,3665925904&fm=21&gp=0.jpg"));
68 | travelingList.add(new TravelingEntity(type_plant, "仙人掌", "美国", 8, "http://img1.imgtn.bdimg.com/it/u=3808801622,1608105009&fm=21&gp=0.jpg"));
69 | travelingList.add(new TravelingEntity(type_scenery, "威尔士", "英国", 9, "http://img4.imgtn.bdimg.com/it/u=2440866214,1867472386&fm=21&gp=0.jpg"));
70 | travelingList.add(new TravelingEntity(type_building, "伦敦塔桥", "英国", 10, "http://img3.imgtn.bdimg.com/it/u=3040385967,1031044866&fm=21&gp=0.jpg"));
71 | travelingList.add(new TravelingEntity(type_animal, "", "英国", 11, "http://img3.imgtn.bdimg.com/it/u=1896821840,3837942977&fm=21&gp=0.jpg"));
72 | travelingList.add(new TravelingEntity(type_plant, "", "英国", 12, "http://img3.imgtn.bdimg.com/it/u=2745651862,279304559&fm=21&gp=0.jpg"));
73 | travelingList.add(new TravelingEntity(type_scenery, "", "德国", 13, "http://img3.imgtn.bdimg.com/it/u=4137420324,1489843447&fm=206&gp=0.jpg"));
74 | travelingList.add(new TravelingEntity(type_building, "自由女神像", "美国", 6, "http://img3.imgtn.bdimg.com/it/u=2566161363,1140447270&fm=206&gp=0.jpg"));
75 | travelingList.add(new TravelingEntity(type_building, "拉萨", "中国", 2, "http://img1.imgtn.bdimg.com/it/u=372954611,2699392190&fm=21&gp=0.jpg"));
76 | travelingList.add(new TravelingEntity(type_animal, "熊猫", "中国", 3, "http://img0.imgtn.bdimg.com/it/u=1022702848,645282860&fm=206&gp=0.jpg"));
77 | travelingList.add(new TravelingEntity(type_building, "", "德国", 14, "http://img1.imgtn.bdimg.com/it/u=3436675019,2609348874&fm=206&gp=0.jpg"));
78 | travelingList.add(new TravelingEntity(type_animal, "狗熊", "德国", 15, "http://img4.imgtn.bdimg.com/it/u=4280994062,276434784&fm=21&gp=0.jpg"));
79 | travelingList.add(new TravelingEntity(type_plant, "", "德国", 16, "http://img0.imgtn.bdimg.com/it/u=1644854868,3172549858&fm=21&gp=0.jpg"));
80 | travelingList.add(new TravelingEntity(type_scenery, "", "西班牙", 17, "http://img4.imgtn.bdimg.com/it/u=620137884,621556624&fm=21&gp=0.jpg"));
81 | travelingList.add(new TravelingEntity(type_building, "", "意大利", 22, "http://img0.imgtn.bdimg.com/it/u=3631118072,1530723002&fm=206&gp=0.jpg"));
82 | return travelingList;
83 | }
84 |
85 | // 分类数据
86 | public static List getCategoryData() {
87 | List list = new ArrayList<>();
88 | list.add(new FilterTwoEntity(type_scenery, getFilterData()));
89 | list.add(new FilterTwoEntity(type_building, getFilterData()));
90 | list.add(new FilterTwoEntity(type_animal, getFilterData()));
91 | list.add(new FilterTwoEntity(type_plant, getFilterData()));
92 | return list;
93 | }
94 |
95 | // 排序数据
96 | public static List getSortData() {
97 | List list = new ArrayList<>();
98 | list.add(new FilterEntity("排序从高到低", "1"));
99 | list.add(new FilterEntity("排序从低到高", "2"));
100 | return list;
101 | }
102 |
103 | // 筛选数据
104 | public static List getFilterData() {
105 | List list = new ArrayList<>();
106 | list.add(new FilterEntity("中国", "1"));
107 | list.add(new FilterEntity("美国", "2"));
108 | list.add(new FilterEntity("英国", "3"));
109 | list.add(new FilterEntity("德国", "4"));
110 | list.add(new FilterEntity("西班牙", "5"));
111 | list.add(new FilterEntity("意大利", "6"));
112 | return list;
113 | }
114 |
115 | // ListView分类数据
116 | public static List getCategoryTravelingData(FilterTwoEntity leftEntity, FilterEntity rightEntity) {
117 | List list = getTravelingData();
118 | List travelingList = new ArrayList<>();
119 | int size = list.size();
120 | for (int i=0; i getSortTravelingData(FilterEntity entity) {
130 | List list = getTravelingData();
131 | Comparator ascComparator = new TravelingEntityComparator();
132 | if (entity.getKey().equals("排序从高到低")) {
133 | Collections.sort(list);
134 | } else {
135 | Collections.sort(list, ascComparator);
136 | }
137 | return list;
138 | }
139 |
140 | // ListView筛选数据
141 | public static List getFilterTravelingData(FilterEntity entity) {
142 | List list = getTravelingData();
143 | List travelingList = new ArrayList<>();
144 | int size = list.size();
145 | for (int i=0; i getNoDataEntity(int height) {
155 | List list = new ArrayList<>();
156 | TravelingEntity entity = new TravelingEntity();
157 | entity.setNoData(true);
158 | entity.setHeight(height);
159 | list.add(entity);
160 | return list;
161 | }
162 |
163 | }
164 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/util/StatusBarUtil.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.util;
2 |
3 | import android.app.Activity;
4 | import android.graphics.Color;
5 | import android.os.Build;
6 | import android.view.View;
7 | import android.view.Window;
8 | import android.view.WindowManager;
9 |
10 | import java.lang.reflect.Field;
11 | import java.lang.reflect.Method;
12 |
13 | /**
14 | * Created by sunfusheng on 16/11/20.
15 | */
16 | public class StatusBarUtil {
17 |
18 | // 设置状态栏透明与字体颜色
19 | public static void setStatusBarTranslucent(Activity acitivty, boolean isLightStatusBar) {
20 | Window window = acitivty.getWindow();
21 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
22 | window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
23 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
24 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
25 | window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
26 | | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
27 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
28 | window.setStatusBarColor(Color.TRANSPARENT);
29 | }
30 |
31 | if (isXiaomi()) {
32 | setXiaomiStatusBar(window, isLightStatusBar);
33 | } else if (isMeizu()) {
34 | setMeizuStatusBar(window, isLightStatusBar);
35 | }
36 | }
37 |
38 | // 是否是小米手机
39 | public static boolean isXiaomi() {
40 | return "Xiaomi".equals(Build.MANUFACTURER);
41 | }
42 |
43 | // 设置小米状态栏
44 | public static void setXiaomiStatusBar(Window window, boolean isLightStatusBar) {
45 | Class extends Window> clazz = window.getClass();
46 | try {
47 | Class> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
48 | Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
49 | int darkModeFlag = field.getInt(layoutParams);
50 | Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
51 | extraFlagField.invoke(window, isLightStatusBar ? darkModeFlag : 0, darkModeFlag);
52 | } catch (Exception e) {
53 | e.printStackTrace();
54 | }
55 | }
56 |
57 | // 是否是魅族手机
58 | public static boolean isMeizu() {
59 | try {
60 | Method method = Build.class.getMethod("hasSmartBar");
61 | return method != null;
62 | } catch (NoSuchMethodException e) {
63 | }
64 | return false;
65 | }
66 |
67 | // 设置魅族状态栏
68 | public static void setMeizuStatusBar(Window window, boolean isLightStatusBar) {
69 | WindowManager.LayoutParams params = window.getAttributes();
70 | try {
71 | Field darkFlag = WindowManager.LayoutParams.class.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
72 | Field meizuFlags = WindowManager.LayoutParams.class.getDeclaredField("meizuFlags");
73 | darkFlag.setAccessible(true);
74 | meizuFlags.setAccessible(true);
75 | int bit = darkFlag.getInt(null);
76 | int value = meizuFlags.getInt(params);
77 | if (isLightStatusBar) {
78 | value |= bit;
79 | } else {
80 | value &= ~bit;
81 | }
82 | meizuFlags.setInt(params, value);
83 | window.setAttributes(params);
84 | darkFlag.setAccessible(false);
85 | meizuFlags.setAccessible(false);
86 | } catch (Exception e) {
87 | e.printStackTrace();
88 | }
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/util/ToastUtil.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.util;
2 |
3 | import android.content.Context;
4 | import android.text.TextUtils;
5 | import android.widget.Toast;
6 |
7 | /**
8 | * Created by sunfusheng on 15/8/7.
9 | */
10 | public class ToastUtil {
11 |
12 | private static Toast mToast;
13 |
14 | public static void show(Context context, String message) {
15 | if (context == null || TextUtils.isEmpty(message)) return;
16 | int duration;
17 | if (message.length() > 10) {
18 | duration = Toast.LENGTH_LONG; //如果字符串比较长,那么显示的时间也长一些。
19 | } else {
20 | duration = Toast.LENGTH_SHORT;
21 | }
22 | if (mToast == null) {
23 | mToast = Toast.makeText(context, message, duration);
24 | } else {
25 | mToast.setText(message);
26 | mToast.setDuration(duration);
27 | }
28 | mToast.show();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/view/AbsHeaderView.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.view;
2 |
3 | import android.app.Activity;
4 | import android.view.LayoutInflater;
5 | import android.widget.ListView;
6 |
7 | import java.util.List;
8 |
9 | public abstract class AbsHeaderView {
10 |
11 | protected Activity mActivity;
12 | protected LayoutInflater mInflate;
13 | protected T mEntity;
14 |
15 | public AbsHeaderView(Activity activity) {
16 | this.mActivity = activity;
17 | mInflate = LayoutInflater.from(activity);
18 | }
19 |
20 | public boolean fillView(T t, ListView listView) {
21 | if (t == null) {
22 | return false;
23 | }
24 | if ((t instanceof List) && ((List) t).size() == 0) {
25 | return false;
26 | }
27 | this.mEntity = t;
28 | getView(t, listView);
29 | return true;
30 | }
31 |
32 | protected abstract void getView(T t, ListView listView);
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/view/FilterView.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.view;
2 |
3 | import android.animation.ObjectAnimator;
4 | import android.app.Activity;
5 | import android.content.Context;
6 | import android.util.AttributeSet;
7 | import android.view.LayoutInflater;
8 | import android.view.MotionEvent;
9 | import android.view.View;
10 | import android.view.ViewTreeObserver;
11 | import android.view.animation.Animation;
12 | import android.view.animation.RotateAnimation;
13 | import android.widget.AdapterView;
14 | import android.widget.ImageView;
15 | import android.widget.LinearLayout;
16 | import android.widget.ListView;
17 | import android.widget.TextView;
18 |
19 | import com.sunfusheng.StickyHeaderListView.R;
20 | import com.sunfusheng.StickyHeaderListView.adapter.FilterLeftAdapter;
21 | import com.sunfusheng.StickyHeaderListView.adapter.FilterOneAdapter;
22 | import com.sunfusheng.StickyHeaderListView.adapter.FilterRightAdapter;
23 | import com.sunfusheng.StickyHeaderListView.model.FilterData;
24 | import com.sunfusheng.StickyHeaderListView.model.FilterEntity;
25 | import com.sunfusheng.StickyHeaderListView.model.FilterTwoEntity;
26 |
27 | import butterknife.BindView;
28 | import butterknife.ButterKnife;
29 |
30 | /**
31 | * Created by sunfusheng on 16/4/20.
32 | */
33 | public class FilterView extends LinearLayout implements View.OnClickListener {
34 |
35 | @BindView(R.id.tv_category_title)
36 | TextView tvCategoryTitle;
37 | @BindView(R.id.iv_category_arrow)
38 | ImageView ivCategoryArrow;
39 | @BindView(R.id.tv_sort_title)
40 | TextView tvSortTitle;
41 | @BindView(R.id.iv_sort_arrow)
42 | ImageView ivSortArrow;
43 | @BindView(R.id.tv_filter_title)
44 | TextView tvFilterTitle;
45 | @BindView(R.id.iv_filter_arrow)
46 | ImageView ivFilterArrow;
47 | @BindView(R.id.ll_category)
48 | LinearLayout llCategory;
49 | @BindView(R.id.ll_sort)
50 | LinearLayout llSort;
51 | @BindView(R.id.ll_filter)
52 | LinearLayout llFilter;
53 | @BindView(R.id.lv_left)
54 | ListView lvLeft;
55 | @BindView(R.id.lv_right)
56 | ListView lvRight;
57 | @BindView(R.id.ll_head_layout)
58 | LinearLayout llHeadLayout;
59 | @BindView(R.id.ll_content_list_view)
60 | LinearLayout llContentListView;
61 | @BindView(R.id.view_mask_bg)
62 | View viewMaskBg;
63 |
64 | private Context mContext;
65 | private Activity mActivity;
66 |
67 | private int filterPosition = -1;
68 | private int lastFilterPosition = -1;
69 | public static final int POSITION_CATEGORY = 0; // 分类的位置
70 | public static final int POSITION_SORT = 1; // 排序的位置
71 | public static final int POSITION_FILTER = 2; // 筛选的位置
72 |
73 | private boolean isShowing = false;
74 | private int panelHeight;
75 | private FilterData filterData;
76 |
77 | private FilterLeftAdapter leftAdapter;
78 | private FilterRightAdapter rightAdapter;
79 | private FilterOneAdapter sortAdapter;
80 | private FilterOneAdapter filterAdapter;
81 |
82 | private FilterTwoEntity leftSelectedCategoryEntity; // 被选择的分类项左侧数据
83 | private FilterEntity rightSelectedCategoryEntity; // 被选择的分类项右侧数据
84 | private FilterEntity selectedSortEntity; // 被选择的排序项
85 | private FilterEntity selectedFilterEntity; // 被选择的筛选项
86 |
87 | public FilterView(Context context, AttributeSet attrs) {
88 | super(context, attrs);
89 | init(context);
90 | }
91 |
92 | public FilterView(Context context, AttributeSet attrs, int defStyleAttr) {
93 | super(context, attrs, defStyleAttr);
94 | init(context);
95 | }
96 |
97 | private void init(Context context) {
98 | this.mContext = context;
99 | View view = LayoutInflater.from(context).inflate(R.layout.view_filter_layout, this);
100 | ButterKnife.bind(this, view);
101 |
102 | initView();
103 | initListener();
104 | }
105 |
106 | private void initView() {
107 | viewMaskBg.setVisibility(GONE);
108 | llContentListView.setVisibility(GONE);
109 | }
110 |
111 | private void initListener() {
112 | llCategory.setOnClickListener(this);
113 | llSort.setOnClickListener(this);
114 | llFilter.setOnClickListener(this);
115 | viewMaskBg.setOnClickListener(this);
116 | llContentListView.setOnTouchListener(new OnTouchListener() {
117 | @Override
118 | public boolean onTouch(View v, MotionEvent event) {
119 | return true;
120 | }
121 | });
122 | }
123 |
124 | @Override
125 | public void onClick(View v) {
126 | switch (v.getId()) {
127 | case R.id.ll_category:
128 | filterPosition = 0;
129 | if (onFilterClickListener != null) {
130 | onFilterClickListener.onFilterClick(filterPosition);
131 | }
132 | break;
133 | case R.id.ll_sort:
134 | filterPosition = 1;
135 | if (onFilterClickListener != null) {
136 | onFilterClickListener.onFilterClick(filterPosition);
137 | }
138 | break;
139 | case R.id.ll_filter:
140 | filterPosition = 2;
141 | if (onFilterClickListener != null) {
142 | onFilterClickListener.onFilterClick(filterPosition);
143 | }
144 | break;
145 | case R.id.view_mask_bg:
146 | hide();
147 | break;
148 | }
149 | }
150 |
151 | // 复位筛选的显示状态
152 | public void resetViewStatus() {
153 | tvCategoryTitle.setTextColor(mContext.getResources().getColor(R.color.font_black_2));
154 | ivCategoryArrow.setImageResource(R.mipmap.home_down_arrow);
155 |
156 | tvSortTitle.setTextColor(mContext.getResources().getColor(R.color.font_black_2));
157 | ivSortArrow.setImageResource(R.mipmap.home_down_arrow);
158 |
159 | tvFilterTitle.setTextColor(mContext.getResources().getColor(R.color.font_black_2));
160 | ivFilterArrow.setImageResource(R.mipmap.home_down_arrow);
161 | }
162 |
163 | // 复位所有的状态
164 | public void resetAllStatus() {
165 | resetViewStatus();
166 | hide();
167 | }
168 |
169 | // 设置分类数据
170 | private void setCategoryAdapter() {
171 | lvLeft.setVisibility(VISIBLE);
172 | lvRight.setVisibility(VISIBLE);
173 |
174 | // 左边列表视图
175 | leftAdapter = new FilterLeftAdapter(mContext, filterData.getCategory());
176 | lvLeft.setAdapter(leftAdapter);
177 | if (leftSelectedCategoryEntity == null) {
178 | leftSelectedCategoryEntity = filterData.getCategory().get(0);
179 | }
180 | leftAdapter.setSelectedEntity(leftSelectedCategoryEntity);
181 |
182 | lvLeft.setOnItemClickListener(new AdapterView.OnItemClickListener() {
183 | @Override
184 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
185 | leftSelectedCategoryEntity = filterData.getCategory().get(position);
186 | leftAdapter.setSelectedEntity(leftSelectedCategoryEntity);
187 |
188 | // 右边列表视图
189 | rightAdapter = new FilterRightAdapter(mContext, leftSelectedCategoryEntity.getList());
190 | lvRight.setAdapter(rightAdapter);
191 | rightAdapter.setSelectedEntity(rightSelectedCategoryEntity);
192 | }
193 | });
194 |
195 | // 右边列表视图
196 | rightAdapter = new FilterRightAdapter(mContext, leftSelectedCategoryEntity.getList());
197 | lvRight.setAdapter(rightAdapter);
198 | rightAdapter.setSelectedEntity(rightSelectedCategoryEntity);
199 | lvRight.setOnItemClickListener(new AdapterView.OnItemClickListener() {
200 | @Override
201 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
202 | rightSelectedCategoryEntity = leftSelectedCategoryEntity.getList().get(position);
203 | rightAdapter.setSelectedEntity(rightSelectedCategoryEntity);
204 | if (onItemCategoryClickListener != null) {
205 | onItemCategoryClickListener.onItemCategoryClick(leftSelectedCategoryEntity, rightSelectedCategoryEntity);
206 | }
207 | hide();
208 | }
209 | });
210 | }
211 |
212 | // 设置排序数据
213 | private void setSortAdapter() {
214 | lvLeft.setVisibility(GONE);
215 | lvRight.setVisibility(VISIBLE);
216 |
217 | sortAdapter = new FilterOneAdapter(mContext, filterData.getSorts());
218 | lvRight.setAdapter(sortAdapter);
219 |
220 | lvRight.setOnItemClickListener(new AdapterView.OnItemClickListener() {
221 | @Override
222 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
223 | selectedSortEntity = filterData.getSorts().get(position);
224 | sortAdapter.setSelectedEntity(selectedSortEntity);
225 | if (onItemSortClickListener != null) {
226 | onItemSortClickListener.onItemSortClick(selectedSortEntity);
227 | }
228 | hide();
229 | }
230 | });
231 | }
232 |
233 | // 设置筛选数据
234 | private void setFilterAdapter() {
235 | lvLeft.setVisibility(GONE);
236 | lvRight.setVisibility(VISIBLE);
237 |
238 | filterAdapter = new FilterOneAdapter(mContext, filterData.getFilters());
239 | lvRight.setAdapter(filterAdapter);
240 |
241 | lvRight.setOnItemClickListener(new AdapterView.OnItemClickListener() {
242 | @Override
243 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
244 | selectedFilterEntity = filterData.getFilters().get(position);
245 | filterAdapter.setSelectedEntity(selectedFilterEntity);
246 | if (onItemFilterClickListener != null) {
247 | onItemFilterClickListener.onItemFilterClick(selectedFilterEntity);
248 | }
249 | hide();
250 | }
251 | });
252 | }
253 |
254 | // 动画显示
255 | public void show(int position) {
256 | if (isShowing && lastFilterPosition == position) {
257 | hide();
258 | return;
259 | } else if (!isShowing) {
260 | viewMaskBg.setVisibility(VISIBLE);
261 | llContentListView.setVisibility(VISIBLE);
262 | llContentListView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
263 | @Override
264 | public void onGlobalLayout() {
265 | llContentListView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
266 | panelHeight = llContentListView.getHeight();
267 | ObjectAnimator.ofFloat(llContentListView, "translationY", -panelHeight, 0).setDuration(200).start();
268 | }
269 | });
270 | }
271 | isShowing = true;
272 | resetViewStatus();
273 | rotateArrowUp(position);
274 | rotateArrowDown(lastFilterPosition);
275 | lastFilterPosition = position;
276 |
277 | switch (position) {
278 | case POSITION_CATEGORY:
279 | tvCategoryTitle.setTextColor(mActivity.getResources().getColor(R.color.colorPrimary));
280 | ivCategoryArrow.setImageResource(R.mipmap.home_down_arrow_red);
281 | setCategoryAdapter();
282 | break;
283 | case POSITION_SORT:
284 | tvSortTitle.setTextColor(mActivity.getResources().getColor(R.color.colorPrimary));
285 | ivSortArrow.setImageResource(R.mipmap.home_down_arrow_red);
286 | setSortAdapter();
287 | break;
288 | case POSITION_FILTER:
289 | tvFilterTitle.setTextColor(mActivity.getResources().getColor(R.color.colorPrimary));
290 | ivFilterArrow.setImageResource(R.mipmap.home_down_arrow_red);
291 | setFilterAdapter();
292 | break;
293 | }
294 | }
295 |
296 | // 隐藏动画
297 | public void hide() {
298 | isShowing = false;
299 | resetViewStatus();
300 | rotateArrowDown(filterPosition);
301 | rotateArrowDown(lastFilterPosition);
302 | filterPosition = -1;
303 | lastFilterPosition = -1;
304 | viewMaskBg.setVisibility(View.GONE);
305 | ObjectAnimator.ofFloat(llContentListView, "translationY", 0, -panelHeight).setDuration(200).start();
306 | }
307 |
308 | // 设置筛选数据
309 | public void setFilterData(Activity activity, FilterData filterData) {
310 | this.mActivity = activity;
311 | this.filterData = filterData;
312 | }
313 |
314 | // 是否显示
315 | public boolean isShowing() {
316 | return isShowing;
317 | }
318 |
319 | public int getFilterPosition() {
320 | return filterPosition;
321 | }
322 |
323 | // 旋转箭头向上
324 | private void rotateArrowUp(int position) {
325 | switch (position) {
326 | case POSITION_CATEGORY:
327 | rotateArrowUpAnimation(ivCategoryArrow);
328 | break;
329 | case POSITION_SORT:
330 | rotateArrowUpAnimation(ivSortArrow);
331 | break;
332 | case POSITION_FILTER:
333 | rotateArrowUpAnimation(ivFilterArrow);
334 | break;
335 | }
336 | }
337 |
338 | // 旋转箭头向下
339 | private void rotateArrowDown(int position) {
340 | switch (position) {
341 | case POSITION_CATEGORY:
342 | rotateArrowDownAnimation(ivCategoryArrow);
343 | break;
344 | case POSITION_SORT:
345 | rotateArrowDownAnimation(ivSortArrow);
346 | break;
347 | case POSITION_FILTER:
348 | rotateArrowDownAnimation(ivFilterArrow);
349 | break;
350 | }
351 | }
352 |
353 | // 旋转箭头向上
354 | public static void rotateArrowUpAnimation(final ImageView iv) {
355 | if (iv == null) return;
356 | RotateAnimation animation = new RotateAnimation(0f, 180f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
357 | animation.setDuration(200);
358 | animation.setFillAfter(true);
359 | iv.startAnimation(animation);
360 | }
361 |
362 | // 旋转箭头向下
363 | public static void rotateArrowDownAnimation(final ImageView iv) {
364 | if (iv == null) return;
365 | RotateAnimation animation = new RotateAnimation(180f, 0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
366 | animation.setDuration(200);
367 | animation.setFillAfter(true);
368 | iv.startAnimation(animation);
369 | }
370 |
371 | // 筛选视图点击
372 | private OnFilterClickListener onFilterClickListener;
373 | public void setOnFilterClickListener(OnFilterClickListener onFilterClickListener) {
374 | this.onFilterClickListener = onFilterClickListener;
375 | }
376 | public interface OnFilterClickListener {
377 | void onFilterClick(int position);
378 | }
379 |
380 | // 分类Item点击
381 | private OnItemCategoryClickListener onItemCategoryClickListener;
382 | public void setOnItemCategoryClickListener(OnItemCategoryClickListener onItemCategoryClickListener) {
383 | this.onItemCategoryClickListener = onItemCategoryClickListener;
384 | }
385 | public interface OnItemCategoryClickListener {
386 | void onItemCategoryClick(FilterTwoEntity leftEntity, FilterEntity rightEntity);
387 | }
388 |
389 | // 排序Item点击
390 | private OnItemSortClickListener onItemSortClickListener;
391 | public void setOnItemSortClickListener(OnItemSortClickListener onItemSortClickListener) {
392 | this.onItemSortClickListener = onItemSortClickListener;
393 | }
394 | public interface OnItemSortClickListener {
395 | void onItemSortClick(FilterEntity entity);
396 | }
397 |
398 | // 筛选Item点击
399 | private OnItemFilterClickListener onItemFilterClickListener;
400 | public void setOnItemFilterClickListener(OnItemFilterClickListener onItemFilterClickListener) {
401 | this.onItemFilterClickListener = onItemFilterClickListener;
402 | }
403 | public interface OnItemFilterClickListener {
404 | void onItemFilterClick(FilterEntity entity);
405 | }
406 |
407 | }
408 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/view/FixedGridView.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.view;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.widget.GridView;
6 |
7 | /**
8 | * Created by sunfusheng on 16/4/21.
9 | */
10 | public class FixedGridView extends GridView {
11 |
12 | public FixedGridView(Context context) {
13 | super(context);
14 | }
15 |
16 | public FixedGridView(Context context, AttributeSet attrs) {
17 | super(context, attrs);
18 | }
19 |
20 | public FixedGridView(Context context, AttributeSet attrs, int defStyle) {
21 | super(context, attrs, defStyle);
22 | }
23 |
24 | @Override
25 | public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
26 | int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
27 | super.onMeasure(widthMeasureSpec, expandSpec);
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/view/FixedSpeedScroller.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.view;
2 |
3 | import android.content.Context;
4 | import android.view.animation.Interpolator;
5 | import android.widget.Scroller;
6 |
7 | /**
8 | * Created by sunfusheng on 16/8/18.
9 | */
10 | public class FixedSpeedScroller extends Scroller {
11 |
12 | private int mDuration = 1000;
13 |
14 | public FixedSpeedScroller(Context context) {
15 | super(context);
16 | }
17 |
18 | public FixedSpeedScroller(Context context, Interpolator interpolator) {
19 | super(context, interpolator);
20 | }
21 |
22 | @Override
23 | public void startScroll(int startX, int startY, int dx, int dy, int duration) {
24 | super.startScroll(startX, startY, dx, dy, mDuration);
25 | }
26 |
27 | @Override
28 | public void startScroll(int startX, int startY, int dx, int dy) {
29 | super.startScroll(startX, startY, dx, dy, mDuration);
30 | }
31 |
32 | public void setDuration(int time) {
33 | mDuration = time;
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/view/HeaderBannerView.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.view;
2 |
3 | import android.app.Activity;
4 | import android.os.Handler;
5 | import android.os.Message;
6 | import android.support.v4.view.ViewPager;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.view.animation.AccelerateDecelerateInterpolator;
10 | import android.widget.AbsListView;
11 | import android.widget.ImageView;
12 | import android.widget.LinearLayout;
13 | import android.widget.ListView;
14 | import android.widget.RelativeLayout;
15 |
16 | import com.sunfusheng.StickyHeaderListView.R;
17 | import com.sunfusheng.StickyHeaderListView.adapter.HeaderBannerAdapter;
18 | import com.sunfusheng.StickyHeaderListView.util.DensityUtil;
19 | import com.sunfusheng.glideimageview.GlideImageView;
20 |
21 | import java.lang.reflect.Field;
22 | import java.util.ArrayList;
23 | import java.util.List;
24 |
25 | import butterknife.BindView;
26 | import butterknife.ButterKnife;
27 |
28 | public class HeaderBannerView extends AbsHeaderView> {
29 |
30 | @BindView(R.id.vp_banner)
31 | ViewPager vpBanner;
32 | @BindView(R.id.ll_index_container)
33 | LinearLayout llIndexContainer;
34 | @BindView(R.id.rl_banner)
35 | RelativeLayout rlBanner;
36 |
37 | private static final int BANNER_TYPE = 0;
38 | private static final int BANNER_TIME = 5000; // ms
39 | private List ivList;
40 | private int bannerHeight;
41 | private int bannerCount;
42 |
43 | private Handler mHandler = new Handler() {
44 | @Override
45 | public void handleMessage(Message msg) {
46 | super.handleMessage(msg);
47 | if (msg.what == BANNER_TYPE) {
48 | vpBanner.setCurrentItem(vpBanner.getCurrentItem() + 1);
49 | enqueueBannerLoopMessage();
50 | }
51 | }
52 | };
53 |
54 | public HeaderBannerView(Activity context) {
55 | super(context);
56 | ivList = new ArrayList<>();
57 | bannerHeight = DensityUtil.getWindowWidth(context) * 9 / 16;
58 | }
59 |
60 | @Override
61 | protected void getView(List list, ListView listView) {
62 | View view = mInflate.inflate(R.layout.header_banner_layout, listView, false);
63 | ButterKnife.bind(this, view);
64 |
65 | dealWithTheView(list);
66 | listView.addHeaderView(view);
67 | }
68 |
69 | private void dealWithTheView(List list) {
70 | ivList.clear();
71 |
72 | bannerCount = list.size();
73 | if (bannerCount == 2) {
74 | list.addAll(list);
75 | }
76 |
77 | AbsListView.LayoutParams layoutParams = (AbsListView.LayoutParams) rlBanner.getLayoutParams();
78 | layoutParams.height = bannerHeight;
79 | rlBanner.setLayoutParams(layoutParams);
80 |
81 | createImageViews(list);
82 |
83 | HeaderBannerAdapter adapter = new HeaderBannerAdapter(ivList);
84 | vpBanner.setAdapter(adapter);
85 |
86 | addIndicatorImageViews();
87 | setViewPagerChangeListener();
88 | controlViewPagerSpeed(vpBanner, 500);
89 | }
90 |
91 | // 创建要显示的ImageView
92 | private void createImageViews(List list) {
93 | for (int i = 0; i < list.size(); i++) {
94 | GlideImageView imageView = new GlideImageView(mActivity);
95 | AbsListView.LayoutParams params = new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
96 | imageView.setLayoutParams(params);
97 | imageView.loadImage(list.get(i), R.color.font_black_6);
98 | imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
99 | ivList.add(imageView);
100 | }
101 | }
102 |
103 | // 添加指示图标
104 | private void addIndicatorImageViews() {
105 | llIndexContainer.removeAllViews();
106 | if (bannerCount < 2) return;
107 | for (int i = 0; i < bannerCount; i++) {
108 | ImageView iv = new ImageView(mActivity);
109 | LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(DensityUtil.dip2px(mActivity, 5), DensityUtil.dip2px(mActivity, 5));
110 | lp.leftMargin = DensityUtil.dip2px(mActivity, (i == 0) ? 0 : 7);
111 | iv.setLayoutParams(lp);
112 | iv.setBackgroundResource(R.drawable.xml_round_orange_grey_sel);
113 | iv.setEnabled(i == 0);
114 | llIndexContainer.addView(iv);
115 | }
116 | }
117 |
118 | // 为ViewPager设置监听器
119 | private void setViewPagerChangeListener() {
120 | vpBanner.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
121 | @Override
122 | public void onPageSelected(int position) {
123 | if (ivList == null || ivList.size() == 0) return;
124 | int newPosition = position % bannerCount;
125 | for (int i = 0; i < bannerCount; i++) {
126 | llIndexContainer.getChildAt(i).setEnabled(i == newPosition);
127 | }
128 | }
129 |
130 | @Override
131 | public void onPageScrolled(int position, float arg1, int arg2) {
132 | }
133 |
134 | @Override
135 | public void onPageScrollStateChanged(int arg0) {
136 | }
137 | });
138 | }
139 |
140 | // 添加Banner循环消息到队列
141 | public void enqueueBannerLoopMessage() {
142 | if (ivList == null || ivList.size() <= 1) return;
143 | mHandler.sendEmptyMessageDelayed(BANNER_TYPE, BANNER_TIME);
144 | }
145 |
146 | // 移除Banner循环的消息
147 | public void removeBannerLoopMessage() {
148 | if (mHandler.hasMessages(BANNER_TYPE)) {
149 | mHandler.removeMessages(BANNER_TYPE);
150 | }
151 | }
152 |
153 | // 反射设置ViewPager的轮播速度
154 | private void controlViewPagerSpeed(ViewPager viewPager, int speedTimeMillis) {
155 | try {
156 | Field field = ViewPager.class.getDeclaredField("mScroller");
157 | field.setAccessible(true);
158 | FixedSpeedScroller scroller = new FixedSpeedScroller(mActivity, new AccelerateDecelerateInterpolator());
159 | scroller.setDuration(speedTimeMillis);
160 | field.set(viewPager, scroller);
161 | } catch (Exception e) {
162 | }
163 | }
164 |
165 | }
166 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/view/HeaderChannelView.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.view;
2 |
3 | import android.app.Activity;
4 | import android.view.View;
5 | import android.widget.AdapterView;
6 | import android.widget.ListView;
7 |
8 | import com.sunfusheng.StickyHeaderListView.R;
9 | import com.sunfusheng.StickyHeaderListView.adapter.HeaderChannelAdapter;
10 | import com.sunfusheng.StickyHeaderListView.model.ChannelEntity;
11 | import com.sunfusheng.StickyHeaderListView.util.ToastUtil;
12 |
13 | import java.util.List;
14 |
15 | import butterknife.BindView;
16 | import butterknife.ButterKnife;
17 |
18 | /**
19 | * Created by sunfusheng on 16/4/20.
20 | */
21 | public class HeaderChannelView extends AbsHeaderView> {
22 |
23 | @BindView(R.id.gv_channel)
24 | FixedGridView gvChannel;
25 |
26 | public HeaderChannelView(Activity context) {
27 | super(context);
28 | }
29 |
30 | @Override
31 | protected void getView(List list, ListView listView) {
32 | View view = mInflate.inflate(R.layout.header_channel_layout, listView, false);
33 | ButterKnife.bind(this, view);
34 |
35 | dealWithTheView(list);
36 | listView.addHeaderView(view);
37 | }
38 |
39 | private void dealWithTheView(final List list) {
40 | if (list == null || list.size() < 2) return;
41 | int size = list.size();
42 | if (size <= 4) {
43 | gvChannel.setNumColumns(size);
44 | } else if (size == 6) {
45 | gvChannel.setNumColumns(3);
46 | } else if (size == 8) {
47 | gvChannel.setNumColumns(4);
48 | } else {
49 | return;
50 | }
51 |
52 | final HeaderChannelAdapter adapter = new HeaderChannelAdapter(mActivity, list);
53 | gvChannel.setAdapter(adapter);
54 |
55 | gvChannel.setOnItemClickListener(new AdapterView.OnItemClickListener() {
56 | @Override
57 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
58 | ToastUtil.show(mActivity, adapter.getItem(position).getTitle());
59 | }
60 | });
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/view/HeaderDividerView.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.view;
2 |
3 | import android.app.Activity;
4 | import android.view.View;
5 | import android.widget.ListView;
6 |
7 | import com.sunfusheng.StickyHeaderListView.R;
8 |
9 | /**
10 | * Created by sunfusheng on 16/4/20.
11 | */
12 | public class HeaderDividerView extends AbsHeaderView {
13 |
14 | public HeaderDividerView(Activity context) {
15 | super(context);
16 | }
17 |
18 | @Override
19 | protected void getView(String s, ListView listView) {
20 | View view = mInflate.inflate(R.layout.header_divider_layout, listView, false);
21 | listView.addHeaderView(view);
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sunfusheng/StickyHeaderListView/view/HeaderFilterView.java:
--------------------------------------------------------------------------------
1 | package com.sunfusheng.StickyHeaderListView.view;
2 |
3 | import android.app.Activity;
4 | import android.view.View;
5 | import android.widget.ListView;
6 |
7 | import com.sunfusheng.StickyHeaderListView.R;
8 |
9 | import butterknife.BindView;
10 | import butterknife.ButterKnife;
11 |
12 | /**
13 | * Created by sunfusheng on 16/4/20.
14 | */
15 | public class HeaderFilterView extends AbsHeaderView