├── .classpath
├── .gitignore
├── .project
├── .settings
└── org.eclipse.jdt.core.prefs
├── AndroidManifest.xml
├── README.md
├── libs
├── android-support-v4.jar
├── nineoldandroids-2.4.0.jar
└── universal-image-loader-1.9.4.jar
├── proguard-project.txt
├── project.properties
├── res
├── drawable-hdpi
│ └── ic_launcher.png
├── drawable-mdpi
│ └── ic_launcher.png
├── drawable-nodpi
│ ├── actionbar_downloading_manager.png
│ ├── actionbar_menu.png
│ ├── bg_score.9.png
│ ├── google.jpg
│ ├── heart.png
│ ├── heart_hover.png
│ ├── ic_arrow_back_white.png
│ ├── ic_pentagram_empty.png
│ ├── ic_pentagram_full.png
│ ├── ic_pentagram_half.png
│ └── share.png
├── drawable-xhdpi
│ └── ic_launcher.png
├── drawable-xxhdpi
│ └── ic_launcher.png
├── drawable
│ ├── background_tab.xml
│ ├── dots_normal.xml
│ ├── dots_selected.xml
│ ├── game_collection_selector.xml
│ ├── selector_actionbar_acttion_bg.xml
│ ├── shape_home_gradient.xml
│ └── tab_indicator_color.xml
├── layout
│ ├── activity_main.xml
│ ├── activity_start.xml
│ ├── detail_footer.xml
│ ├── fragment_tab.xml
│ ├── item.xml
│ └── stickylayout_topview.xml
├── menu
│ └── main.xml
├── values-sw600dp
│ └── dimens.xml
├── values-sw720dp-land
│ └── dimens.xml
├── values-v11
│ └── styles.xml
├── values-v14
│ └── styles.xml
└── values
│ ├── attrs.xml
│ ├── color.xml
│ ├── dimens.xml
│ ├── ids_sticky.xml
│ ├── psts__attrs.xml
│ ├── strings.xml
│ └── styles.xml
├── screenrecord.gif
└── src
└── com
└── touch18
└── finaldemo
├── MainActivity.java
├── StartActivity.java
├── TabFragment.java
├── util
├── ImageLoaderUtil.java
├── InitUtils.java
└── UiUtils.java
└── view
├── MyRatingBar.java
├── PagerSlidingTabStrip.java
└── StickyLayout.java
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 |
15 | # Gradle files
16 | .gradle/
17 | build/
18 |
19 | # Local configuration file (sdk path, etc)
20 | local.properties
21 |
22 | # Proguard folder generated by Eclipse
23 | proguard/
24 |
25 | # Log Files
26 | *.log
27 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | FinalDemo
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
3 | org.eclipse.jdt.core.compiler.compliance=1.6
4 | org.eclipse.jdt.core.compiler.source=1.6
5 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
19 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 仿当乐软件详情页
2 | > 基于 [Android 自定义控件 轻松实现360软件详情页](http://blog.csdn.net/lmj623565791/article/details/43649913)
3 |
4 | 
--------------------------------------------------------------------------------
/libs/android-support-v4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ngstyle/StickyLayout/3b01a693eb7093d045f7d65499e909719ecb4418/libs/android-support-v4.jar
--------------------------------------------------------------------------------
/libs/nineoldandroids-2.4.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ngstyle/StickyLayout/3b01a693eb7093d045f7d65499e909719ecb4418/libs/nineoldandroids-2.4.0.jar
--------------------------------------------------------------------------------
/libs/universal-image-loader-1.9.4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ngstyle/StickyLayout/3b01a693eb7093d045f7d65499e909719ecb4418/libs/universal-image-loader-1.9.4.jar
--------------------------------------------------------------------------------
/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-19
15 |
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ngstyle/StickyLayout/3b01a693eb7093d045f7d65499e909719ecb4418/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ngstyle/StickyLayout/3b01a693eb7093d045f7d65499e909719ecb4418/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-nodpi/actionbar_downloading_manager.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ngstyle/StickyLayout/3b01a693eb7093d045f7d65499e909719ecb4418/res/drawable-nodpi/actionbar_downloading_manager.png
--------------------------------------------------------------------------------
/res/drawable-nodpi/actionbar_menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ngstyle/StickyLayout/3b01a693eb7093d045f7d65499e909719ecb4418/res/drawable-nodpi/actionbar_menu.png
--------------------------------------------------------------------------------
/res/drawable-nodpi/bg_score.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ngstyle/StickyLayout/3b01a693eb7093d045f7d65499e909719ecb4418/res/drawable-nodpi/bg_score.9.png
--------------------------------------------------------------------------------
/res/drawable-nodpi/google.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ngstyle/StickyLayout/3b01a693eb7093d045f7d65499e909719ecb4418/res/drawable-nodpi/google.jpg
--------------------------------------------------------------------------------
/res/drawable-nodpi/heart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ngstyle/StickyLayout/3b01a693eb7093d045f7d65499e909719ecb4418/res/drawable-nodpi/heart.png
--------------------------------------------------------------------------------
/res/drawable-nodpi/heart_hover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ngstyle/StickyLayout/3b01a693eb7093d045f7d65499e909719ecb4418/res/drawable-nodpi/heart_hover.png
--------------------------------------------------------------------------------
/res/drawable-nodpi/ic_arrow_back_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ngstyle/StickyLayout/3b01a693eb7093d045f7d65499e909719ecb4418/res/drawable-nodpi/ic_arrow_back_white.png
--------------------------------------------------------------------------------
/res/drawable-nodpi/ic_pentagram_empty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ngstyle/StickyLayout/3b01a693eb7093d045f7d65499e909719ecb4418/res/drawable-nodpi/ic_pentagram_empty.png
--------------------------------------------------------------------------------
/res/drawable-nodpi/ic_pentagram_full.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ngstyle/StickyLayout/3b01a693eb7093d045f7d65499e909719ecb4418/res/drawable-nodpi/ic_pentagram_full.png
--------------------------------------------------------------------------------
/res/drawable-nodpi/ic_pentagram_half.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ngstyle/StickyLayout/3b01a693eb7093d045f7d65499e909719ecb4418/res/drawable-nodpi/ic_pentagram_half.png
--------------------------------------------------------------------------------
/res/drawable-nodpi/share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ngstyle/StickyLayout/3b01a693eb7093d045f7d65499e909719ecb4418/res/drawable-nodpi/share.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ngstyle/StickyLayout/3b01a693eb7093d045f7d65499e909719ecb4418/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ngstyle/StickyLayout/3b01a693eb7093d045f7d65499e909719ecb4418/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable/background_tab.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/res/drawable/dots_normal.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/res/drawable/dots_selected.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/res/drawable/game_collection_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/res/drawable/selector_actionbar_acttion_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/res/drawable/shape_home_gradient.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
9 |
10 |
--------------------------------------------------------------------------------
/res/drawable/tab_indicator_color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
12 |
13 |
14 |
15 |
30 |
31 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/res/layout/activity_start.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
18 |
19 |
28 |
29 |
--------------------------------------------------------------------------------
/res/layout/detail_footer.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
16 |
17 |
21 |
22 |
31 |
32 |
46 |
47 |
48 |
53 |
54 |
58 |
59 |
64 |
65 |
71 |
72 |
73 |
79 |
80 |
85 |
86 |
87 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/res/layout/fragment_tab.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
--------------------------------------------------------------------------------
/res/layout/item.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
--------------------------------------------------------------------------------
/res/layout/stickylayout_topview.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
19 |
20 |
24 |
25 |
26 |
32 |
33 |
39 |
40 |
47 |
48 |
53 |
54 |
65 |
66 |
76 |
77 |
83 |
84 |
85 |
95 |
96 |
97 |
104 |
105 |
106 |
112 |
113 |
118 |
119 |
127 |
128 |
133 |
134 |
135 |
144 |
145 |
150 |
151 |
152 |
161 |
162 |
167 |
168 |
169 |
170 |
--------------------------------------------------------------------------------
/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/res/values-sw600dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/res/values-sw720dp-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 | 128dp
8 |
9 |
10 |
--------------------------------------------------------------------------------
/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/res/values/color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #ff7800
4 | #737373
5 | #6633B5E5
6 |
7 |
--------------------------------------------------------------------------------
/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 16dp
5 | 16dp
6 |
7 |
8 |
--------------------------------------------------------------------------------
/res/values/ids_sticky.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/res/values/psts__attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | FinalDemo
5 | Settings
6 | Hello world!
7 |
8 |
9 |
--------------------------------------------------------------------------------
/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/screenrecord.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ngstyle/StickyLayout/3b01a693eb7093d045f7d65499e909719ecb4418/screenrecord.gif
--------------------------------------------------------------------------------
/src/com/touch18/finaldemo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.touch18.finaldemo;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import android.content.Context;
7 | import android.graphics.Color;
8 | import android.os.Bundle;
9 | import android.support.v4.app.Fragment;
10 | import android.support.v4.app.FragmentActivity;
11 | import android.support.v4.app.FragmentPagerAdapter;
12 | import android.support.v4.view.PagerAdapter;
13 | import android.support.v4.view.ViewPager;
14 | import android.support.v4.view.ViewPager.OnPageChangeListener;
15 | import android.text.Spannable;
16 | import android.text.SpannableString;
17 | import android.text.style.AbsoluteSizeSpan;
18 | import android.util.DisplayMetrics;
19 | import android.view.View;
20 | import android.view.View.OnClickListener;
21 | import android.view.ViewGroup;
22 | import android.view.ViewGroup.LayoutParams;
23 | import android.view.Window;
24 | import android.view.WindowManager;
25 | import android.view.animation.AccelerateDecelerateInterpolator;
26 | import android.widget.ImageView;
27 | import android.widget.ImageView.ScaleType;
28 | import android.widget.LinearLayout;
29 | import android.widget.RelativeLayout;
30 | import android.widget.TextView;
31 |
32 | import com.nineoldandroids.animation.Animator;
33 | import com.nineoldandroids.animation.AnimatorListenerAdapter;
34 | import com.nineoldandroids.animation.ObjectAnimator;
35 | import com.nineoldandroids.view.ViewHelper;
36 | import com.touch18.finaldemo.util.ImageLoaderUtil;
37 | import com.touch18.finaldemo.util.UiUtils;
38 | import com.touch18.finaldemo.view.PagerSlidingTabStrip;
39 | import com.touch18.finaldemo.view.StickyLayout;
40 | import com.touch18.finaldemo.view.StickyLayout.StickyState;
41 | import com.touch18.finaldemo.view.StickyLayout.TriggerZoomListener;
42 | import com.touch18.finaldemo.view.StickyLayout.onScrollChangedListener;
43 |
44 |
45 | public class MainActivity extends FragmentActivity {
46 | private String[] mTitles = new String[] { "简介", "评价", "相关" };
47 |
48 | private RelativeLayout mTopView,mTitleBar;
49 | private RelativeLayout mBottomDownload,mBottomComment;
50 | private TextView mScore;
51 | private View bgView;
52 | private StickyLayout stickyLayout;
53 | private LinearLayout llDots;
54 | private PagerSlidingTabStrip mIndicator;
55 | private ViewPager mTopViewPager,mViewPager;
56 | private FragmentPagerAdapter mAdapter;
57 | private PagerAdapter mTopAdapter;
58 | private TabFragment[] mFragments = new TabFragment[mTitles.length];
59 |
60 | private List imageViews;
61 | private boolean needAnimation;
62 |
63 | private int screenWidth,screenHeight;
64 | private int mBottomHeight;
65 |
66 | @Override
67 | protected void onCreate(Bundle savedInstanceState) {
68 | super.onCreate(savedInstanceState);
69 | requestWindowFeature(Window.FEATURE_NO_TITLE);
70 | setContentView(R.layout.activity_main);
71 |
72 | needAnimation = getIntent().getBooleanExtra("animation",false);
73 | WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
74 | DisplayMetrics dm = new DisplayMetrics();
75 | wm.getDefaultDisplay().getMetrics(dm);
76 | screenWidth = dm.widthPixels;
77 | screenHeight = dm.heightPixels;
78 |
79 | mBottomHeight = UiUtils.Dp2Px(40);
80 |
81 | initViews();
82 | initDatas();
83 | initEvents();
84 | }
85 |
86 | private int ANIM_DURATION = 240;
87 | private int ANIM_DELAY = 80;
88 | private void initEvents() {
89 | stickyLayout.setTriggerZoomListener(new TriggerZoomListener() {
90 |
91 | @Override
92 | public void zoom(boolean zoomUp) {
93 | if(needAnimation){
94 | ViewGroup.LayoutParams params = mTopViewPager.getLayoutParams();
95 | if(zoomUp){
96 | // 放大
97 | params.height = stickyLayout.getHeight();
98 | mTopViewPager.setLayoutParams(params);
99 | // TODO 这个值得计算
100 | float scaleUpX = (float)stickyLayout.getHeight() / screenWidth;
101 | float scaleUpY = (float)screenWidth / imageViews.get(mTopViewPager.getCurrentItem()).getHeight();
102 |
103 | float translationUpY = (float)(stickyLayout.getHeight() - imageViews.get(mTopViewPager.getCurrentItem()).getHeight()) / 2;
104 |
105 | for (int i = 0; i < imageViews.size(); i++) {
106 | if(i != mTopViewPager.getCurrentItem())
107 | imageViews.get(i).setVisibility(View.GONE);
108 |
109 | ImageView view = imageViews.get(i);
110 |
111 | ViewHelper.setPivotX(view, view.getWidth()/2);
112 | ViewHelper.setPivotY(view, view.getHeight()/2);
113 | ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotation",90.0f).setDuration(ANIM_DURATION);
114 | animator.setInterpolator(new AccelerateDecelerateInterpolator());
115 | animator.start();
116 |
117 | animator.addListener(new AnimatorListenerAdapter(){
118 | @Override
119 | public void onAnimationEnd(Animator animation){
120 | for (ImageView view : imageViews) {
121 | view.setVisibility(View.VISIBLE);
122 | }
123 | }
124 | });
125 |
126 | // System.out.println("bigw: " + view.getWidth() + " bigh: " + view.getHeight());
127 | ObjectAnimator o1 = ObjectAnimator.ofFloat(view, "scaleX", 1.0F, scaleUpX).setDuration(ANIM_DURATION - ANIM_DELAY);
128 | o1.setStartDelay(ANIM_DELAY);
129 | o1.start();
130 |
131 | ObjectAnimator o2 = ObjectAnimator.ofFloat(view, "scaleY", 1.0F, scaleUpY).setDuration(ANIM_DURATION - ANIM_DELAY);
132 | o2.setStartDelay(ANIM_DELAY);
133 | o2.start();
134 |
135 | ObjectAnimator.ofFloat(view, "translationY", translationUpY).setDuration(ANIM_DURATION).start();
136 |
137 | }
138 |
139 | }else{
140 | params.height = (int) Math.ceil((float)screenWidth * 1080 / 1920);
141 | mTopViewPager.setLayoutParams(params);
142 | for (int i = 0; i < imageViews.size(); i++) {
143 | if(i != mTopViewPager.getCurrentItem())
144 | imageViews.get(i).setVisibility(View.GONE);
145 |
146 | ImageView view = imageViews.get(i);
147 | ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotation", 0.0f).setDuration(ANIM_DURATION);
148 | animator.setInterpolator(new AccelerateDecelerateInterpolator());
149 | animator.start();
150 |
151 | animator.addListener(new AnimatorListenerAdapter(){
152 | @Override
153 | public void onAnimationEnd(Animator animation){
154 | for (ImageView view : imageViews) {
155 | view.setVisibility(View.VISIBLE);
156 | }
157 | }
158 | });
159 |
160 | // System.out.println("w: " + view.getWidth() + " h: " + view.getHeight());
161 | ObjectAnimator o1 = ObjectAnimator.ofFloat(view, "scaleX", 1.0f).setDuration(ANIM_DURATION - ANIM_DELAY);
162 | o1.setStartDelay(ANIM_DELAY);
163 | o1.start();
164 |
165 | ObjectAnimator o2 = ObjectAnimator.ofFloat(view, "scaleY", 1.0f).setDuration(ANIM_DURATION - ANIM_DELAY);
166 | o2.setStartDelay(ANIM_DELAY);
167 | o2.start();
168 |
169 | ObjectAnimator.ofFloat(view, "translationY", 0).setDuration(ANIM_DURATION).start();
170 | }
171 | }
172 | }
173 |
174 | mBottomDownload.setVisibility(zoomUp ? View.GONE : View.VISIBLE);
175 | mBottomComment.setVisibility(zoomUp ? View.GONE : View.VISIBLE);
176 |
177 | }
178 | });
179 |
180 | mTopViewPager.setOnPageChangeListener(new OnPageChangeListener() {
181 |
182 | @Override
183 | public void onPageSelected(int position) {
184 | for (int i = 0; i < llDots.getChildCount(); i++) {
185 | llDots.getChildAt(i).setBackgroundResource(R.drawable.dots_normal);
186 | }
187 |
188 | llDots.getChildAt(position).setBackgroundResource(R.drawable.dots_selected);
189 | }
190 |
191 | @Override
192 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
193 |
194 | }
195 |
196 | @Override
197 | public void onPageScrollStateChanged(int arg0) {
198 |
199 | }
200 | });
201 |
202 | stickyLayout.setOnScrollChangedListener(new onScrollChangedListener() {
203 |
204 | @Override
205 | public void onScroll(int l, int t, int oldl, int oldt) {
206 | // 头部viewPager 的错觉显示
207 | ViewHelper.setTranslationY(mTopView, t);
208 | ViewHelper.setTranslationY(mTitleBar, t);
209 |
210 | int all = stickyLayout.getHeight() - stickyLayout.getMiddleSticky() - mTitleBar.getHeight();
211 | int part = t - stickyLayout.getMiddleSticky();
212 |
213 | float alpha = (float) part/all;
214 |
215 | if(t >= stickyLayout.getMiddleSticky())
216 | mTitleBar.setBackgroundColor(Color.argb((int)(255 * alpha), 228, 115, 30));
217 |
218 | float offset = (float)t / (stickyLayout.getHeight() - mTitleBar.getHeight()) * 0.5f;
219 |
220 | // TODO 头部viewPager表面透明度 t越大越模糊
221 | bgView.setBackgroundColor(Color.argb((int)(255 * offset), 0, 0, 0));
222 |
223 | // TODO mScore透明度变换
224 | if(t < stickyLayout.getMiddleSticky())
225 | ViewHelper.setAlpha(mScore, (float)t / stickyLayout.getMiddleSticky());
226 | }
227 | });
228 |
229 | mIndicator.setOnPageChangeListener(new OnPageChangeListener() {
230 |
231 | @Override
232 | public void onPageSelected(int position) {
233 | if(position != 0 && position != 1){
234 | ViewHelper.setTranslationY(mBottomDownload,mBottomHeight);
235 | ViewHelper.setTranslationY(mBottomComment,mBottomHeight);
236 | }
237 | }
238 |
239 | @Override
240 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
241 | if(position == 0){
242 | ViewHelper.setTranslationY(mBottomDownload,mBottomHeight * positionOffset * 2);
243 | ViewHelper.setTranslationY(mBottomComment,mBottomHeight * (1 - positionOffset) * 2);
244 | }else if(position == 1){
245 | ViewHelper.setTranslationY(mBottomComment,mBottomHeight * positionOffset);
246 | // ViewHelper.setTranslationY(mBottomDownload,mBottomHeight * (1 - positionOffset));
247 | }
248 | }
249 |
250 | @Override
251 | public void onPageScrollStateChanged(int arg0) {
252 |
253 | }
254 | });
255 |
256 | findViewById(R.id.rl_back).setOnClickListener(new OnClickListener() {
257 |
258 | @Override
259 | public void onClick(View v) {
260 | finish();
261 | }
262 | });
263 |
264 | }
265 |
266 | private void initDatas(){
267 |
268 | for (int i = 0; i < mTitles.length; i++)
269 | mFragments[i] = (TabFragment) TabFragment.newInstance(mTitles[i]);
270 |
271 | mAdapter = new FragmentPagerAdapter(getSupportFragmentManager()){
272 | @Override
273 | public int getCount(){
274 | return mTitles.length;
275 | }
276 |
277 | @Override
278 | public Fragment getItem(int position){
279 | return mFragments[position];
280 | }
281 |
282 | @Override
283 | public CharSequence getPageTitle(int position) {
284 | return mTitles[position];
285 | }
286 |
287 | };
288 |
289 | mViewPager.setAdapter(mAdapter);
290 | mIndicator.setViewPager(mViewPager);
291 |
292 | String[] urls;
293 | if(!needAnimation){
294 | urls = new String[]{
295 | "http://f.hiphotos.baidu.com/image/pic/item/a08b87d6277f9e2fa2a1472e1c30e924b899f304.jpg",
296 | "http://f.hiphotos.baidu.com/image/pic/item/a08b87d6277f9e2fa2a1472e1c30e924b899f304.jpg",
297 | "http://f.hiphotos.baidu.com/image/pic/item/a08b87d6277f9e2fa2a1472e1c30e924b899f304.jpg",
298 | "http://f.hiphotos.baidu.com/image/pic/item/a08b87d6277f9e2fa2a1472e1c30e924b899f304.jpg",
299 | "http://f.hiphotos.baidu.com/image/pic/item/a08b87d6277f9e2fa2a1472e1c30e924b899f304.jpg"};
300 | }else{
301 | // 横向
302 | urls = new String[]{
303 | "http://photo.enterdesk.com/2011-6-2/enterdesk.com-422374E95B160CEAC0C7A01DAD7BBB74.jpg",
304 | "http://bizhi.zhuoku.com/2013/01/20/meinv/Meinv045.jpg",
305 | "http://www.33.la/uploads/20140525bztp/12303.jpg",
306 | "http://bizhi.zhuoku.com/2012/08/14/jingyingbudui/Jingyingbudui09.jpg",
307 | "http://www.33lc.com/article/UploadPic/2012-7/201272711182351761.jpg"};
308 |
309 | // http://bizhi.zhuoku.com/2012/08/14/jingyingbudui/Jingyingbudui09.jpg
310 | // "http://qn.18touch.com/magicbox_images/upload/res_snap/2015-05-28/55667be5f38a56.42451287.jpg", // 超好玩
311 | // "http://d.hiphotos.baidu.com/image/pic/item/5243fbf2b2119313e36edab767380cd791238d83.jpg"
312 | }
313 |
314 | // stickyLayout.setNeedAnimation(needAnimation);
315 | if(needAnimation){
316 | ViewGroup.LayoutParams params = mTopViewPager.getLayoutParams();
317 | params.height = (int) Math.ceil((float)screenWidth * 1080 / 1920);
318 | mTopViewPager.setLayoutParams(params);
319 | }
320 |
321 | imageViews = new ArrayList();
322 |
323 | for (int i = 0; i < urls.length; i++) {
324 | ImageView view = new ImageView(MainActivity.this);
325 | view.setScaleType(ScaleType.FIT_START);
326 | ImageLoaderUtil.setImage(view, urls[i]);
327 |
328 | view.setOnClickListener(new OnClickListener() {
329 |
330 | @Override
331 | public void onClick(View v) {
332 | stickyLayout.switchState(
333 | stickyLayout.getCurrentState() != StickyState.MIDDLE ?
334 | StickyState.MIDDLE :
335 | StickyState.BOTTOM);
336 | }
337 | });
338 |
339 | imageViews.add(view);
340 |
341 | View dot = new View(MainActivity.this);
342 | dot.setBackgroundResource(R.drawable.dots_normal);
343 | llDots.addView(dot,UiUtils.Dp2Px(8),UiUtils.Dp2Px(8));
344 |
345 | if(i == 0)
346 | dot.setBackgroundResource(R.drawable.dots_selected);
347 |
348 | android.widget.LinearLayout.LayoutParams params = (android.widget.LinearLayout.LayoutParams) dot.getLayoutParams();
349 | params.rightMargin = 8;
350 | }
351 |
352 | mTopAdapter = new PagerAdapter() {
353 |
354 | @Override
355 | public boolean isViewFromObject(View arg0, Object arg1) {
356 | return arg0 == arg1;
357 | }
358 |
359 | @Override
360 | public int getCount() {
361 | return imageViews.size();
362 | }
363 |
364 | @Override
365 | public Object instantiateItem(ViewGroup container, int position) {
366 | ImageView iv = imageViews.get(position);
367 | LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
368 | container.addView(iv,params);
369 | return iv;
370 | }
371 |
372 | @Override
373 | public void destroyItem(ViewGroup container, int position,Object object) {
374 | container.removeView(imageViews.get(position));
375 | }
376 |
377 | };
378 |
379 | mTopViewPager.setAdapter(mTopAdapter);
380 | mTopViewPager.setOffscreenPageLimit(imageViews.size());
381 |
382 | SpannableString spanText = new SpannableString("8.2");
383 | spanText.setSpan(new AbsoluteSizeSpan(UiUtils.Dp2Px(18)), 1, 3,Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
384 | mScore.setText(spanText);
385 | }
386 |
387 | private void initViews(){
388 | mTopView = (RelativeLayout) findViewById(R.id.rl_top);
389 | bgView = findViewById(R.id.view_bg);
390 | mTitleBar = (RelativeLayout) findViewById(R.id.title_bar);
391 | stickyLayout = (StickyLayout) findViewById(R.id.stickyLayout);
392 | llDots = (LinearLayout) findViewById(R.id.ll_dots);
393 | mIndicator = (PagerSlidingTabStrip) findViewById(R.id.id_stickylayout_indicator);
394 | mTopViewPager = (ViewPager) findViewById(R.id.id_stickylayout_top_viewpager);
395 | mViewPager = (ViewPager) findViewById(R.id.id_stickylayout_viewpager);
396 |
397 | mScore = (TextView) findViewById(R.id.tv_score);
398 | mBottomDownload = (RelativeLayout) findViewById(R.id.rl_download);
399 | mBottomComment = (RelativeLayout) findViewById(R.id.rl_send);
400 | }
401 |
402 |
403 | }
404 |
--------------------------------------------------------------------------------
/src/com/touch18/finaldemo/StartActivity.java:
--------------------------------------------------------------------------------
1 | package com.touch18.finaldemo;
2 |
3 | import com.touch18.finaldemo.util.InitUtils;
4 |
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.support.v4.app.FragmentActivity;
8 | import android.view.View;
9 | import android.view.Window;
10 |
11 | public class StartActivity extends FragmentActivity {
12 |
13 | @Override
14 | protected void onCreate(Bundle savedInstanceState) {
15 | super.onCreate(savedInstanceState);
16 | requestWindowFeature(Window.FEATURE_NO_TITLE);
17 | setContentView(R.layout.activity_start);
18 |
19 | InitUtils.initImageLoader(this);
20 | }
21 |
22 |
23 | public void jump(View view){
24 | int id = view.getId();
25 | Intent intent = new Intent(this,MainActivity.class);
26 | switch (id) {
27 | case R.id.btn_animation:
28 | intent.putExtra("animation", true);
29 | break;
30 | case R.id.btn_no_animation:
31 | intent.putExtra("animation", false);
32 | break;
33 | }
34 | startActivity(intent);
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/com/touch18/finaldemo/TabFragment.java:
--------------------------------------------------------------------------------
1 | package com.touch18.finaldemo;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import android.os.Bundle;
7 | import android.support.v4.app.Fragment;
8 | import android.util.Log;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.ArrayAdapter;
13 | import android.widget.ListView;
14 | import android.widget.TextView;
15 |
16 | public class TabFragment extends Fragment{
17 | public static final String TITLE = "title";
18 | private String mTitle = "Defaut Value";
19 | private ListView mListView;
20 | // private TextView mTextView;
21 | private List mDatas = new ArrayList();
22 |
23 | @Override
24 | public void onCreate(Bundle savedInstanceState){
25 | super.onCreate(savedInstanceState);
26 | if (getArguments() != null)
27 | mTitle = getArguments().getString(TITLE);
28 | }
29 |
30 | @Override
31 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
32 | Bundle savedInstanceState)
33 | {
34 | View view = inflater.inflate(R.layout.fragment_tab, container, false);
35 | mListView = (ListView) view.findViewById(R.id.id_stickylayout_innerscrollview);
36 | // mTextView = (TextView) view.findViewById(R.id.id_info);
37 | // mTextView.setText(mTitle);
38 | mDatas.clear();
39 | for (int i = 0; i < 50; i++){
40 | mDatas.add(mTitle+" -> " + i);
41 | }
42 |
43 | mListView.setAdapter(new ArrayAdapter(getActivity(),R.layout.item, R.id.id_info, mDatas){
44 | @Override
45 | public View getView(int position, View convertView, ViewGroup parent){
46 | // Log.e("tag", "convertView = " + convertView);
47 | return super.getView(position, convertView, parent);
48 | }
49 |
50 | @Override
51 | public int getCount() {
52 | return mDatas.size();
53 | }
54 | });
55 | return view;
56 |
57 | }
58 |
59 | public static TabFragment newInstance(String title)
60 | {
61 | TabFragment tabFragment = new TabFragment();
62 | Bundle bundle = new Bundle();
63 | bundle.putString(TITLE, title);
64 | tabFragment.setArguments(bundle);
65 | return tabFragment;
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/src/com/touch18/finaldemo/util/ImageLoaderUtil.java:
--------------------------------------------------------------------------------
1 | package com.touch18.finaldemo.util;
2 |
3 | import android.graphics.Bitmap;
4 | import android.widget.ImageView;
5 |
6 | import com.nostra13.universalimageloader.core.DisplayImageOptions;
7 | import com.nostra13.universalimageloader.core.ImageLoader;
8 | import com.nostra13.universalimageloader.core.assist.ImageScaleType;
9 | import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
10 |
11 | public class ImageLoaderUtil {
12 | public static SimpleImageLoadingListener listener = new SimpleImageLoadingListener();
13 | private static DisplayImageOptions.Builder builder = new DisplayImageOptions.Builder()
14 | .cacheOnDisc()
15 | .bitmapConfig(Bitmap.Config.RGB_565)
16 | .imageScaleType(ImageScaleType.EXACTLY);
17 |
18 | private static DisplayImageOptions.Builder builderForImageRes = new DisplayImageOptions.Builder()
19 | .cacheOnDisc()
20 | .bitmapConfig(Bitmap.Config.RGB_565)
21 | .imageScaleType(ImageScaleType.EXACTLY);
22 |
23 | public static void displayImage(ImageView iv, String uri)
24 | {
25 | // builderForImageRes.showStubImage(R.drawable.pic_food_default);
26 | // builderForImageRes.showImageForEmptyUri(R.drawable.pic_food_default);
27 | ImageLoader.getInstance().displayImage(uri, iv, builderForImageRes.build());
28 | }
29 |
30 | public static void setImage(ImageView iv, String uri) {
31 | ImageLoader.getInstance().displayImage(uri, iv, builder.build(),listener);
32 | }
33 |
34 | /* public static void setImage(ImageView iv, String uri) {
35 | ImageLoader.getInstance().displayImage(uri, iv, listener);
36 | }*/
37 |
38 |
39 | /**
40 | * 图片下载未完成时,显示指定默认图
41 | * @param iv
42 | * @param uri
43 | * @param res
44 | */
45 | public static void setImage(ImageView iv, String uri, int res) {
46 | /* builderForImageRes.showStubImage(res);
47 | builderForImageRes.showImageForEmptyUri(res);
48 | ImageLoader.getInstance().displayImage(uri, iv, builderForImageRes.build(),listener);
49 | */
50 | iv.setImageResource(res);
51 | ImageLoader.getInstance().displayImage(uri, iv,listener);
52 | }
53 | /**
54 | * 显示本地图片
55 | * @param iv
56 | * @param uri
57 | */
58 | public static void setFileImage(ImageView iv, String uri){
59 | uri = "file://" + uri;
60 | setImage(iv, uri);
61 | }
62 | /**
63 | * 显示本地图片
64 | * @param iv
65 | * @param uri
66 | * @param res
67 | */
68 | public static void setFileImage(ImageView iv, String uri, int res){
69 | uri = "file://" + uri;
70 | setImage(iv, uri, res);
71 | }
72 |
73 | /**
74 | * 算出需要缩放的比例
75 | */
76 | public static float calculateScale(int widthOrg,int heightOrg,int widthDes,int heightDes){
77 | float widthScale = (float)widthDes/widthOrg;
78 | float heightScale = (float)heightDes/heightOrg;
79 | return widthScale > heightScale ? widthScale:heightScale;
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/src/com/touch18/finaldemo/util/InitUtils.java:
--------------------------------------------------------------------------------
1 | package com.touch18.finaldemo.util;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 |
6 | import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;
7 | import com.nostra13.universalimageloader.cache.memory.impl.LRULimitedMemoryCache;
8 | import com.nostra13.universalimageloader.core.DisplayImageOptions;
9 | import com.nostra13.universalimageloader.core.ImageLoader;
10 | import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
11 | import com.nostra13.universalimageloader.core.assist.ImageScaleType;
12 | import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
13 |
14 | public class InitUtils {
15 | public static void initImageLoader(Context context) {
16 | ImageLoader imageLoader = ImageLoader.getInstance();
17 | // @formatter:off
18 | DisplayImageOptions defaultDisplayImageOptions = new DisplayImageOptions.Builder()
19 | .cacheInMemory(true).cacheOnDisc(true)
20 | .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2)
21 | .bitmapConfig(Bitmap.Config.ARGB_8888).build();
22 | int memoryCacheSize = (int) (Math.min(
23 | Runtime.getRuntime().maxMemory() / 8, 8 * 1024 * 1024));
24 | // MemoryCacheAware memoryCache = new LRULimitedMemoryCache(
25 | // memoryCacheSize);
26 | ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
27 | // .memoryCache(memoryCache)
28 | .defaultDisplayImageOptions(defaultDisplayImageOptions)
29 | .denyCacheImageMultipleSizesInMemory()
30 | .discCacheFileNameGenerator(new Md5FileNameGenerator())
31 | // .discCache(new UnlimitedDiscCache(new File("")))
32 | .tasksProcessingOrder(QueueProcessingType.FIFO).build();
33 | // @formatter:on
34 | imageLoader.init(config);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/com/touch18/finaldemo/util/UiUtils.java:
--------------------------------------------------------------------------------
1 | package com.touch18.finaldemo.util;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.res.Resources;
5 | import android.os.Build;
6 |
7 | /**
8 | * 帮助类
9 | *
10 | * @ClassName: UiUtils
11 | * @Description: TODO
12 | * @author wenxucheng
13 | * @date 2014-7-18
14 | *
15 | */
16 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
17 | public class UiUtils {
18 | /**
19 | * 将dp转换为px
20 | *
21 | * @param context
22 | * @param dp
23 | * @return
24 | */
25 | public static int Dp2Px(int dp) {
26 | return (int)(dp * Resources.getSystem().getDisplayMetrics().density);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/com/touch18/finaldemo/view/MyRatingBar.java:
--------------------------------------------------------------------------------
1 | package com.touch18.finaldemo.view;
2 |
3 | import com.touch18.finaldemo.R;
4 |
5 | import android.content.Context;
6 | import android.content.res.TypedArray;
7 | import android.util.AttributeSet;
8 | import android.view.MotionEvent;
9 | import android.view.View;
10 | import android.widget.ImageView;
11 | import android.widget.LinearLayout;
12 |
13 |
14 | public class MyRatingBar extends LinearLayout {
15 | private TypedArray typedArray;
16 | private int ratingNum;
17 | private int ratingDrawableFull;
18 | private int ratingDrawableHalf;
19 | private int ratingDrawableEmpty;
20 | private boolean isIndicator;
21 | private float rating;
22 | private float previousRating;
23 |
24 | private Context context;
25 | private int width, height;
26 | private int layout_width;
27 | private int scroolX = 0;//触摸横向位移
28 |
29 | private OnTouchListener touchListener;
30 | private OnRatingBarChangeListener mOnRatingBarChangeListener;
31 | public void setOnRatingBarChangeListener(OnRatingBarChangeListener mOnRatingBarChangeListener) {
32 | this.mOnRatingBarChangeListener = mOnRatingBarChangeListener;
33 | }
34 |
35 | public interface OnRatingBarChangeListener {
36 | void onRatingChanged(float rating);
37 | }
38 |
39 | public MyRatingBar(Context context){
40 | this(context,null);
41 | }
42 |
43 | public MyRatingBar(Context context, AttributeSet attrs) {
44 | super(context,attrs);
45 | this.context = context;
46 | typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyRatingBar);
47 | initRatingView();
48 | typedArray.recycle();
49 | }
50 |
51 |
52 | /**初始化评分控件*/
53 | private void initRatingView(){
54 | ratingNum = typedArray.getInt(R.styleable.MyRatingBar_ratingNum, 5);
55 | ratingDrawableFull = typedArray.getResourceId(
56 | R.styleable.MyRatingBar_ratingDrawableFull, R.drawable.ic_pentagram_full);
57 | ratingDrawableHalf = typedArray.getResourceId(
58 | R.styleable.MyRatingBar_ratingDrawableHalf, R.drawable.ic_pentagram_half);
59 | ratingDrawableEmpty = typedArray.getResourceId(
60 | R.styleable.MyRatingBar_ratingDrawableEmpty, R.drawable.ic_pentagram_empty);
61 | rating = typedArray.getFloat(R.styleable.MyRatingBar_rating, 0);
62 | isIndicator = typedArray.getBoolean(R.styleable.MyRatingBar_isIndicator, true);
63 | width = typedArray.getDimensionPixelSize(R.styleable.MyRatingBar_pentagramWidth, width);
64 | height = typedArray.getDimensionPixelSize(R.styleable.MyRatingBar_pentagramHeight, height);
65 | layout_width = ratingNum * width;
66 |
67 | rating = rating > ratingNum ? ratingNum : rating;
68 | for (int i = 0; i < ratingNum; i++)
69 | addView(createRatingView(ratingDrawableEmpty));
70 |
71 | drowRatingBar();
72 | super.setOnTouchListener(myTouchListener);
73 | }
74 |
75 |
76 | /**绘制RatingBar*/
77 | private void drowRatingBar() {
78 | // rating 0.5 - 5.0
79 | int decimal = (int) (rating * 10 % 10);
80 | int intPart = (int) (rating * 10 / 10);;
81 | for (int i = 0; i < intPart; i++) {
82 | getChildAt(i).setBackgroundResource(ratingDrawableFull);
83 | }
84 |
85 | if(intPart < ratingNum){
86 | getChildAt(intPart).setBackgroundResource(decimal == 0 ?ratingDrawableEmpty:ratingDrawableHalf);
87 |
88 | for (int j = intPart + 1; j < ratingNum; j++) {
89 | getChildAt(j).setBackgroundResource(ratingDrawableEmpty);
90 | }
91 | }
92 | }
93 |
94 | /**
95 | * 创建评分控件view
96 | * @param position
97 | * @param ratingId
98 | * @return
99 | */
100 | private ImageView createRatingView(int ratingId){
101 | ImageView iv = new ImageView(context);
102 | iv.setBackgroundResource(ratingId);
103 | LayoutParams params = new LayoutParams(width, height);//设置成等比
104 | iv.setLayoutParams(params);
105 | return iv;
106 | }
107 |
108 | private OnTouchListener myTouchListener = new OnTouchListener() {
109 | @Override
110 | public boolean onTouch(View v, MotionEvent event) {
111 | if(isIndicator)
112 | return false;
113 | int action = event.getAction();
114 | if (action == MotionEvent.ACTION_MOVE) {
115 | scroolX = (int) event.getX() > layout_width ? layout_width : (int) event.getX();
116 | scroolX = (int) event.getX() < 0 ? 0 : scroolX;
117 | rating = scroolX/(float)width;
118 |
119 | int decimal = (int) (rating * 10 % 10);
120 | double floor = Math.floor(rating);
121 | if(floor < ratingNum)
122 | rating = (float) (decimal > 5 ? floor + 1 :floor + 0.5);
123 |
124 | if(previousRating != rating){
125 | drowRatingBar();
126 | previousRating = rating;
127 | }
128 | }
129 |
130 | if(mOnRatingBarChangeListener != null){
131 | mOnRatingBarChangeListener.onRatingChanged(rating);
132 | }
133 |
134 | if (touchListener != null) {
135 | return touchListener.onTouch(v, event);
136 | }
137 |
138 |
139 | return true;
140 | }
141 | };
142 |
143 | @Override
144 | public void setOnTouchListener(OnTouchListener touchListener) {
145 | this.touchListener = touchListener;
146 | };
147 |
148 | /**
149 | * 设置等级
150 | * @param progress
151 | */
152 | public void setProgress(float progress){
153 | rating = progress > ratingNum ? ratingNum : progress;
154 | if(rating <= 0)
155 | rating = 0.5f;
156 | drowRatingBar();
157 | }
158 |
159 | public float getProgress() {
160 | return rating;
161 | }
162 |
163 | }
164 |
--------------------------------------------------------------------------------
/src/com/touch18/finaldemo/view/PagerSlidingTabStrip.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Andreas Stuetz
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.touch18.finaldemo.view;
18 |
19 | import java.util.Locale;
20 |
21 | import com.touch18.finaldemo.R;
22 |
23 | import android.annotation.SuppressLint;
24 | import android.content.Context;
25 | import android.content.res.ColorStateList;
26 | import android.content.res.TypedArray;
27 | import android.graphics.Canvas;
28 | import android.graphics.Paint;
29 | import android.graphics.Paint.Style;
30 | import android.graphics.Typeface;
31 | import android.os.Build;
32 | import android.os.Parcel;
33 | import android.os.Parcelable;
34 | import android.support.v4.view.ViewPager;
35 | import android.support.v4.view.ViewPager.OnPageChangeListener;
36 | import android.util.AttributeSet;
37 | import android.util.DisplayMetrics;
38 | import android.util.TypedValue;
39 | import android.view.Gravity;
40 | import android.view.View;
41 | import android.view.ViewTreeObserver.OnGlobalLayoutListener;
42 | import android.widget.HorizontalScrollView;
43 | import android.widget.ImageButton;
44 | import android.widget.LinearLayout;
45 | import android.widget.TextView;
46 |
47 | public class PagerSlidingTabStrip extends HorizontalScrollView {
48 |
49 | public interface IconTabProvider {
50 | public int getPageIconResId(int position);
51 | }
52 |
53 | public interface OnTabClickListener{
54 | public void onClick(int position);
55 | }
56 |
57 | // @formatter:off
58 | private static final int[] ATTRS = new int[] {
59 | android.R.attr.textSize,
60 | android.R.attr.textColor
61 | };
62 | // @formatter:on
63 |
64 | private LinearLayout.LayoutParams defaultTabLayoutParams;
65 | private LinearLayout.LayoutParams expandedTabLayoutParams;
66 |
67 | private final PageListener pageListener = new PageListener();
68 | public OnPageChangeListener delegatePageListener;
69 | public OnTabClickListener tabClickListener;
70 |
71 |
72 | private LinearLayout tabsContainer;
73 | private ViewPager pager;
74 |
75 | private int tabCount;
76 |
77 | private int currentPosition = 0;
78 | private float currentPositionOffset = 0f;
79 |
80 | private Paint rectPaint;
81 | private Paint dividerPaint;
82 |
83 | private int indicatorColor = 0xFF666666;
84 | private int underlineColor = 0x1A000000;
85 | private int dividerColor = 0x1A000000;
86 |
87 | private boolean shouldExpand = false;
88 | private boolean textAllCaps = true;
89 |
90 | private int scrollOffset = 52;
91 | private int indicatorHeight = 8;
92 | private int underlineHeight = 2;
93 | private int dividerPadding = 12;
94 | private int tabPadding = 24;
95 | private int dividerWidth = 1;
96 |
97 | private int tabTextSize = 12;
98 | private ColorStateList tabTextColor = null;
99 | private Typeface tabTypeface = null;
100 | private int tabTypefaceStyle = Typeface.NORMAL;
101 |
102 | private int lastScrollX = 0;
103 |
104 | private int tabBackgroundResId = R.drawable.background_tab;
105 |
106 | private Locale locale;
107 |
108 | public PagerSlidingTabStrip(Context context) {
109 | this(context, null);
110 | }
111 |
112 | public PagerSlidingTabStrip(Context context, AttributeSet attrs) {
113 | this(context, attrs, 0);
114 | }
115 |
116 | public PagerSlidingTabStrip(Context context, AttributeSet attrs, int defStyle) {
117 | super(context, attrs, defStyle);
118 |
119 | setFillViewport(true);
120 | setWillNotDraw(false);
121 |
122 | tabsContainer = new LinearLayout(context);
123 | tabsContainer.setOrientation(LinearLayout.HORIZONTAL);
124 | tabsContainer.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
125 | addView(tabsContainer);
126 |
127 | DisplayMetrics dm = getResources().getDisplayMetrics();
128 |
129 | scrollOffset = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, scrollOffset, dm);
130 | indicatorHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, indicatorHeight, dm);
131 | underlineHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, underlineHeight, dm);
132 | dividerPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dividerPadding, dm);
133 | tabPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, tabPadding, dm);
134 | dividerWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dividerWidth, dm);
135 | tabTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, tabTextSize, dm);
136 |
137 | // get system attrs (android:textSize and android:textColor)
138 |
139 | TypedArray a = context.obtainStyledAttributes(attrs, ATTRS);
140 |
141 | tabTextSize = a.getDimensionPixelSize(0, tabTextSize);
142 | tabTextColor = a.getColorStateList(1);
143 |
144 | a.recycle();
145 |
146 | // get custom attrs
147 |
148 | a = context.obtainStyledAttributes(attrs, R.styleable.PagerSlidingTabStrip);
149 |
150 | indicatorColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsIndicatorColor, indicatorColor);
151 | underlineColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsUnderlineColor, underlineColor);
152 | dividerColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsDividerColor, dividerColor);
153 | indicatorHeight = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsIndicatorHeight, indicatorHeight);
154 | underlineHeight = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsUnderlineHeight, underlineHeight);
155 | dividerPadding = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsDividerPadding, dividerPadding);
156 | tabPadding = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsTabPaddingLeftRight, tabPadding);
157 | tabBackgroundResId = a.getResourceId(R.styleable.PagerSlidingTabStrip_pstsTabBackground, tabBackgroundResId);
158 | shouldExpand = a.getBoolean(R.styleable.PagerSlidingTabStrip_pstsShouldExpand, shouldExpand);
159 | scrollOffset = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsScrollOffset, scrollOffset);
160 | textAllCaps = a.getBoolean(R.styleable.PagerSlidingTabStrip_pstsTextAllCaps, textAllCaps);
161 |
162 | a.recycle();
163 |
164 | rectPaint = new Paint();
165 | rectPaint.setAntiAlias(true);
166 | rectPaint.setStyle(Style.FILL);
167 |
168 | dividerPaint = new Paint();
169 | dividerPaint.setAntiAlias(true);
170 | dividerPaint.setStrokeWidth(dividerWidth);
171 |
172 | defaultTabLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
173 | expandedTabLayoutParams = new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f);
174 |
175 | if (locale == null) {
176 | locale = getResources().getConfiguration().locale;
177 | }
178 | }
179 |
180 | public void setViewPager(ViewPager pager) {
181 | this.pager = pager;
182 |
183 | if (pager.getAdapter() == null) {
184 | throw new IllegalStateException("ViewPager does not have adapter instance.");
185 | }
186 |
187 | pager.setOnPageChangeListener(pageListener);
188 |
189 | notifyDataSetChanged();
190 | }
191 |
192 | public void setOnPageChangeListener(OnPageChangeListener listener) {
193 | this.delegatePageListener = listener;
194 | }
195 |
196 | public void setOnTabClickListener(OnTabClickListener listener) {
197 | this.tabClickListener = listener;
198 | }
199 |
200 | public void notifyDataSetChanged() {
201 |
202 | tabsContainer.removeAllViews();
203 |
204 | tabCount = pager.getAdapter().getCount();
205 |
206 | for (int i = 0; i < tabCount; i++) {
207 |
208 | if (pager.getAdapter() instanceof IconTabProvider) {
209 | addIconTab(i, ((IconTabProvider) pager.getAdapter()).getPageIconResId(i));
210 | } else {
211 | addTextTab(i, pager.getAdapter().getPageTitle(i).toString());
212 | }
213 |
214 | }
215 |
216 | updateTabStyles();
217 |
218 | getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
219 |
220 | @SuppressWarnings("deprecation")
221 | @SuppressLint("NewApi")
222 | @Override
223 | public void onGlobalLayout() {
224 |
225 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
226 | getViewTreeObserver().removeGlobalOnLayoutListener(this);
227 | } else {
228 | getViewTreeObserver().removeOnGlobalLayoutListener(this);
229 | }
230 |
231 | currentPosition = pager.getCurrentItem();
232 | scrollToChild(currentPosition, 0);
233 | updateSelection(currentPosition);
234 | }
235 | });
236 |
237 | }
238 |
239 | private void addTextTab(final int position, String title) {
240 |
241 | TextView tab = new TextView(getContext());
242 | tab.setText(title);
243 | tab.setGravity(Gravity.CENTER);
244 | tab.setSingleLine();
245 |
246 | addTab(position, tab);
247 | }
248 |
249 | private void addIconTab(final int position, int resId) {
250 |
251 | ImageButton tab = new ImageButton(getContext());
252 | tab.setImageResource(resId);
253 |
254 | addTab(position, tab);
255 |
256 | }
257 |
258 | private void addTab(final int position, View tab) {
259 | tab.setFocusable(true);
260 | tab.setOnClickListener(new OnClickListener() {
261 | @Override
262 | public void onClick(View v) {
263 | if(tabClickListener != null && pager.getCurrentItem() == position)
264 | tabClickListener.onClick(position);
265 | pager.setCurrentItem(position);
266 | }
267 | });
268 |
269 | tab.setPadding(tabPadding, 0, tabPadding, 0);
270 | tabsContainer.addView(tab, position, shouldExpand ? expandedTabLayoutParams : defaultTabLayoutParams);
271 | }
272 |
273 | private void updateTabStyles() {
274 |
275 | for (int i = 0; i < tabCount; i++) {
276 |
277 | View v = tabsContainer.getChildAt(i);
278 |
279 | v.setBackgroundResource(tabBackgroundResId);
280 |
281 | if (v instanceof TextView) {
282 |
283 | TextView tab = (TextView) v;
284 | tab.setTextSize(TypedValue.COMPLEX_UNIT_PX, tabTextSize);
285 | tab.setTypeface(tabTypeface, tabTypefaceStyle);
286 | if (tabTextColor != null) {
287 | tab.setTextColor(tabTextColor);
288 | }
289 |
290 | // setAllCaps() is only available from API 14, so the upper case is made manually if we are on a
291 | // pre-ICS-build
292 | if (textAllCaps) {
293 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
294 | tab.setAllCaps(true);
295 | } else {
296 | tab.setText(tab.getText().toString().toUpperCase(locale));
297 | }
298 | }
299 | }
300 | }
301 |
302 | }
303 |
304 | private void scrollToChild(int position, int offset) {
305 |
306 | if (tabCount == 0) {
307 | return;
308 | }
309 |
310 | int newScrollX = tabsContainer.getChildAt(position).getLeft() + offset;
311 |
312 | if (position > 0 || offset > 0) {
313 | newScrollX -= scrollOffset;
314 | }
315 |
316 | if (newScrollX != lastScrollX) {
317 | lastScrollX = newScrollX;
318 | scrollTo(newScrollX, 0);
319 | }
320 |
321 | }
322 |
323 | @Override
324 | protected void onDraw(Canvas canvas) {
325 | super.onDraw(canvas);
326 |
327 | if (isInEditMode() || tabCount == 0) {
328 | return;
329 | }
330 |
331 | final int height = getHeight();
332 |
333 | // draw indicator line
334 |
335 | rectPaint.setColor(indicatorColor);
336 |
337 | // default: line below current tab
338 | View currentTab = tabsContainer.getChildAt(currentPosition);
339 | float lineLeft = currentTab.getLeft();
340 | float lineRight = currentTab.getRight();
341 |
342 | // if there is an offset, start interpolating left and right coordinates between current and next tab
343 | if (currentPositionOffset > 0f && currentPosition < tabCount - 1) {
344 |
345 | View nextTab = tabsContainer.getChildAt(currentPosition + 1);
346 | final float nextTabLeft = nextTab.getLeft();
347 | final float nextTabRight = nextTab.getRight();
348 |
349 | lineLeft = (currentPositionOffset * nextTabLeft + (1f - currentPositionOffset) * lineLeft);
350 | lineRight = (currentPositionOffset * nextTabRight + (1f - currentPositionOffset) * lineRight);
351 | }
352 |
353 | canvas.drawRect(lineLeft, height - indicatorHeight, lineRight, height, rectPaint);
354 |
355 | // draw underline
356 |
357 | rectPaint.setColor(underlineColor);
358 | canvas.drawRect(0, height - underlineHeight, tabsContainer.getWidth(), height, rectPaint);
359 |
360 | // draw divider
361 |
362 | dividerPaint.setColor(dividerColor);
363 | for (int i = 0; i < tabCount - 1; i++) {
364 | View tab = tabsContainer.getChildAt(i);
365 | canvas.drawLine(tab.getRight(), dividerPadding, tab.getRight(), height - dividerPadding, dividerPaint);
366 | }
367 | }
368 |
369 | private class PageListener implements OnPageChangeListener {
370 |
371 | @Override
372 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
373 |
374 | // updateSelection(positionOffset > 0.5f ? position + 1:position);
375 |
376 | currentPosition = position;
377 | currentPositionOffset = positionOffset;
378 |
379 | scrollToChild(position, (int) (positionOffset * tabsContainer.getChildAt(position).getWidth()));
380 |
381 | invalidate();
382 |
383 | if (delegatePageListener != null) {
384 | delegatePageListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
385 | }
386 | }
387 |
388 | @Override
389 | public void onPageScrollStateChanged(int state) {
390 | if (state == ViewPager.SCROLL_STATE_IDLE) {
391 | scrollToChild(pager.getCurrentItem(), 0);
392 | }
393 |
394 | if (delegatePageListener != null) {
395 | delegatePageListener.onPageScrollStateChanged(state);
396 | }
397 | }
398 |
399 | @Override
400 | public void onPageSelected(int position) {
401 | updateSelection(position);
402 |
403 | if (delegatePageListener != null) {
404 | delegatePageListener.onPageSelected(position);
405 | }
406 | }
407 |
408 | }
409 |
410 | private int currentSeletedPosition = -1;
411 | public void updateSelection(int position) {
412 | if(currentSeletedPosition == position)
413 | return;
414 |
415 | currentSeletedPosition = position;
416 | for (int i = 0; i < tabCount; ++i) {
417 | View tv = tabsContainer.getChildAt(i);
418 | tv.setSelected(i == position);
419 | }
420 | }
421 |
422 | public void setIndicatorColor(int indicatorColor) {
423 | this.indicatorColor = indicatorColor;
424 | invalidate();
425 | }
426 |
427 | public void setIndicatorColorResource(int resId) {
428 | this.indicatorColor = getResources().getColor(resId);
429 | invalidate();
430 | }
431 |
432 | public int getIndicatorColor() {
433 | return this.indicatorColor;
434 | }
435 |
436 | public void setIndicatorHeight(int indicatorLineHeightPx) {
437 | this.indicatorHeight = indicatorLineHeightPx;
438 | invalidate();
439 | }
440 |
441 | public int getIndicatorHeight() {
442 | return indicatorHeight;
443 | }
444 |
445 | public void setUnderlineColor(int underlineColor) {
446 | this.underlineColor = underlineColor;
447 | invalidate();
448 | }
449 |
450 | public void setUnderlineColorResource(int resId) {
451 | this.underlineColor = getResources().getColor(resId);
452 | invalidate();
453 | }
454 |
455 | public int getUnderlineColor() {
456 | return underlineColor;
457 | }
458 |
459 | public void setDividerColor(int dividerColor) {
460 | this.dividerColor = dividerColor;
461 | invalidate();
462 | }
463 |
464 | public void setDividerColorResource(int resId) {
465 | this.dividerColor = getResources().getColor(resId);
466 | invalidate();
467 | }
468 |
469 | public int getDividerColor() {
470 | return dividerColor;
471 | }
472 |
473 | public void setUnderlineHeight(int underlineHeightPx) {
474 | this.underlineHeight = underlineHeightPx;
475 | invalidate();
476 | }
477 |
478 | public int getUnderlineHeight() {
479 | return underlineHeight;
480 | }
481 |
482 | public void setDividerPadding(int dividerPaddingPx) {
483 | this.dividerPadding = dividerPaddingPx;
484 | invalidate();
485 | }
486 |
487 | public int getDividerPadding() {
488 | return dividerPadding;
489 | }
490 |
491 | public void setScrollOffset(int scrollOffsetPx) {
492 | this.scrollOffset = scrollOffsetPx;
493 | invalidate();
494 | }
495 |
496 | public int getScrollOffset() {
497 | return scrollOffset;
498 | }
499 |
500 | public void setShouldExpand(boolean shouldExpand) {
501 | this.shouldExpand = shouldExpand;
502 | requestLayout();
503 | }
504 |
505 | public boolean getShouldExpand() {
506 | return shouldExpand;
507 | }
508 |
509 | public boolean isTextAllCaps() {
510 | return textAllCaps;
511 | }
512 |
513 | public void setAllCaps(boolean textAllCaps) {
514 | this.textAllCaps = textAllCaps;
515 | }
516 |
517 | public void setTextSize(int textSizePx) {
518 | this.tabTextSize = textSizePx;
519 | updateTabStyles();
520 | }
521 |
522 | public int getTextSize() {
523 | return tabTextSize;
524 | }
525 |
526 | public void setTextColor(ColorStateList textColor) {
527 | this.tabTextColor = textColor;
528 | updateTabStyles();
529 | }
530 |
531 | public void setTextColorResource(int resId) {
532 | this.tabTextColor = getResources().getColorStateList(resId);
533 | updateTabStyles();
534 | }
535 |
536 | public ColorStateList getTextColor() {
537 | return tabTextColor;
538 | }
539 |
540 | public void setTypeface(Typeface typeface, int style) {
541 | this.tabTypeface = typeface;
542 | this.tabTypefaceStyle = style;
543 | updateTabStyles();
544 | }
545 |
546 | public void setTabBackground(int resId) {
547 | this.tabBackgroundResId = resId;
548 | }
549 |
550 | public int getTabBackground() {
551 | return tabBackgroundResId;
552 | }
553 |
554 | public void setTabPaddingLeftRight(int paddingPx) {
555 | this.tabPadding = paddingPx;
556 | updateTabStyles();
557 | }
558 |
559 | public int getTabPaddingLeftRight() {
560 | return tabPadding;
561 | }
562 |
563 | public T getIndicatorChildAtIndex(int position){
564 | if (position >= tabCount) {
565 | throw new IllegalStateException("tab index out of Bounds");
566 | }
567 | return (T) ((LinearLayout) getChildAt(0)).getChildAt(position);
568 | }
569 |
570 | @Override
571 | public void onRestoreInstanceState(Parcelable state) {
572 | SavedState savedState = (SavedState) state;
573 | super.onRestoreInstanceState(savedState.getSuperState());
574 | currentPosition = savedState.currentPosition;
575 | requestLayout();
576 | }
577 |
578 | @Override
579 | public Parcelable onSaveInstanceState() {
580 | Parcelable superState = super.onSaveInstanceState();
581 | SavedState savedState = new SavedState(superState);
582 | savedState.currentPosition = currentPosition;
583 | return savedState;
584 | }
585 |
586 | static class SavedState extends BaseSavedState {
587 | int currentPosition;
588 |
589 | public SavedState(Parcelable superState) {
590 | super(superState);
591 | }
592 |
593 | private SavedState(Parcel in) {
594 | super(in);
595 | currentPosition = in.readInt();
596 | }
597 |
598 | @Override
599 | public void writeToParcel(Parcel dest, int flags) {
600 | super.writeToParcel(dest, flags);
601 | dest.writeInt(currentPosition);
602 | }
603 |
604 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
605 | @Override
606 | public SavedState createFromParcel(Parcel in) {
607 | return new SavedState(in);
608 | }
609 |
610 | @Override
611 | public SavedState[] newArray(int size) {
612 | return new SavedState[size];
613 | }
614 | };
615 | }
616 |
617 | }
618 |
--------------------------------------------------------------------------------
/src/com/touch18/finaldemo/view/StickyLayout.java:
--------------------------------------------------------------------------------
1 | package com.touch18.finaldemo.view;
2 |
3 | import android.content.Context;
4 | import android.support.v4.app.Fragment;
5 | import android.support.v4.app.FragmentPagerAdapter;
6 | import android.support.v4.app.FragmentStatePagerAdapter;
7 | import android.support.v4.view.PagerAdapter;
8 | import android.support.v4.view.ViewPager;
9 | import android.util.AttributeSet;
10 | import android.util.DisplayMetrics;
11 | import android.view.MotionEvent;
12 | import android.view.View;
13 | import android.view.ViewConfiguration;
14 | import android.view.ViewGroup;
15 | import android.view.ViewTreeObserver.OnPreDrawListener;
16 | import android.view.WindowManager;
17 | import android.widget.LinearLayout;
18 | import android.widget.ListView;
19 | import android.widget.OverScroller;
20 | import android.widget.ScrollView;
21 |
22 | import com.touch18.finaldemo.R;
23 | import com.touch18.finaldemo.util.UiUtils;
24 |
25 |
26 | public class StickyLayout extends LinearLayout {
27 |
28 | public enum StickyState{
29 | TOP,MIDDLE,BOTTOM
30 | }
31 |
32 | private View mTop;
33 | private View mNav;
34 | private ViewPager mViewPager;
35 |
36 | private int mTopViewHeight;
37 | private ViewGroup mInnerScrollView;
38 | private boolean isTopHidden = false;
39 |
40 | private OverScroller mScroller;
41 | // private VelocityTracker mVelocityTracker;
42 | private int mTouchSlop;
43 | // private int mMaximumVelocity, mMinimumVelocity;
44 |
45 | // 屏幕高度,屏幕的1/12触发高度(包括State改变,图片旋转)
46 | private int screenWidth,screenHeight,triggerValue,triggerZoom;
47 |
48 | private int middleSticky;
49 |
50 | private int headerHeight = UiUtils.Dp2Px(45);
51 |
52 | private StickyState currentState = StickyState.MIDDLE;
53 |
54 | private float mLastX;
55 | private float mLastY;
56 | private boolean mDragging;
57 |
58 | public StickyLayout(Context context, AttributeSet attrs) {
59 | super(context, attrs);
60 | setOrientation(LinearLayout.VERTICAL);
61 |
62 | mScroller = new OverScroller(context);
63 | // mVelocityTracker = VelocityTracker.obtain();
64 | // mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
65 | mTouchSlop = ViewConfiguration.getTouchSlop();
66 | // mMaximumVelocity = ViewConfiguration.get(context).getScaledMaximumFlingVelocity();
67 | // mMinimumVelocity = ViewConfiguration.get(context).getScaledMinimumFlingVelocity();
68 | WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
69 | DisplayMetrics dm = new DisplayMetrics();
70 | wm.getDefaultDisplay().getMetrics(dm);
71 |
72 | screenHeight = dm.heightPixels;
73 | screenWidth = dm.widthPixels;
74 | middleSticky = (int) (screenHeight * (13/24f));
75 |
76 | triggerZoom = (int) (screenHeight * (1/24f)); // 以 middleSticky 为基准 触发放大缩小
77 | triggerValue = (int) (screenHeight * (1/32f)); // 改变state 的最小单位
78 | }
79 |
80 | @Override
81 | protected void onFinishInflate() {
82 | super.onFinishInflate();
83 | mTop = findViewById(R.id.id_stickylayout_topview);
84 | mNav = findViewById(R.id.id_stickylayout_indicator);
85 | View view = findViewById(R.id.id_stickylayout_viewpager);
86 | if (!(view instanceof ViewPager)) {
87 | throw new RuntimeException("id_stickynavlayout_viewpager show used by ViewPager !");
88 | }
89 | mViewPager = (ViewPager) view;
90 |
91 | mViewPager.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {
92 |
93 | @Override
94 | public boolean onPreDraw() {
95 | mViewPager.getViewTreeObserver().removeOnPreDrawListener(this);
96 | scrollTo(0, middleSticky);
97 | return false;
98 | }
99 | });
100 |
101 | }
102 |
103 | // public void setNeedAnimation(boolean animation){
104 | // this.needAnimation = animation;
105 | // }
106 |
107 | @Override
108 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
109 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
110 | ViewGroup.LayoutParams params = mViewPager.getLayoutParams();
111 | params.height = getMeasuredHeight() - mNav.getMeasuredHeight() - headerHeight;
112 | }
113 |
114 | @Override
115 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
116 | super.onSizeChanged(w, h, oldw, oldh);
117 | mTopViewHeight = mTop.getMeasuredHeight();
118 | }
119 |
120 | @Override
121 | public boolean onInterceptTouchEvent(MotionEvent ev) {
122 | int action = ev.getAction();
123 | float y = ev.getY();
124 | float x = ev.getX();
125 |
126 | switch (action) {
127 | case MotionEvent.ACTION_DOWN:
128 | mLastX = x;
129 | mLastY = y;
130 | break;
131 | case MotionEvent.ACTION_MOVE:
132 | float dx = x - mLastX;
133 | float dy = y - mLastY;
134 |
135 | // mLastX = x;
136 | mLastY = y;
137 | getCurrentScrollView();
138 |
139 | if (Math.abs(dy) > mTouchSlop && Math.abs(dy) > Math.abs(dx)) {
140 | mDragging = true;
141 |
142 | if (mInnerScrollView instanceof ScrollView) {
143 | if (!isTopHidden || (mInnerScrollView.getScrollY() == 0 && isTopHidden && dy > 0)) {
144 | return true;
145 | }
146 | } else if (mInnerScrollView instanceof ListView) {
147 | ListView lv = (ListView) mInnerScrollView;
148 | View c = lv.getChildAt(lv.getFirstVisiblePosition());
149 | if (!isTopHidden || (c != null && c.getTop() == 0 && isTopHidden && dy > 0)) {
150 | return true;
151 | }
152 | }
153 |
154 | }
155 | break;
156 | }
157 | return super.onInterceptTouchEvent(ev);
158 | }
159 |
160 | private void getCurrentScrollView() {
161 |
162 | int currentItem = mViewPager.getCurrentItem();
163 | PagerAdapter a = mViewPager.getAdapter();
164 | if (a instanceof FragmentPagerAdapter) {
165 | FragmentPagerAdapter fadapter = (FragmentPagerAdapter) a;
166 | Fragment item = fadapter.getItem(currentItem);
167 | mInnerScrollView = (ViewGroup) (item.getView().findViewById(R.id.id_stickylayout_innerscrollview));
168 | } else if (a instanceof FragmentStatePagerAdapter) {
169 | FragmentStatePagerAdapter fsAdapter = (FragmentStatePagerAdapter) a;
170 | Fragment item = fsAdapter.getItem(currentItem);
171 | mInnerScrollView = (ViewGroup) (item.getView().findViewById(R.id.id_stickylayout_innerscrollview));
172 | }
173 |
174 | }
175 |
176 | @Override
177 | public boolean onTouchEvent(MotionEvent event) {
178 | // mVelocityTracker.addMovement(event);
179 | int action = event.getAction();
180 | // float x = event.getX();
181 | float y = event.getY();
182 |
183 | switch (action) {
184 | case MotionEvent.ACTION_DOWN:
185 | if (!mScroller.isFinished())
186 | mScroller.abortAnimation();
187 | // mVelocityTracker.clear();
188 | // mVelocityTracker.addMovement(event);
189 | mLastY = y;
190 | return true;
191 | case MotionEvent.ACTION_MOVE:
192 | float dy = y - mLastY;
193 |
194 | if (!mDragging && Math.abs(dy) > mTouchSlop) {
195 | mDragging = true;
196 | }
197 | if (mDragging) {
198 | scrollBy(0, (int) -dy);
199 | mLastY = y;
200 | }
201 | break;
202 | case MotionEvent.ACTION_CANCEL:
203 | mDragging = false;
204 | if (!mScroller.isFinished()) {
205 | mScroller.abortAnimation();
206 | }
207 | break;
208 | case MotionEvent.ACTION_UP:
209 | mDragging = false;
210 | /* mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
211 | int velocityY = (int) mVelocityTracker.getYVelocity();
212 | if (Math.abs(velocityY) > mMinimumVelocity) {
213 | fling(-velocityY);
214 | }
215 | mVelocityTracker.clear();
216 | break;*/
217 | int currentY = getScrollY();
218 |
219 | switch (currentState) {
220 | case TOP:
221 | if(currentY > mTopViewHeight - triggerValue){
222 | currentState = StickyState.TOP;
223 | }else if(currentY > middleSticky + triggerValue){
224 | currentState = StickyState.MIDDLE;
225 | }else{
226 | currentState = StickyState.BOTTOM;
227 | }
228 | break;
229 | case MIDDLE:
230 | if(currentY > middleSticky + triggerValue){
231 | currentState = StickyState.TOP;
232 | }else if(currentY < middleSticky - triggerValue){
233 | currentState = StickyState.BOTTOM;
234 | }else{
235 | currentState = StickyState.MIDDLE;
236 | }
237 | break;
238 | case BOTTOM:
239 | if(currentY < triggerValue){
240 | currentState = StickyState.BOTTOM;
241 | }else if(currentY > middleSticky + triggerValue){
242 | currentState = StickyState.TOP;
243 | }else{
244 | currentState = StickyState.MIDDLE;
245 | }
246 | break;
247 | }
248 |
249 | switchState(currentState);
250 |
251 | }
252 |
253 | return super.onTouchEvent(event);
254 | }
255 |
256 | public StickyState getCurrentState() {
257 | return currentState;
258 | }
259 |
260 | public int getMiddleSticky() {
261 | return middleSticky;
262 | }
263 |
264 | public void switchState(StickyState currentState) {
265 | this.currentState = currentState;
266 |
267 | int scrollY = getScrollY();
268 | int dy = 0;
269 | if(currentState == StickyState.TOP){
270 | // scrollTo(0, mTopViewHeight);
271 | dy = mTopViewHeight - headerHeight - scrollY;
272 | }else if(currentState == StickyState.MIDDLE){
273 | // scrollTo(0, middleSticky);
274 | dy = middleSticky - scrollY;
275 | }else if(currentState == StickyState.BOTTOM){
276 | // scrollTo(0, 0);
277 | dy = 0 - scrollY;
278 | }
279 |
280 | mScroller.startScroll(0, scrollY, 0, dy,Math.abs(dy));
281 | invalidate();
282 | }
283 |
284 |
285 | @Override
286 | public void computeScroll() {
287 | if (mScroller.computeScrollOffset()) {
288 | scrollTo(0, mScroller.getCurrY());
289 | invalidate();
290 | }
291 | }
292 |
293 | /* public void fling(int velocityY) {
294 | mScroller.fling(0, getScrollY(), 0, velocityY, 0, 0, 0, mTopViewHeight);
295 | invalidate();
296 | }*/
297 |
298 | private boolean zoomFlag = false;
299 | // private boolean needAnimation = false; // viewPager中图片是否需要旋转
300 |
301 | public interface TriggerZoomListener{
302 | void zoom(boolean zoomUp);
303 | }
304 |
305 | private TriggerZoomListener mTriggerZoomListener;
306 | public void setTriggerZoomListener(TriggerZoomListener mTriggerZoomListener) {
307 | this.mTriggerZoomListener = mTriggerZoomListener;
308 | }
309 |
310 | private onScrollChangedListener mScrollChangedListener;
311 | public interface onScrollChangedListener{
312 | void onScroll(int l, int t, int oldl, int oldt);
313 | }
314 | public void setOnScrollChangedListener(onScrollChangedListener mScrollChangedListener) {
315 | this.mScrollChangedListener = mScrollChangedListener;
316 | }
317 |
318 | @Override
319 | protected void onScrollChanged(int l, int t, int oldl, int oldt) {
320 | // if(needAnimation){
321 | // TODO 变化多大触发动画 1/12f
322 | if(!zoomFlag && t <= middleSticky - triggerZoom && oldt - t > 0){
323 | // 放大
324 | zoomFlag = !zoomFlag;
325 | if(mTriggerZoomListener != null){
326 | mTriggerZoomListener.zoom(true);
327 | }
328 | }else if(zoomFlag && t > middleSticky - triggerZoom && oldt - t < 0){
329 | // 缩小
330 | zoomFlag = !zoomFlag;
331 | if(mTriggerZoomListener != null){
332 | mTriggerZoomListener.zoom(false);
333 | }
334 | }
335 | // }
336 |
337 | if(mScrollChangedListener!= null)
338 | mScrollChangedListener.onScroll(l, t, oldl, oldt);
339 |
340 | super.onScrollChanged(l, t, oldl, oldt);
341 | }
342 |
343 | @Override
344 | public void scrollTo(int x, int y) {
345 | if (y < 0) {
346 | y = 0;
347 | }
348 | if (y > mTopViewHeight - headerHeight) {
349 | y = mTopViewHeight - headerHeight;
350 | }
351 | if (y != getScrollY()) {
352 | super.scrollTo(x, y);
353 | }
354 |
355 | isTopHidden = (getScrollY() == mTopViewHeight - headerHeight);
356 |
357 | }
358 |
359 |
360 | }
361 |
--------------------------------------------------------------------------------