├── .idea ├── YPX_RefreshLayout.iml ├── misc.xml ├── modules.xml ├── vcs.xml └── workspace.xml ├── README.md └── YPX_RefreshLayout_demo ├── .gitignore ├── .idea ├── caches │ ├── build_file_checksums.ser │ └── gradle_models.ser ├── codeStyles │ └── Project.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── ypx │ │ └── jiehunle │ │ └── ypx_bezierqqrefreshdemo │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── ypx │ │ │ └── jiehunle │ │ │ └── ypx_bezierqqrefreshdemo │ │ │ ├── MainActivity.java │ │ │ ├── PullToRefreshRecyclerView.java │ │ │ ├── YPXTabIndicator │ │ │ ├── YPXTabIndicator.java │ │ │ └── YPXViewPager.java │ │ │ ├── adapters │ │ │ ├── ListViewAdapter.java │ │ │ └── RecyclerViewAdapter.java │ │ │ └── fragments │ │ │ ├── GridViewFragment.java │ │ │ ├── ListViewFragment.java │ │ │ ├── NormalRefreshFragment.java │ │ │ ├── RecyclerViewFragment.java │ │ │ ├── ScrollViewFragment.java │ │ │ └── WebViewFragment.java │ └── res │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── fragment_gridview.xml │ │ ├── fragment_listview.xml │ │ ├── fragment_normalrefresh.xml │ │ ├── fragment_recyclerview.xml │ │ ├── fragment_scrollview.xml │ │ ├── fragment_webview.xml │ │ ├── item.xml │ │ └── layout_pulltorefresh.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── ypx │ └── jiehunle │ └── ypx_bezierqqrefreshdemo │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── projectFilesBackup └── .idea │ └── workspace.xml ├── refreshlayout ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── ypx │ │ └── refreshlayout │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── ypx │ │ │ └── refreshlayout │ │ │ ├── YPXRefreshBaseView.java │ │ │ ├── simple │ │ │ ├── YPXNormalRefreshView.java │ │ │ └── qq │ │ │ │ ├── YPXBezierHeaderView.java │ │ │ │ └── YPXQQRefreshView.java │ │ │ └── util │ │ │ └── TimeSPUtil.java │ └── res │ │ ├── drawable │ │ └── pulling.xml │ │ ├── layout │ │ ├── a_layout_qq_header.xml │ │ └── layout_refresh_header.xml │ │ ├── mipmap-xhdpi │ │ ├── pull_down.png │ │ ├── pull_failure.png │ │ ├── pull_indicator_arrow.png │ │ ├── pull_ok.png │ │ ├── pull_progessing.png │ │ └── pull_up.png │ │ └── mipmap-xxhdpi │ │ └── refresh.png │ └── test │ └── java │ └── com │ └── ypx │ └── refreshlayout │ └── ExampleUnitTest.java └── settings.gradle /.idea/YPX_RefreshLayout.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Android 12 | 13 | 14 | Android Lint 15 | 16 | 17 | CorrectnessLintAndroid 18 | 19 | 20 | General 21 | 22 | 23 | LintAndroid 24 | 25 | 26 | Maven 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 1.8 38 | 39 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 27 | 28 | 29 | 31 | 32 | 35 | 36 | 37 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 65 | 66 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 79 | 80 | 83 | 84 | 85 | 86 | 89 | 90 | 93 | 94 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 122 | 123 | 124 | 125 | 126 | 139 | 140 | 147 | 148 | 149 | 150 | 168 | 175 | 176 | 184 | 185 | 190 | 191 | 193 | 194 | 195 | 197 | 198 | 199 | 200 | 1522317842807 201 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 251 | 252 | 253 | 254 | 255 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # YPXRefreshLayout 2 | 通用下拉刷新控件 3 | 4 | 引用方式: 5 | 6 | compile 'com.ypx.refreshlayout:refreshlayout:1.1.7' 7 | 8 | 9 | -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/.idea/caches/build_file_checksums.ser: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangpeixing/YPXRefreshLayout/d4da7c7f4c122e24fcabb3131f44ec4ed4b54af7/YPX_RefreshLayout_demo/.idea/caches/build_file_checksums.ser -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/.idea/caches/gradle_models.ser: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangpeixing/YPXRefreshLayout/d4da7c7f4c122e24fcabb3131f44ec4ed4b54af7/YPX_RefreshLayout_demo/.idea/caches/gradle_models.ser -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 | 8 | 9 | 10 | xmlns:android 11 | 12 | ^$ 13 | 14 | 15 | 16 |
17 |
18 | 19 | 20 | 21 | xmlns:.* 22 | 23 | ^$ 24 | 25 | 26 | BY_NAME 27 | 28 |
29 |
30 | 31 | 32 | 33 | .*:id 34 | 35 | http://schemas.android.com/apk/res/android 36 | 37 | 38 | 39 |
40 |
41 | 42 | 43 | 44 | .*:name 45 | 46 | http://schemas.android.com/apk/res/android 47 | 48 | 49 | 50 |
51 |
52 | 53 | 54 | 55 | name 56 | 57 | ^$ 58 | 59 | 60 | 61 |
62 |
63 | 64 | 65 | 66 | style 67 | 68 | ^$ 69 | 70 | 71 | 72 |
73 |
74 | 75 | 76 | 77 | .* 78 | 79 | ^$ 80 | 81 | 82 | BY_NAME 83 | 84 |
85 |
86 | 87 | 88 | 89 | .* 90 | 91 | http://schemas.android.com/apk/res/android 92 | 93 | 94 | ANDROID_ATTRIBUTE_ORDER 95 | 96 |
97 |
98 | 99 | 100 | 101 | .* 102 | 103 | .* 104 | 105 | 106 | BY_NAME 107 | 108 |
109 |
110 |
111 |
112 |
113 |
-------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 23 | 24 | -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 37 | 38 | 39 | 40 | 41 | 42 | 44 | -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion '25.0.3' 6 | 7 | defaultConfig { 8 | applicationId "com.ypx.jiehunle.ypx_bezierqqrefreshdemo" 9 | minSdkVersion 17 10 | targetSdkVersion 25 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | 15 | lintOptions { 16 | abortOnError false 17 | } 18 | 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | } 26 | 27 | dependencies { 28 | compile fileTree(include: ['*.jar'], dir: 'libs') 29 | testCompile 'junit:junit:4.12' 30 | compile 'com.android.support:appcompat-v7:25.4.0' 31 | compile 'com.android.support:recyclerview-v7:25.4.0' 32 | compile 'com.ypx.refreshlayout:refreshlayout:1.1.7' 33 | //compile project(':refreshlayout') 34 | } 35 | -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/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/jiehunle/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/app/src/androidTest/java/com/ypx/jiehunle/ypx_bezierqqrefreshdemo/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.ypx.jiehunle.ypx_bezierqqrefreshdemo; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/app/src/main/java/com/ypx/jiehunle/ypx_bezierqqrefreshdemo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.ypx.jiehunle.ypx_bezierqqrefreshdemo; 2 | 3 | import android.graphics.Color; 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v4.app.FragmentPagerAdapter; 7 | import android.support.v4.view.ViewPager; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.util.TypedValue; 10 | 11 | import com.ypx.jiehunle.ypx_bezierqqrefreshdemo.YPXTabIndicator.YPXTabIndicator; 12 | import com.ypx.jiehunle.ypx_bezierqqrefreshdemo.fragments.GridViewFragment; 13 | import com.ypx.jiehunle.ypx_bezierqqrefreshdemo.fragments.ListViewFragment; 14 | import com.ypx.jiehunle.ypx_bezierqqrefreshdemo.fragments.NormalRefreshFragment; 15 | import com.ypx.jiehunle.ypx_bezierqqrefreshdemo.fragments.RecyclerViewFragment; 16 | import com.ypx.jiehunle.ypx_bezierqqrefreshdemo.fragments.ScrollViewFragment; 17 | import com.ypx.jiehunle.ypx_bezierqqrefreshdemo.fragments.WebViewFragment; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | public class MainActivity extends AppCompatActivity { 23 | ScrollViewFragment scrollViewFragment; 24 | ListViewFragment listViewFragment; 25 | WebViewFragment webViewFragment; 26 | RecyclerViewFragment recyclerViewFragment; 27 | GridViewFragment gridViewFragment; 28 | NormalRefreshFragment normalRefreshFragment; 29 | private List mTabContents = new ArrayList<>(); 30 | private FragmentPagerAdapter mAdapter; 31 | private ViewPager mViewPager; 32 | private String[] mDatas; 33 | private YPXTabIndicator mIndicator2; 34 | 35 | @Override 36 | protected void onCreate(Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | setContentView(R.layout.activity_main); 39 | initView(); 40 | initData(); 41 | setStyle(); 42 | } 43 | 44 | private void initData() { 45 | mDatas = new String[]{"ScrollView", "ListView", "WebView", "RecyclerView", "GridView", "普通刷新"}; 46 | mTabContents.clear(); 47 | if (scrollViewFragment == null) { 48 | scrollViewFragment = new ScrollViewFragment(); 49 | } 50 | mTabContents.add(scrollViewFragment); 51 | if (listViewFragment == null) { 52 | listViewFragment = new ListViewFragment(); 53 | } 54 | mTabContents.add(listViewFragment); 55 | if (webViewFragment == null) { 56 | webViewFragment = new WebViewFragment(); 57 | } 58 | mTabContents.add(webViewFragment); 59 | if (recyclerViewFragment == null) { 60 | recyclerViewFragment = new RecyclerViewFragment(); 61 | } 62 | mTabContents.add(recyclerViewFragment); 63 | 64 | if (gridViewFragment == null) { 65 | gridViewFragment = new GridViewFragment(); 66 | } 67 | mTabContents.add(gridViewFragment); 68 | 69 | if (normalRefreshFragment == null) { 70 | normalRefreshFragment = new NormalRefreshFragment(); 71 | } 72 | mTabContents.add(normalRefreshFragment); 73 | 74 | mAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) { 75 | @Override 76 | public int getCount() { 77 | return mTabContents.size(); 78 | } 79 | 80 | @Override 81 | public Fragment getItem(int position) { 82 | return mTabContents.get(position); 83 | } 84 | }; 85 | 86 | } 87 | 88 | private void initView() { 89 | mViewPager = (ViewPager) findViewById(R.id.id_vp); 90 | mIndicator2 = (YPXTabIndicator) findViewById(R.id.netEaseIndicator2); 91 | mViewPager.setOffscreenPageLimit(6); 92 | } 93 | 94 | protected void setStyle() { 95 | mViewPager.setAdapter(mAdapter); 96 | mIndicator2.setViewPager(mViewPager, 0); 97 | mIndicator2.setTitles(mDatas); 98 | mIndicator2.setDefaultHeight(dp(44));//设置默认高度为30dp 99 | mIndicator2.setTabPadding(dp(10), 0, dp(10), dp(0));//设置tabPadding左右10dp 100 | mIndicator2.setBackgroundRadius(0);//设置外框半径25dp 101 | mIndicator2.setShowTabSizeChange(true);//显示字体大小切换效果 102 | mIndicator2.setShowBackground(false);//不显示背景 103 | mIndicator2.setShowIndicator(true);//显示指示器 104 | mIndicator2.setDeuceTabWidth(false);//不平分tab宽度,默认为平分 105 | mIndicator2.setTabTextSize(14);//设置tab默认字体大小 106 | mIndicator2.setTabMaxTextSize(16);//设置tab变换字体大小,如果setShowTabSizeChange设置false,则按默认字体大小 107 | mIndicator2.setTabPressColor(Color.RED);//设置tab选中后的字体颜色 108 | mIndicator2.setTabTextColor(Color.parseColor("#666666"));//设置未选中时字体颜色 109 | mIndicator2.setIndicatorColor(Color.RED);//设置指示器颜色为红色 110 | mIndicator2.setmBackgroundColor(Color.WHITE);//设置背景颜色为红色,如果setShowBackground为false则无背景 111 | mIndicator2.setBackgroundLineColor(Color.WHITE);//设置背景框颜色,如果setShowBackground为false则无背景框颜色 112 | mIndicator2.setBackgroundStrokeWidth(0);//设置背景框宽度\ 113 | //mIndicator2.setTabWidth(ScreenUtils.getScreenWidth(this)/3);//强制tab宽度,优先级最高,设置了固定宽度后,不平分宽度设置就会无效 114 | } 115 | 116 | public int dp(int dp) { 117 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 118 | dp, getResources().getDisplayMetrics()); 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/app/src/main/java/com/ypx/jiehunle/ypx_bezierqqrefreshdemo/PullToRefreshRecyclerView.java: -------------------------------------------------------------------------------- 1 | package com.ypx.jiehunle.ypx_bezierqqrefreshdemo; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.widget.LinearLayout; 8 | 9 | import com.ypx.refreshlayout.YPXRefreshBaseView; 10 | import com.ypx.refreshlayout.simple.qq.YPXQQRefreshView; 11 | 12 | /** 13 | * Description: TODO 14 | *

15 | * Author: peixing.yang 16 | * Date: 2019/3/11 17 | */ 18 | public class PullToRefreshRecyclerView extends LinearLayout { 19 | 20 | public PullToRefreshRecyclerView(Context context) { 21 | super(context); 22 | } 23 | 24 | public PullToRefreshRecyclerView(Context context, AttributeSet attrs) { 25 | super(context, attrs); 26 | } 27 | 28 | // private void init(){ 29 | //// View view=LayoutInflater.from(getContext()).inflate(R.layout.) 30 | //// } 31 | //// 32 | //// public View setFootView(){ 33 | //// 34 | //// } 35 | } 36 | -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/app/src/main/java/com/ypx/jiehunle/ypx_bezierqqrefreshdemo/YPXTabIndicator/YPXTabIndicator.java: -------------------------------------------------------------------------------- 1 | package com.ypx.jiehunle.ypx_bezierqqrefreshdemo.YPXTabIndicator; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.graphics.RectF; 8 | import android.graphics.drawable.GradientDrawable; 9 | import android.support.v4.view.ViewPager; 10 | import android.support.v4.view.ViewPager.OnPageChangeListener; 11 | import android.text.TextPaint; 12 | import android.util.AttributeSet; 13 | import android.util.DisplayMetrics; 14 | import android.util.TypedValue; 15 | import android.view.Gravity; 16 | import android.view.View; 17 | import android.view.ViewGroup; 18 | import android.view.WindowManager; 19 | import android.widget.FrameLayout; 20 | import android.widget.HorizontalScrollView; 21 | import android.widget.LinearLayout; 22 | import android.widget.TextView; 23 | 24 | 25 | /** 26 | * 仿网易圆形移动viewpager指示器 27 | *

28 | * 博客地址:http://blog.csdn.net/qq_16674697/article/details/51954228 29 | * 30 | * @author yangpeixing 31 | */ 32 | @SuppressWarnings("unused") 33 | public class YPXTabIndicator extends LinearLayout implements 34 | OnPageChangeListener, YPXViewPager.OnPageChangeListener { 35 | private Paint mLinePaint; 36 | /** 37 | * 自定义指示器构造器 38 | */ 39 | private DrawIndicatorCreator creator; 40 | private int screenWidth = 0; 41 | /** 42 | * 内部椭圆背景paint 43 | */ 44 | private Paint indicatorPaint; 45 | /** 46 | * 外围背景线条宽度,默认为0px 47 | */ 48 | private int strokeWidth = 0; 49 | /** 50 | * 背景色,,默认为红色#ff0000 51 | */ 52 | private int backgroundColor = Color.WHITE; 53 | /** 54 | * 背景线条色 55 | */ 56 | private int backgroundLineColor = Color.WHITE; 57 | /** 58 | * 指示器颜色 59 | */ 60 | private int indicatorColor = Color.RED; 61 | /** 62 | * 背景和指示器半径,默认无背景 63 | */ 64 | private int backgroundRadius = 0; 65 | /** 66 | * 记录tab宽度数组 67 | */ 68 | private int[] tabLengthArray; 69 | /** 70 | * x轴偏移量 71 | */ 72 | private int mTransitX = 0; 73 | /** 74 | * tab默认大小为14 75 | */ 76 | private int tabTextSize = 14; 77 | /** 78 | * 设置tab默认颜色,既未选中时颜色 79 | */ 80 | private int tabTextColor = Color.parseColor("#666666"); 81 | /** 82 | * tab选中后颜色,默认和背景色一致 83 | */ 84 | private int tabPressColor = indicatorColor; 85 | private int mTabWidth = 0; 86 | private String[] titles; 87 | private ViewPager viewPager; 88 | private YPXViewPager ypxViewPager; 89 | /** 90 | * 默认高度,用户可自己设置高度,默认50px 91 | */ 92 | private int defaultHeight = 50; 93 | /** 94 | * viewpager坐标 95 | */ 96 | private int mCurrentIndex = 0; 97 | /** 98 | * 默认选中第几个tab 99 | */ 100 | private int mInitIndex = 0; 101 | /** 102 | * 判断是否点击 103 | */ 104 | private boolean isClick = false; 105 | /** 106 | * 是否显示tab中间分割线 107 | */ 108 | private boolean isShowTabDivider = false; 109 | /** 110 | * 是否设置背景 111 | */ 112 | private boolean isShowBackground = true; 113 | /** 114 | * 是否设置指示器 115 | */ 116 | private boolean isShowIndicator = true; 117 | /** 118 | * 是否设置tab字体变换 119 | */ 120 | private boolean isShowTabSizeChange = true; 121 | /** 122 | * 是否平分tab的宽度,若false,则返回每个tab自适应的宽度,适合在多种数目下使用 123 | */ 124 | private boolean isDeuceTabWidth = false; 125 | /** 126 | * 最大字体大小,默认为16 127 | */ 128 | private int maxTabTextSize = 16; 129 | /** 130 | * tab总数 131 | */ 132 | private int totalCount = 0; 133 | /** 134 | * 是否手动设置了tab的宽度 135 | */ 136 | private boolean isSetTabWidth = false; 137 | /** 138 | * 是否是HorizonScrollView的子View 139 | */ 140 | private boolean isChildOfHorizontalScrollView = false; 141 | 142 | private int tabPaddingLeft = dp(10), tabPaddingRight = dp(10), tabPaddingTop = 0, 143 | tabPaddingBottom = 0; 144 | 145 | /** 146 | * Tab排版模式 147 | */ 148 | private int tabGravity = Gravity.CENTER; 149 | /** 150 | * 对外的ViewPager的回调接口 151 | */ 152 | private PageChangeListener onPageChangeListener; 153 | private TabClickListener tabClickListener; 154 | 155 | private int tabLeftMargin = 0; 156 | private int tabRightMargin = 0; 157 | 158 | private int dividerTopAndBottomMargin = 0; 159 | private int dividerColor = Color.parseColor("#EBEBEB"); 160 | 161 | public YPXTabIndicator(Context context) { 162 | this(context, null); 163 | } 164 | 165 | public YPXTabIndicator(Context context, AttributeSet attrs) { 166 | this(context, attrs, 0); 167 | } 168 | 169 | public YPXTabIndicator(Context context, AttributeSet attrs, 170 | int defStyleAttr) { 171 | super(context, attrs, defStyleAttr); 172 | setOrientation(HORIZONTAL); 173 | setGravity(Gravity.CENTER); 174 | initView(); 175 | } 176 | 177 | private void initView() { 178 | mCurrentIndex = 0; 179 | mInitIndex = 0; 180 | mTabWidth = 0; 181 | mTransitX = 0; 182 | defaultHeight = dp(44); 183 | titles = new String[]{"tab1", "tab2", "tab3"}; 184 | tabLengthArray = new int[titles.length]; 185 | screenWidth = getScreenWidth(); 186 | initPaints(); 187 | setBackgroundShape(); 188 | refreshTabLayouts(); 189 | } 190 | 191 | /** 192 | * 初始化指示器画笔 193 | */ 194 | private void initPaints() { 195 | indicatorPaint = new Paint(); 196 | indicatorPaint.setAntiAlias(true); 197 | indicatorPaint.setColor(indicatorColor); 198 | indicatorPaint.setStyle(Paint.Style.FILL); 199 | } 200 | 201 | /** 202 | * 设置圆角背景,可定制圆角和边框(大小和颜色) 203 | */ 204 | private void setBackgroundShape() { 205 | GradientDrawable gd = new GradientDrawable(); 206 | gd.setColor(backgroundColor); 207 | gd.setCornerRadius(backgroundRadius); 208 | gd.setStroke(strokeWidth, backgroundLineColor); 209 | if (isShowBackground) { 210 | setBackground(gd); 211 | } else { 212 | setBackgroundColor(backgroundColor); 213 | } 214 | } 215 | 216 | /** 217 | * 重置刷新所有Tab 218 | */ 219 | private void refreshTabLayouts() { 220 | removeAllViews(); 221 | for (int i = 0; i < titles.length; i++) { 222 | addView(createDefaultTab(titles[i], i)); 223 | } 224 | refreshCurrentTab(); 225 | } 226 | 227 | /** 228 | * 刷新选中Tab 229 | */ 230 | public void refreshCurrentTab() { 231 | resetTabColor(); 232 | resetTabSize(); 233 | getTab(mCurrentIndex).setTextColor(tabPressColor); 234 | if (isShowTabSizeChange) { 235 | getTab(mCurrentIndex).setTextSize(maxTabTextSize); 236 | } else { 237 | getTab(mCurrentIndex).setTextSize(tabTextSize); 238 | } 239 | mTransitX = getTransitXByPosition(mCurrentIndex); 240 | mTabWidth = tabLengthArray[mCurrentIndex]; 241 | int centerX = mTransitX - (screenWidth - mTabWidth) / 2 + tabLeftMargin; 242 | parentScrollTo(centerX, 0); 243 | invalidate(); 244 | } 245 | 246 | /** 247 | * 创建默认tab(TextView) 248 | * 249 | * @param string 要显示的文本 250 | * @param i 坐标 251 | */ 252 | private TextView createDefaultTab(String string, final int i) { 253 | TextView textView = new TextView(getContext()); 254 | textView.setGravity(Gravity.CENTER); 255 | textView.setTextColor(tabTextColor); 256 | textView.setTextSize(tabTextSize); 257 | textView.setText(string); 258 | textView.setPadding(tabPaddingLeft, tabPaddingTop, tabPaddingRight, 259 | tabPaddingBottom); 260 | TextPaint mTextPaint; 261 | if (isShowTabSizeChange) {//设置是否字体变换 262 | TextView dTextView = new TextView(getContext()); 263 | dTextView.setTextSize(maxTabTextSize); 264 | mTextPaint = dTextView.getPaint();//得到最大尺寸textView的Paint,用于测量宽度 265 | } else { 266 | mTextPaint = textView.getPaint(); 267 | } 268 | if (!isSetTabWidth) { 269 | mTabWidth = (int) mTextPaint.measureText(isDeuceTabWidth ? getMaxLengthString(titles) : string) 270 | + tabPaddingLeft + tabPaddingRight; 271 | } 272 | tabLengthArray[i] = mTabWidth; 273 | LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(mTabWidth, defaultHeight + tabPaddingBottom + tabPaddingTop); 274 | if (i == 0) { 275 | params.leftMargin = tabLeftMargin; 276 | } 277 | 278 | if (i == totalCount - 1) { 279 | params.rightMargin = tabRightMargin; 280 | } 281 | textView.setOnClickListener(new OnClickListener() { 282 | @Override 283 | public void onClick(View v) { 284 | isClick = true; 285 | setCurrentIndex(i); 286 | if (tabClickListener != null) { 287 | tabClickListener.onClick((TextView) v, i); 288 | } 289 | } 290 | }); 291 | textView.setLayoutParams(params); 292 | return textView; 293 | } 294 | 295 | /** 296 | * 设置整个指示器左边距和右边距,即第一个tab的左边距和最后一个tab的右边距 297 | * 如果当前tab布局排版模式为居中,则设置左右间距无效 298 | * 299 | * @param tabLeftMargin 左边距 300 | * @param tabRightMargin 右边距 301 | */ 302 | public void setTabLeftAndRightMargin(int tabLeftMargin, int tabRightMargin) { 303 | if (tabGravity == Gravity.CENTER) { 304 | return; 305 | } 306 | this.tabLeftMargin = tabLeftMargin; 307 | this.tabRightMargin = tabRightMargin; 308 | 309 | LinearLayout.LayoutParams pa = (LinearLayout.LayoutParams) getTab(0).getLayoutParams(); 310 | pa.leftMargin = tabLeftMargin; 311 | getTab(0).setLayoutParams(pa); 312 | 313 | LinearLayout.LayoutParams pa2 = (LinearLayout.LayoutParams) getTab(getChildCount() - 1).getLayoutParams(); 314 | pa2.rightMargin = tabRightMargin; 315 | getTab(getChildCount() - 1).setLayoutParams(pa2); 316 | } 317 | 318 | 319 | /** 320 | * 获取position前几项tab宽度之和 321 | * 322 | * @param position 索引 323 | */ 324 | private int getTransitXByPosition(int position) { 325 | int defaultNum = 0; 326 | for (int i = 0; i < position; i++) { 327 | defaultNum += tabLengthArray[i]; 328 | } 329 | return defaultNum; 330 | } 331 | 332 | /** 333 | * 显示tab分割线 334 | * 335 | * @param isShowTabDivider 显示tab分割线 336 | * @param dividerTopAndBottomMargin tab分割线上下间距 337 | */ 338 | public void setShowTabDivider(boolean isShowTabDivider, int dividerTopAndBottomMargin, int dividerColor) { 339 | this.isShowTabDivider = isShowTabDivider; 340 | this.dividerTopAndBottomMargin = dividerTopAndBottomMargin; 341 | this.dividerColor = dividerColor; 342 | invalidate(); 343 | } 344 | 345 | public void setShowTabDivider(boolean isShowTabDivider) { 346 | this.isShowTabDivider = isShowTabDivider; 347 | invalidate(); 348 | } 349 | 350 | @Override 351 | protected void dispatchDraw(Canvas canvas) { 352 | defaultHeight = getMeasuredHeight(); 353 | if (mCurrentIndex == 0) { 354 | mTabWidth = tabLengthArray[0]; 355 | } 356 | int left = mTransitX + mInitIndex * mTabWidth + getTab(0).getLeft();// tab左边距离原点的位置 357 | int right = mTabWidth + left;// 整个tab的位置 358 | int top = 0;// tab距离顶端的位置 359 | int bottom = defaultHeight;// 整个tab的高度 360 | 361 | if (isShowTabDivider) { 362 | drawDivider(canvas); 363 | } 364 | 365 | if (isShowIndicator) { 366 | if (creator != null) { 367 | creator.drawIndicator(canvas, left, top, right, bottom, 368 | indicatorPaint, backgroundRadius); 369 | } else { 370 | drawUnderLineIndicatorWithTransitX(canvas, left, top, right, bottom, indicatorPaint); 371 | } 372 | } 373 | if (mInitIndex != 0) { 374 | (getTab(mInitIndex)).setTextColor(backgroundColor); 375 | int centerX = getTransitXByPosition(mInitIndex) 376 | - (screenWidth - tabLengthArray[mInitIndex]) / 2; 377 | parentScrollTo(centerX, 0); 378 | } 379 | mInitIndex = 0;// 清除第一次默认index 380 | super.dispatchDraw(canvas); 381 | } 382 | 383 | 384 | /** 385 | * 画分割线 386 | * 387 | * @param canvas 画布 388 | */ 389 | private void drawDivider(Canvas canvas) { 390 | if (mLinePaint == null) { 391 | mLinePaint = new Paint(); 392 | mLinePaint.setColor(dividerColor); 393 | mLinePaint.setStrokeWidth(1); 394 | mLinePaint.setAntiAlias(true); 395 | } 396 | for (int i = 1; i < totalCount; i++) { 397 | float x = (getTransitXByPosition(i) + tabLeftMargin) * 1.0f; 398 | float y = dividerTopAndBottomMargin; 399 | float endY = defaultHeight * 1.0f - dividerTopAndBottomMargin; 400 | canvas.drawLines(new float[]{x, y, x, endY}, mLinePaint); 401 | } 402 | } 403 | 404 | /** 405 | * 默认为圆角矩形指示器,用户可继承重写自定义指示器样式 406 | * 407 | * @param canvas 画布 408 | * @param left tab左边距离原点的位置 409 | * @param top 整个tab的位置 410 | * @param right tab距离顶端的位置 411 | * @param bottom 整个tab的高度,既控件高度 412 | * @param paint 指示器画笔 413 | */ 414 | public void drawIndicatorWithTransitX(Canvas canvas, int left, int top, 415 | int right, int bottom, Paint paint) { 416 | if (backgroundRadius < defaultHeight / 2) { 417 | // 真机运行用这种方式,模拟器圆角会失真 418 | RectF oval = new RectF(left, top, right, bottom);// 设置个新的长方形,扫描测量 419 | canvas.drawRoundRect(oval, backgroundRadius, backgroundRadius, 420 | paint); 421 | } else {// 画三段代替圆角矩形,既圆、矩形、圆 422 | RectF oval2 = new RectF(bottom / 2 + left, top, right - bottom / 2, 423 | bottom); 424 | canvas.drawCircle(oval2.left, bottom / 2, bottom / 2, 425 | indicatorPaint); 426 | canvas.drawRect(oval2, indicatorPaint); 427 | canvas.drawCircle(oval2.right, bottom / 2, bottom / 2, paint); 428 | } 429 | } 430 | 431 | public void setViewPager(ViewPager viewPager, int index) { 432 | this.viewPager = viewPager; 433 | this.mCurrentIndex = index; 434 | mInitIndex = index; 435 | isChildOfHorizontalScrollView = (getParent() != null 436 | && (getParent() instanceof HorizontalScrollView)); 437 | 438 | viewPager.addOnPageChangeListener(this); 439 | setCurrentIndex(index); 440 | } 441 | 442 | public void setViewPager(YPXViewPager viewPager, int index) { 443 | this.ypxViewPager = viewPager; 444 | this.mCurrentIndex = index; 445 | mInitIndex = index; 446 | isChildOfHorizontalScrollView = (getParent() != null 447 | && (getParent() instanceof HorizontalScrollView)); 448 | ypxViewPager.setOnPageChangeListener(this); 449 | setCurrentIndex(index); 450 | 451 | } 452 | 453 | /** 454 | * 如果父控件是HorizonScrollView,则控制父控件移动 455 | * 456 | * @param x x 457 | * @param y y 458 | */ 459 | public void parentScrollTo(int x, int y) { 460 | if (isChildOfHorizontalScrollView) { 461 | ((HorizontalScrollView) getParent()).smoothScrollTo(x, y); 462 | } 463 | } 464 | 465 | /** 466 | * 设置颜色变换 467 | * 468 | * @param position 索引 469 | * @param positionOffset 变化因子 470 | */ 471 | protected void setTabColorChange(int position, float positionOffset) { 472 | getTab(position).setTextColor( 473 | blendColors(tabPressColor, tabTextColor, positionOffset)); 474 | 475 | } 476 | 477 | /** 478 | * 设置字体大小变换 479 | * 480 | * @param position 索引 481 | * @param positionOffset 变化因子 482 | */ 483 | protected void setTabSizeChange(int position, float positionOffset) { 484 | getTab(position).setTextSize( 485 | blendSize(tabTextSize, maxTabTextSize, positionOffset)); 486 | } 487 | 488 | /** 489 | * 两个大小渐变 490 | * 491 | * @param minSize 最小尺寸 492 | * @param maxSize 最大尺寸 493 | * @param ratio 渐变率 494 | * @return 计算后的尺寸 495 | */ 496 | private float blendSize(int minSize, int maxSize, float ratio) { 497 | return (minSize + (maxSize - minSize) * ratio * 1.0f); 498 | } 499 | 500 | /** 501 | * 两个颜色渐变转化 502 | * 503 | * @param color1 默认色 504 | * @param color2 目标色 505 | * @param ratio 渐变率(0~1) 506 | * @return 计算后的颜色 507 | */ 508 | private int blendColors(int color1, int color2, float ratio) { 509 | final float inverseRation = 1f - ratio; 510 | float r = (Color.red(color1) * ratio) 511 | + (Color.red(color2) * inverseRation); 512 | float g = (Color.green(color1) * ratio) 513 | + (Color.green(color2) * inverseRation); 514 | float b = (Color.blue(color1) * ratio) 515 | + (Color.blue(color2) * inverseRation); 516 | return Color.rgb((int) r, (int) g, (int) b); 517 | } 518 | 519 | /** 520 | * 设置Tab的排版模式,比如居中和居左(相对父布局) 521 | * 如果可以横向滑动,则限定居左加载(已限定死,外部无法更改) 522 | * 如果不能横向滑动,则根据用户传入参数决定排版,默认居中 523 | * 524 | * @param tabGravity 排版模式,只针对tab数量不足一屏时生效 525 | */ 526 | public void setTabLayoutGravity(int tabGravity) { 527 | this.tabGravity = tabGravity; 528 | if (isChildOfHorizontalScrollView) { 529 | FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) this.getLayoutParams(); 530 | if (params == null) { 531 | return; 532 | } 533 | if (parentCanScroll()) { 534 | params.gravity = Gravity.START | Gravity.CENTER; 535 | } else { 536 | params.gravity = tabGravity; 537 | } 538 | setLayoutParams(params); 539 | } else { 540 | if (this.getLayoutParams() instanceof LinearLayout.LayoutParams) { 541 | LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) this.getLayoutParams(); 542 | params.gravity = tabGravity; 543 | setLayoutParams(params); 544 | } else if (this.getLayoutParams() instanceof FrameLayout.LayoutParams) { 545 | FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) this.getLayoutParams(); 546 | params.gravity = tabGravity; 547 | setLayoutParams(params); 548 | } 549 | 550 | } 551 | 552 | } 553 | 554 | /** 555 | * 检测父布局是否可以滑动,换句话说,用来检测当前tab数目是否大于屏幕宽度或父布局宽度 556 | * 557 | * @return 是否大于 558 | */ 559 | private boolean parentCanScroll() { 560 | int parentWidth = ((ViewGroup) getParent()).getMeasuredWidth(); 561 | if (isDeuceTabWidth) { 562 | return parentWidth == 0 ? mTabWidth * totalCount > screenWidth 563 | : mTabWidth * totalCount > parentWidth; 564 | } 565 | int totalWidth = tabLeftMargin + tabRightMargin; 566 | for (int i = 0; i < totalCount; i++) { 567 | totalWidth += tabLengthArray[i]; 568 | if ((parentWidth != 0 && totalWidth > parentWidth) || totalWidth >= screenWidth) { 569 | return true; 570 | } 571 | } 572 | return false; 573 | } 574 | 575 | /** 576 | * 设置外框宽度,默认为0px 577 | * 578 | * @param strokeWidth 背景边框宽度 579 | */ 580 | public void setBackgroundStrokeWidth(int strokeWidth) { 581 | this.strokeWidth = strokeWidth; 582 | setBackgroundShape(); 583 | } 584 | 585 | public ViewPager getViewPager() { 586 | return viewPager; 587 | } 588 | 589 | public YPXViewPager getYPXViewPager() { 590 | return ypxViewPager; 591 | } 592 | 593 | public int getDefaultHeight() { 594 | return defaultHeight; 595 | } 596 | 597 | /** 598 | * 设置指示器高度,默认50px 599 | * 600 | * @param defaultHeight 指示器高度 601 | */ 602 | public void setDefaultHeight(int defaultHeight) { 603 | this.defaultHeight = defaultHeight; 604 | refreshTabLayouts(); 605 | } 606 | 607 | public int getStrokeWidth() { 608 | return strokeWidth; 609 | } 610 | 611 | public String[] getTitles() { 612 | return titles; 613 | } 614 | 615 | /** 616 | * 设置指示器内容,默认tab1,tab2,tab3 617 | * 618 | * @param titles 设置标题数组 619 | */ 620 | public void setTitles(String[] titles) { 621 | if (titles != null && titles.length > 0) { 622 | this.titles = titles; 623 | totalCount = titles.length; 624 | tabLengthArray = new int[totalCount]; 625 | refreshTabLayouts(); 626 | setTabLayoutGravity(tabGravity); 627 | } 628 | } 629 | 630 | /** 631 | * 获取tab 632 | * 633 | * @param i 索引 634 | * @return 该索引对应的tab(textView) 635 | */ 636 | public TextView getTab(int i) { 637 | if (i < titles.length) { 638 | return (TextView) getChildAt(i); 639 | } else { 640 | return (TextView) getChildAt(titles.length - 1); 641 | } 642 | } 643 | 644 | /** 645 | * 重置tab颜色 646 | */ 647 | public void resetTabColor() { 648 | for (int i = 0; i < totalCount; i++) { 649 | getTab(i).setTextColor(tabTextColor); 650 | } 651 | } 652 | 653 | /** 654 | * 重置tab大小 655 | */ 656 | public void resetTabSize() { 657 | for (int i = 0; i < totalCount; i++) { 658 | getTab(i).setTextSize(tabTextSize); 659 | } 660 | } 661 | 662 | public int getTabTextColor() { 663 | return tabTextColor; 664 | } 665 | 666 | /** 667 | * 设置tab默认颜色,既未选中时颜色,默认为红色 668 | * 669 | * @param tabTextColor 文字颜色 670 | */ 671 | public void setTabTextColor(int tabTextColor) { 672 | this.tabTextColor = tabTextColor; 673 | for (int i = 0; i < totalCount; i++) { 674 | getTab(i).setTextColor(tabTextColor); 675 | } 676 | refreshCurrentTab(); 677 | } 678 | 679 | public int getmBackgroundColor() { 680 | return backgroundColor; 681 | } 682 | 683 | /** 684 | * 设置背景色,同时也是选中tab的文本颜色,默认为白色 685 | * 686 | * @param backgroundColor 背景色 687 | */ 688 | public void setmBackgroundColor(int backgroundColor) { 689 | this.backgroundColor = backgroundColor; 690 | setBackgroundShape(); 691 | } 692 | 693 | public int getBackgroundRadius() { 694 | return backgroundRadius; 695 | } 696 | 697 | /** 698 | * 设置背景圆角大小,默认为40px 699 | * 700 | * @param backgroundRadius 背景圆角大小 701 | */ 702 | public void setBackgroundRadius(int backgroundRadius) { 703 | this.backgroundRadius = backgroundRadius; 704 | setBackgroundShape(); 705 | } 706 | 707 | /** 708 | * 设置外框颜色,默认为白色 709 | * 710 | * @param backgroundLineColor 外框颜色 711 | */ 712 | public void setBackgroundLineColor(int backgroundLineColor) { 713 | this.backgroundLineColor = backgroundLineColor; 714 | setBackgroundShape(); 715 | } 716 | 717 | /** 718 | * 获取当前viewpager选中项 719 | * 720 | * @return 获取当前选中项 721 | */ 722 | public int getCurrentIndex() { 723 | return mCurrentIndex; 724 | } 725 | 726 | /** 727 | * 设置默认项 728 | * 729 | * @param mCurrentIndex 默认 730 | */ 731 | public void setCurrentIndex(final int mCurrentIndex) { 732 | this.mCurrentIndex = mCurrentIndex; 733 | if (ypxViewPager != null && ypxViewPager.getAdapter() != null) { 734 | ypxViewPager.setCurrentItem(mCurrentIndex, true); 735 | } 736 | 737 | if (viewPager != null && viewPager.getAdapter() != null) { 738 | viewPager.setCurrentItem(mCurrentIndex, true); 739 | } 740 | 741 | postDelayed(new Runnable() { 742 | @Override 743 | public void run() { 744 | refreshCurrentTab(); 745 | } 746 | }, 50); 747 | } 748 | 749 | public boolean isShowBackground() { 750 | return isShowBackground; 751 | } 752 | 753 | /** 754 | * 是否显示背景 755 | * 756 | * @param isShowBackground 是否显示背景 757 | */ 758 | public void setShowBackground(boolean isShowBackground) { 759 | this.isShowBackground = isShowBackground; 760 | setBackgroundShape(); 761 | } 762 | 763 | public boolean isShowIndicator() { 764 | return isShowIndicator; 765 | } 766 | 767 | /** 768 | * 是否显示指示器 769 | * 770 | * @param isShowIndicator 是否显示指示器 771 | */ 772 | public void setShowIndicator(boolean isShowIndicator) { 773 | this.isShowIndicator = isShowIndicator; 774 | invalidate(); 775 | } 776 | 777 | public int getIndicatorColor() { 778 | return indicatorColor; 779 | } 780 | 781 | /** 782 | * 设置指示器颜色,默认为红色 783 | * 784 | * @param indicatorColor 指示器颜色 785 | */ 786 | public void setIndicatorColor(int indicatorColor) { 787 | this.indicatorColor = indicatorColor; 788 | indicatorPaint.setColor(indicatorColor); 789 | invalidate(); 790 | } 791 | 792 | /** 793 | * 设置最大字体大小,默认为16 794 | * 795 | * @param maxTabTextSize 最大字体尺寸 796 | */ 797 | public void setTabMaxTextSize(int maxTabTextSize) { 798 | this.maxTabTextSize = maxTabTextSize; 799 | refreshTabLayouts(); 800 | refreshCurrentTab(); 801 | } 802 | 803 | 804 | public int getTabWidth() { 805 | return mTabWidth; 806 | } 807 | 808 | /** 809 | * 设置tab的宽度 810 | * 811 | * @param mTabWidth 强制设置每个tab的宽度 812 | */ 813 | public void setTabWidth(int mTabWidth) { 814 | if (mTabWidth < 0) { 815 | this.isSetTabWidth = false; 816 | refreshTabLayouts(); 817 | return; 818 | } 819 | this.mTabWidth = mTabWidth; 820 | this.isSetTabWidth = true; 821 | refreshTabLayouts(); 822 | } 823 | 824 | public int getMaxTabTextSize() { 825 | return maxTabTextSize; 826 | } 827 | 828 | /** 829 | * 是否设置tab字体变换效果 830 | * 831 | * @param isShowTabSizeChange 是否显示tab字体大小变换效果 832 | */ 833 | public void setShowTabSizeChange(boolean isShowTabSizeChange) { 834 | this.isShowTabSizeChange = isShowTabSizeChange; 835 | } 836 | 837 | public int getTabPressColor() { 838 | return tabPressColor; 839 | } 840 | 841 | /** 842 | * 设置tab选中颜色,默认为红色#ff0000 843 | * 844 | * @param tabPressColor tab选中的颜色 845 | */ 846 | public void setTabPressColor(int tabPressColor) { 847 | this.tabPressColor = tabPressColor; 848 | refreshCurrentTab(); 849 | } 850 | 851 | public int getTabTextSize() { 852 | return tabTextSize; 853 | } 854 | 855 | /** 856 | * 设置tab大小,默认大小为14 857 | * 858 | * @param tabTextSize 正常尺寸 859 | */ 860 | public void setTabTextSize(int tabTextSize) { 861 | this.tabTextSize = tabTextSize; 862 | resetTabSize(); 863 | } 864 | 865 | /** 866 | * 设置tab的边距,默认左右为10dp,上下无间距 867 | * 868 | * @param l 左 869 | * @param t 上 870 | * @param r 右 871 | * @param b 下 872 | */ 873 | public void setTabPadding(int l, int t, int r, int b) { 874 | this.tabPaddingLeft = l; 875 | this.tabPaddingRight = r; 876 | this.tabPaddingTop = t; 877 | this.tabPaddingBottom = b; 878 | refreshTabLayouts(); 879 | } 880 | 881 | /** 882 | * 设置指定tab的边距 883 | * 884 | * @param position 要设置的tab索引 885 | * @param l 左 886 | * @param t 上 887 | * @param r 右 888 | * @param b 下 889 | */ 890 | public void setTabPaddingWithPosition(int position, int l, int t, int r, int b) { 891 | getTab(position).setPadding(l, t, r, b); 892 | refreshTabLayouts(); 893 | } 894 | 895 | public boolean isDeuceTabWidth() { 896 | return isDeuceTabWidth; 897 | } 898 | 899 | /** 900 | * 是否平分tab的宽度,若false,则返回每个tab自适应的宽度,适合在多种数目下使用 901 | * 902 | * @param isDeuceTabWidth 是否平分 903 | */ 904 | public void setDeuceTabWidth(boolean isDeuceTabWidth) { 905 | this.isDeuceTabWidth = isDeuceTabWidth; 906 | refreshTabLayouts(); 907 | refreshCurrentTab(); 908 | } 909 | 910 | /** 911 | * 获取tab中最长的tab文本作为最小tab宽度 912 | * 913 | * @param arrStr tab文本数组 914 | * @return 获取最大的tab文本 915 | */ 916 | private String getMaxLengthString(String[] arrStr) { 917 | String max = arrStr[0]; 918 | for (int x = 1; x < arrStr.length; x++) { 919 | if (arrStr[x].length() > max.length()) 920 | max = arrStr[x]; 921 | } 922 | return max; 923 | } 924 | 925 | 926 | /** 927 | * 设置指示器样式,默认为下划线样式,可定制成网易样式 928 | * 929 | * @param creator 构造器 930 | */ 931 | public void setDrawIndicatorCreator(DrawIndicatorCreator creator) { 932 | this.creator = creator; 933 | } 934 | 935 | /** 936 | * 对外的ViewPager的回调接口的设置 937 | * 938 | * @param pageChangeListener 滑动接口 939 | */ 940 | public void setOnPageChangeListener(PageChangeListener pageChangeListener) { 941 | this.onPageChangeListener = pageChangeListener; 942 | } 943 | 944 | /** 945 | * 对外的设置tab点击回调 946 | * 947 | * @param tabClickListener tab点击回调 948 | */ 949 | public void setOnTabClickListener(TabClickListener tabClickListener) { 950 | this.tabClickListener = tabClickListener; 951 | } 952 | 953 | @Override 954 | public void onPageScrollStateChanged(int state) { 955 | if (state == ViewPager.SCROLL_STATE_IDLE) {//滑动停止,关闭点击 956 | isClick = false; 957 | } 958 | if (onPageChangeListener != null) { // 回调 959 | onPageChangeListener.onPageScrollStateChanged(state); 960 | } 961 | } 962 | 963 | @Override 964 | public void onPageScrolled(int position, float positionOffset, 965 | int positionOffsetPixels) { 966 | if (isClick || position + 1 >= totalCount) { 967 | return; 968 | } 969 | int transitX = getTransitXByPosition(position); 970 | int tabWidth = tabLengthArray[position]; 971 | 972 | if (isShowTabSizeChange) {// 判断是否变换 973 | setTabSizeChange(position, 1 - positionOffset); 974 | setTabSizeChange(position + 1, positionOffset); 975 | } 976 | setTabColorChange(position, 1 - positionOffset); 977 | setTabColorChange(position + 1, positionOffset); 978 | 979 | mTransitX = (int) (tabWidth * positionOffset + transitX); 980 | mTabWidth = (int) (tabWidth + (tabLengthArray[position + 1] - tabWidth) * positionOffset); 981 | invalidate(); 982 | 983 | if (positionOffset != 0.0f) { 984 | int centerX = (mTransitX - (screenWidth - mTabWidth) / 2) + tabLeftMargin; 985 | parentScrollTo(centerX, 0); 986 | } 987 | 988 | if (onPageChangeListener != null) { // 回调 989 | onPageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels); 990 | } 991 | 992 | } 993 | 994 | @Override 995 | public void onPageSelected(int arg0) { 996 | mCurrentIndex = arg0; 997 | if (onPageChangeListener != null) { 998 | onPageChangeListener.onPageSelected(arg0); 999 | } 1000 | } 1001 | 1002 | /** 1003 | * 获得屏幕宽度 1004 | * 1005 | * @return 屏幕宽度 1006 | */ 1007 | public int getScreenWidth() { 1008 | WindowManager wm = (WindowManager) getContext() 1009 | .getSystemService(Context.WINDOW_SERVICE); 1010 | DisplayMetrics outMetrics = new DisplayMetrics(); 1011 | wm.getDefaultDisplay().getMetrics(outMetrics); 1012 | return outMetrics.widthPixels; 1013 | } 1014 | 1015 | 1016 | /** 1017 | * 下划线指示器 1018 | * 1019 | * @param canvas 画布 1020 | * @param left 左边距 1021 | * @param top 上边距 1022 | * @param right 右边距 1023 | * @param bottom 下边距 1024 | * @param paint 画笔 1025 | */ 1026 | public void drawUnderLineIndicatorWithTransitX(Canvas canvas, int left, 1027 | int top, int right, int bottom, Paint paint) { 1028 | RectF oval = new RectF(left, bottom - dp(3), right, bottom); 1029 | canvas.drawRect(oval, paint); 1030 | } 1031 | 1032 | 1033 | public int dp(int dp) { 1034 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1035 | dp, this.getResources().getDisplayMetrics()); 1036 | } 1037 | 1038 | /** 1039 | * 指示器实现者 1040 | * 1041 | * @author yangpeixing 1042 | */ 1043 | public interface DrawIndicatorCreator { 1044 | /** 1045 | * 默认为圆角矩形指示器,用户可继承重写自定义指示器样式 1046 | * 1047 | * @param canvas 画布 1048 | * @param left tab左边距离原点的位置 1049 | * @param top 整个tab的位置 1050 | * @param right tab距离顶端的位置 1051 | * @param bottom 整个tab的高度,既控件高度 1052 | * @param paint 指示器画笔 1053 | * @param raduis 外围圆角半径 1054 | */ 1055 | void drawIndicator(Canvas canvas, int left, int top, int right, 1056 | int bottom, Paint paint, int raduis); 1057 | } 1058 | 1059 | /** 1060 | * 对外的ViewPager的回调接口 1061 | * 1062 | * @author yangpeixing 1063 | */ 1064 | public interface PageChangeListener { 1065 | void onPageScrolled(int position, float positionOffset, 1066 | int positionOffsetPixels); 1067 | 1068 | void onPageSelected(int position); 1069 | 1070 | void onPageScrollStateChanged(int state); 1071 | } 1072 | 1073 | 1074 | /** 1075 | * 对外的ViewPager的回调接口 1076 | * 1077 | * @author yangpeixing 1078 | */ 1079 | public interface TabClickListener { 1080 | void onClick(TextView tab, int position); 1081 | } 1082 | 1083 | } 1084 | -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/app/src/main/java/com/ypx/jiehunle/ypx_bezierqqrefreshdemo/adapters/ListViewAdapter.java: -------------------------------------------------------------------------------- 1 | package com.ypx.jiehunle.ypx_bezierqqrefreshdemo.adapters; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | import android.widget.TextView; 9 | import android.widget.Toast; 10 | 11 | import com.ypx.jiehunle.ypx_bezierqqrefreshdemo.R; 12 | 13 | /** 14 | * Created by yangpeixing on 17/1/17. 15 | */ 16 | public class ListViewAdapter extends BaseAdapter { 17 | Context context; 18 | public ListViewAdapter(Context context){ 19 | this.context=context; 20 | } 21 | 22 | @Override 23 | public int getCount() { 24 | return 5; 25 | } 26 | 27 | @Override 28 | public Object getItem(int i) { 29 | return null; 30 | } 31 | 32 | @Override 33 | public long getItemId(int i) { 34 | return i; 35 | } 36 | 37 | @Override 38 | public View getView(int i, View view, ViewGroup viewGroup) { 39 | final ViewHolder holder; 40 | if(view==null) { 41 | holder = new ViewHolder(); 42 | view=LayoutInflater.from(context).inflate(R.layout.item,null); 43 | holder.tv= (TextView) view.findViewById(R.id.tv); 44 | view.setTag(holder); 45 | }else { 46 | holder= (ViewHolder) view.getTag(); 47 | } 48 | holder.tv.setText("第" + i + "个文本"); 49 | holder.tv.setOnClickListener(new View.OnClickListener() { 50 | @Override 51 | public void onClick(View view) { 52 | Toast.makeText(context,holder.tv.getText(),0).show(); 53 | } 54 | }); 55 | return view; 56 | } 57 | } 58 | 59 | class ViewHolder{ 60 | TextView tv; 61 | } 62 | -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/app/src/main/java/com/ypx/jiehunle/ypx_bezierqqrefreshdemo/adapters/RecyclerViewAdapter.java: -------------------------------------------------------------------------------- 1 | package com.ypx.jiehunle.ypx_bezierqqrefreshdemo.adapters; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | import android.widget.Toast; 10 | 11 | import com.ypx.jiehunle.ypx_bezierqqrefreshdemo.R; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | * Created by jiehunle on 17/1/17. 17 | */ 18 | public class RecyclerViewAdapter extends RecyclerView.Adapter { 19 | private Context context; 20 | private List mList; 21 | 22 | public RecyclerViewAdapter(Context context, List mList) { 23 | this.context = context; 24 | this.mList = mList; 25 | 26 | } 27 | 28 | @Override 29 | public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 30 | MyViewHolder holder = new MyViewHolder(LayoutInflater.from( 31 | context).inflate(R.layout.item, parent, 32 | false)); 33 | return holder; 34 | } 35 | 36 | @Override 37 | public void onBindViewHolder(final MyViewHolder holder, int pos) { 38 | holder.tv.setText(String.format("这是第%s个文本", mList.get(pos))); 39 | holder.tv.setOnClickListener(new View.OnClickListener() { 40 | @Override 41 | public void onClick(View view) { 42 | Toast.makeText(context, holder.tv.getText(), Toast.LENGTH_SHORT).show(); 43 | } 44 | }); 45 | } 46 | 47 | @Override 48 | public int getItemCount() { 49 | return mList.size(); 50 | } 51 | 52 | class MyViewHolder extends RecyclerView.ViewHolder { 53 | 54 | TextView tv; 55 | 56 | public MyViewHolder(View view) { 57 | super(view); 58 | tv = (TextView) view.findViewById(R.id.tv); 59 | 60 | 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/app/src/main/java/com/ypx/jiehunle/ypx_bezierqqrefreshdemo/fragments/GridViewFragment.java: -------------------------------------------------------------------------------- 1 | package com.ypx.jiehunle.ypx_bezierqqrefreshdemo.fragments; 2 | 3 | import android.os.Bundle; 4 | import android.os.Handler; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.GridView; 11 | 12 | import com.ypx.jiehunle.ypx_bezierqqrefreshdemo.adapters.ListViewAdapter; 13 | import com.ypx.jiehunle.ypx_bezierqqrefreshdemo.R; 14 | import com.ypx.refreshlayout.simple.qq.YPXQQRefreshView; 15 | 16 | /** 17 | * 作者:yangpeixing on 17/1/18 11:14 18 | * 博客主页:http://blog.csdn.net/qq_16674697?viewmode=list 19 | */ 20 | public class GridViewFragment extends Fragment{ 21 | View view; 22 | YPXQQRefreshView refreshableView; 23 | GridView gridView; 24 | ListViewAdapter adapter; 25 | final int SUCCESS = 1; 26 | final int FAILED = 0; 27 | 28 | Handler handler = new Handler() { 29 | public void handleMessage(android.os.Message msg) { 30 | switch (msg.what) { 31 | case SUCCESS: 32 | refreshableView.finishRefresh(true); 33 | break; 34 | case FAILED: 35 | refreshableView.finishRefresh(false); 36 | break; 37 | default: 38 | break; 39 | } 40 | }; 41 | }; 42 | @Nullable 43 | @Override 44 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 45 | view=LayoutInflater.from(getActivity()).inflate(R.layout.fragment_gridview,null); 46 | initView(); 47 | initData(); 48 | return view; 49 | } 50 | 51 | private void initView() { 52 | refreshableView = (YPXQQRefreshView) view.findViewById(R.id.refreshableView1); 53 | gridView= (GridView) view.findViewById(R.id.gridView1); 54 | adapter=new ListViewAdapter(getActivity()); 55 | gridView.setAdapter(adapter); 56 | } 57 | 58 | private void initData() { 59 | refreshableView.setRefreshListener(new YPXQQRefreshView.RefreshListener() { 60 | 61 | @Override 62 | public void onRefresh() { 63 | handler.postDelayed(new Runnable() { 64 | 65 | @Override 66 | public void run() { 67 | handler.sendEmptyMessage(FAILED); 68 | 69 | } 70 | }, 500); 71 | } 72 | }); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/app/src/main/java/com/ypx/jiehunle/ypx_bezierqqrefreshdemo/fragments/ListViewFragment.java: -------------------------------------------------------------------------------- 1 | package com.ypx.jiehunle.ypx_bezierqqrefreshdemo.fragments; 2 | 3 | import android.os.Bundle; 4 | import android.os.Handler; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.ListView; 11 | 12 | import com.ypx.jiehunle.ypx_bezierqqrefreshdemo.adapters.ListViewAdapter; 13 | import com.ypx.jiehunle.ypx_bezierqqrefreshdemo.R; 14 | import com.ypx.refreshlayout.simple.qq.YPXQQRefreshView; 15 | 16 | /** 17 | * ListView 18 | * Created by yangpeixing on 17/1/17. 19 | */ 20 | public class ListViewFragment extends Fragment { 21 | View view; 22 | YPXQQRefreshView refreshableView; 23 | ListView listView; 24 | ListViewAdapter adapter; 25 | final int SUCCESS = 1; 26 | final int FAILED = 0; 27 | 28 | Handler handler = new Handler() { 29 | public void handleMessage(android.os.Message msg) { 30 | switch (msg.what) { 31 | case SUCCESS: 32 | refreshableView.finishRefresh(true); 33 | break; 34 | case FAILED: 35 | refreshableView.finishRefresh(false); 36 | break; 37 | default: 38 | break; 39 | } 40 | }; 41 | }; 42 | @Nullable 43 | @Override 44 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 45 | view=LayoutInflater.from(getActivity()).inflate(R.layout.fragment_listview,null); 46 | initView(); 47 | initData(); 48 | return view; 49 | } 50 | 51 | private void initView() { 52 | refreshableView = (YPXQQRefreshView) view.findViewById(R.id.refreshableView1); 53 | listView= (ListView) view.findViewById(R.id.listView1); 54 | adapter=new ListViewAdapter(getActivity()); 55 | listView.setAdapter(adapter); 56 | //设置是否可以刷新,默认可以刷新 57 | refreshableView.setRefreshEnabled(true); 58 | //设置刷新颜色,默认颜色值#999999 59 | /* refreshableView.setRefreshColor(Color.parseColor("#26B8F2")); 60 | //设置刷新图标,默认刷新图标 61 | refreshableView.setRefreshIcon(R.mipmap.ic_launcher); 62 | //设置刷新球最大拉伸距离,默认为刷新头部高度 63 | refreshableView.setRefreshMaxHeight(refreshableView.dp(150)); 64 | //设置刷新球半径,默认15dp 65 | refreshableView.setTopCircleRadius(refreshableView.dp(30)); 66 | //设置刷新球圆心X值,默认屏宽一半 67 | refreshableView.setTopCircleX(refreshableView.dp(50)); 68 | //设置刷新球圆心Y值,默认30dp 69 | refreshableView.setTopCircleY(refreshableView.dp(30)); */ 70 | } 71 | 72 | private void initData() { 73 | refreshableView.setRefreshListener(new YPXQQRefreshView.RefreshListener() { 74 | 75 | @Override 76 | public void onRefresh() { 77 | handler.postDelayed(new Runnable() { 78 | 79 | @Override 80 | public void run() { 81 | handler.sendEmptyMessage(SUCCESS); 82 | 83 | } 84 | }, 500); 85 | } 86 | }); 87 | 88 | } 89 | 90 | 91 | } 92 | -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/app/src/main/java/com/ypx/jiehunle/ypx_bezierqqrefreshdemo/fragments/NormalRefreshFragment.java: -------------------------------------------------------------------------------- 1 | package com.ypx.jiehunle.ypx_bezierqqrefreshdemo.fragments; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.graphics.Color; 5 | import android.os.Bundle; 6 | import android.os.Handler; 7 | import android.support.annotation.Nullable; 8 | import android.support.v4.app.Fragment; 9 | import android.util.TypedValue; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.widget.LinearLayout; 14 | import android.widget.TextView; 15 | import android.widget.Toast; 16 | 17 | import com.ypx.jiehunle.ypx_bezierqqrefreshdemo.R; 18 | import com.ypx.refreshlayout.simple.YPXNormalRefreshView; 19 | 20 | /** 21 | * 作者:yangpeixing on 17/1/19 11:14 22 | * 博客主页:http://blog.csdn.net/qq_16674697?viewmode=list 23 | */ 24 | public class NormalRefreshFragment extends Fragment { 25 | YPXNormalRefreshView refreshableView; 26 | LinearLayout layout; 27 | final int SUCCESS = 1; 28 | final int FAILED = 0; 29 | View view; 30 | @SuppressLint("HandlerLeak") 31 | Handler handler = new Handler() { 32 | public void handleMessage(android.os.Message msg) { 33 | switch (msg.what) { 34 | case SUCCESS: 35 | refreshableView.finishRefresh(true); 36 | TextView textView = new TextView(getActivity()); 37 | textView.setTextColor(Color.parseColor("#666666")); 38 | textView.setTextSize(18); 39 | textView.setText("这是刷新的文本"); 40 | textView.setPadding(dp(15),dp(10),dp(15),dp(10)); 41 | layout.addView(textView,0); 42 | break; 43 | case FAILED: 44 | refreshableView.finishRefresh(false); 45 | break; 46 | default: 47 | break; 48 | } 49 | }; 50 | }; 51 | 52 | @Nullable 53 | @Override 54 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 55 | view= LayoutInflater.from(getContext()).inflate(R.layout.fragment_normalrefresh,null); 56 | initView(); 57 | initData(); 58 | return view; 59 | } 60 | 61 | private void initView() { 62 | refreshableView = (YPXNormalRefreshView) view.findViewById(R.id.refreshableView1); 63 | layout = (LinearLayout) view.findViewById(R.id.ll_layout); 64 | } 65 | 66 | private void initData() { 67 | layout.removeAllViews(); 68 | for (int i = 0; i < 50; i++) { 69 | final TextView textView = new TextView(getActivity()); 70 | textView.setTextColor(Color.parseColor("#666666")); 71 | textView.setTextSize(18); 72 | textView.setPadding(dp(15),dp(10),dp(15),dp(10)); 73 | textView.setText("这是第" + i + "个文本"); 74 | textView.setOnClickListener(new View.OnClickListener() { 75 | @Override 76 | public void onClick(View view) { 77 | Toast.makeText(getActivity(),textView.getText(),Toast.LENGTH_SHORT).show(); 78 | } 79 | }); 80 | layout.addView(textView); 81 | } 82 | refreshableView.setRefreshListener(new YPXNormalRefreshView.RefreshListener() { 83 | 84 | @Override 85 | public void onRefresh() { 86 | handler.postDelayed(new Runnable() { 87 | 88 | @Override 89 | public void run() { 90 | handler.sendEmptyMessage(SUCCESS); 91 | 92 | } 93 | }, 500); 94 | } 95 | }); 96 | } 97 | 98 | public int dp(int dp) { 99 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100 | dp,getResources().getDisplayMetrics()); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/app/src/main/java/com/ypx/jiehunle/ypx_bezierqqrefreshdemo/fragments/RecyclerViewFragment.java: -------------------------------------------------------------------------------- 1 | package com.ypx.jiehunle.ypx_bezierqqrefreshdemo.fragments; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.os.Bundle; 5 | import android.os.Handler; 6 | import android.support.annotation.Nullable; 7 | import android.support.v4.app.Fragment; 8 | import android.support.v7.widget.LinearLayoutManager; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.util.Log; 11 | import android.util.TypedValue; 12 | import android.view.LayoutInflater; 13 | import android.view.View; 14 | import android.view.ViewGroup; 15 | import android.widget.TextView; 16 | 17 | import com.ypx.jiehunle.ypx_bezierqqrefreshdemo.R; 18 | import com.ypx.jiehunle.ypx_bezierqqrefreshdemo.adapters.RecyclerViewAdapter; 19 | import com.ypx.refreshlayout.simple.qq.YPXQQRefreshView; 20 | 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | 24 | /** 25 | * RecyclerView 26 | * Created by yangpeixing on 17/1/17. 27 | */ 28 | public class RecyclerViewFragment extends Fragment { 29 | View view; 30 | RecyclerView recyclerView; 31 | YPXQQRefreshView refreshableView; 32 | TextView mTvLoadMore; 33 | RecyclerViewAdapter adapter; 34 | final int SUCCESS = 1; 35 | final int FAILED = 0; 36 | 37 | List list = new ArrayList<>(); 38 | int page = 1; 39 | 40 | @SuppressLint("HandlerLeak") 41 | Handler handler = new Handler() { 42 | public void handleMessage(android.os.Message msg) { 43 | switch (msg.what) { 44 | case SUCCESS: 45 | adapter.notifyDataSetChanged(); 46 | refreshableView.finishRefresh(true); 47 | mTvLoadMore.setVisibility(View.INVISIBLE); 48 | break; 49 | case FAILED: 50 | adapter.notifyDataSetChanged(); 51 | refreshableView.finishRefresh(false); 52 | mTvLoadMore.setVisibility(View.INVISIBLE); 53 | break; 54 | default: 55 | break; 56 | } 57 | } 58 | 59 | ; 60 | }; 61 | 62 | @Nullable 63 | @Override 64 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 65 | view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_recyclerview, null); 66 | initView(); 67 | initData(); 68 | return view; 69 | } 70 | 71 | private void initView() { 72 | refreshableView = (YPXQQRefreshView) view.findViewById(R.id.refreshableView1); 73 | recyclerView = (RecyclerView) view.findViewById(R.id.recyclerview1); 74 | adapter = new RecyclerViewAdapter(getActivity(), list); 75 | recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); 76 | recyclerView.setAdapter(adapter); 77 | mTvLoadMore = (TextView) view.findViewById(R.id.mTvLoadMore); 78 | refreshableView.setRefreshEnabled(true); 79 | recyclerView.setClipToPadding(false); 80 | recyclerView.setPadding(recyclerView.getPaddingLeft(), recyclerView.getPaddingTop(), recyclerView.getPaddingRight(), 81 | recyclerView.getPaddingBottom() + dp(40)); 82 | recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { 83 | @Override 84 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 85 | super.onScrolled(recyclerView, dx, dy); 86 | if (!recyclerView.canScrollVertically(1)) { 87 | // mTvLoadMore.setTranslationY(-mTvLoadMore.getHeight()); 88 | mTvLoadMore.setVisibility(View.VISIBLE); 89 | if (page == 5) { 90 | mTvLoadMore.setText("没有更多数据了!"); 91 | } else { 92 | mTvLoadMore.setText("正在加载..."); 93 | loadMore(); 94 | } 95 | } else { 96 | Log.e("onScrolled", "onScrolled: " + getScrollY()); 97 | if (dy < 0 && mTvLoadMore.getVisibility() == View.VISIBLE) { 98 | mTvLoadMore.setTranslationY(dy); 99 | if (dy > dp(40)) { 100 | mTvLoadMore.setVisibility(View.INVISIBLE); 101 | } 102 | } 103 | //mTvLoadMore.setVisibility(View.INVISIBLE); 104 | } 105 | 106 | 107 | } 108 | }); 109 | 110 | refreshData(); 111 | } 112 | 113 | private int getScrollY() { 114 | LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); 115 | View view = layoutManager.findViewByPosition(list.size() - 1); 116 | if (view != null) { 117 | return view.getBottom(); 118 | } 119 | return layoutManager.findViewByPosition(layoutManager.findLastVisibleItemPosition()).getBottom(); 120 | } 121 | 122 | private void initData() { 123 | refreshableView.setRefreshListener(new YPXQQRefreshView.RefreshListener() { 124 | 125 | @Override 126 | public void onRefresh() { 127 | refreshData(); 128 | } 129 | }); 130 | } 131 | 132 | private void refreshData() { 133 | list.clear(); 134 | page = 1; 135 | for (int i = 0; i < 50; i++) { 136 | list.add(i + ""); 137 | } 138 | handler.postDelayed(new Runnable() { 139 | 140 | @Override 141 | public void run() { 142 | handler.sendEmptyMessage(SUCCESS); 143 | 144 | } 145 | }, 500); 146 | } 147 | 148 | private void loadMore() { 149 | int start = list.size(); 150 | for (int i = 0; i < 20; i++) { 151 | list.add(start + i + ""); 152 | } 153 | handler.postDelayed(new Runnable() { 154 | 155 | @Override 156 | public void run() { 157 | handler.sendEmptyMessage(SUCCESS); 158 | 159 | } 160 | }, 1000); 161 | page++; 162 | } 163 | 164 | public int dp(int dp) { 165 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 166 | dp, getResources().getDisplayMetrics()); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/app/src/main/java/com/ypx/jiehunle/ypx_bezierqqrefreshdemo/fragments/ScrollViewFragment.java: -------------------------------------------------------------------------------- 1 | package com.ypx.jiehunle.ypx_bezierqqrefreshdemo.fragments; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.graphics.Color; 5 | import android.os.Bundle; 6 | import android.os.Handler; 7 | import android.support.annotation.Nullable; 8 | import android.support.v4.app.Fragment; 9 | import android.util.TypedValue; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.widget.LinearLayout; 14 | import android.widget.TextView; 15 | import android.widget.Toast; 16 | 17 | import com.ypx.jiehunle.ypx_bezierqqrefreshdemo.R; 18 | import com.ypx.refreshlayout.simple.qq.YPXQQRefreshView; 19 | 20 | /** 21 | * ScrollView 22 | * Created by yangpeixing on 17/1/17. 23 | */ 24 | public class ScrollViewFragment extends Fragment{ 25 | YPXQQRefreshView refreshableView; 26 | LinearLayout layout; 27 | final int SUCCESS = 1; 28 | final int FAILED = 0; 29 | View view; 30 | @SuppressLint("HandlerLeak") 31 | Handler handler = new Handler() { 32 | public void handleMessage(android.os.Message msg) { 33 | switch (msg.what) { 34 | case SUCCESS: 35 | refreshableView.finishRefresh(true); 36 | TextView textView = new TextView(getActivity()); 37 | textView.setTextColor(Color.parseColor("#666666")); 38 | textView.setTextSize(18); 39 | textView.setText("这是刷新的文本"); 40 | textView.setPadding(dp(15),dp(10),dp(15),dp(10)); 41 | layout.addView(textView,0); 42 | break; 43 | case FAILED: 44 | refreshableView.finishRefresh(false); 45 | break; 46 | default: 47 | break; 48 | } 49 | }; 50 | }; 51 | 52 | @Nullable 53 | @Override 54 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 55 | view= LayoutInflater.from(getActivity()).inflate(R.layout.fragment_scrollview,null); 56 | initView(); 57 | initData(); 58 | return view; 59 | } 60 | 61 | private void initView() { 62 | refreshableView = (YPXQQRefreshView) view.findViewById(R.id.refreshableView1); 63 | layout = (LinearLayout) view.findViewById(R.id.ll_layout); 64 | //设置是否可以刷新,默认可以刷新 65 | refreshableView.setRefreshEnabled(true); 66 | //设置刷新头的高度,此高度会决定小球的默认半径和坐标 67 | /* refreshableView.setRefreshViewHeight(refreshableView.dp(120)); 68 | //设置刷新颜色,默认颜色值#999999 69 | refreshableView.setRefreshColor(Color.parseColor("#26B8F2")); 70 | //设置刷新图标,默认刷新图标 71 | refreshableView.setRefreshIcon(R.mipmap.ic_launcher); 72 | //设置刷新球最大拉伸距离,默认为刷新头部高度 73 | refreshableView.setRefreshMaxHeight(refreshableView.dp(150)); 74 | //设置刷新球半径,默认15dp 75 | refreshableView.setTopCircleRadius(refreshableView.dp(30)); 76 | //设置刷新球圆心X值,默认屏宽一半 77 | refreshableView.setTopCircleX(refreshableView.dp(50)); 78 | //设置刷新球圆心Y值,默认30dp 79 | refreshableView.setTopCircleY(refreshableView.dp(30)); */ 80 | } 81 | 82 | private void initData() { 83 | layout.removeAllViews(); 84 | for (int i = 0; i < 50; i++) { 85 | final TextView textView = new TextView(getActivity()); 86 | textView.setTextColor(Color.parseColor("#666666")); 87 | textView.setTextSize(18); 88 | textView.setPadding(dp(15),dp(10),dp(15),dp(10)); 89 | textView.setText("这是第" + i + "个文本"); 90 | textView.setOnClickListener(new View.OnClickListener() { 91 | @Override 92 | public void onClick(View view) { 93 | Toast.makeText(getActivity(),textView.getText(),Toast.LENGTH_SHORT).show(); 94 | } 95 | }); 96 | layout.addView(textView); 97 | } 98 | refreshableView.setRefreshListener(new YPXQQRefreshView.RefreshListener() { 99 | 100 | @Override 101 | public void onRefresh() { 102 | handler.postDelayed(new Runnable() { 103 | 104 | @Override 105 | public void run() { 106 | handler.sendEmptyMessage(SUCCESS); 107 | 108 | } 109 | }, 500); 110 | } 111 | }); 112 | } 113 | 114 | public int dp(int dp) { 115 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 116 | dp,getResources().getDisplayMetrics()); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/app/src/main/java/com/ypx/jiehunle/ypx_bezierqqrefreshdemo/fragments/WebViewFragment.java: -------------------------------------------------------------------------------- 1 | package com.ypx.jiehunle.ypx_bezierqqrefreshdemo.fragments; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.os.Bundle; 5 | import android.os.Handler; 6 | import android.support.annotation.Nullable; 7 | import android.support.v4.app.Fragment; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.webkit.WebView; 12 | import android.webkit.WebViewClient; 13 | 14 | import com.ypx.jiehunle.ypx_bezierqqrefreshdemo.R; 15 | import com.ypx.refreshlayout.simple.qq.YPXQQRefreshView; 16 | 17 | /** 18 | * WebView 19 | * Created by yangpeixing on 17/1/17. 20 | */ 21 | public class WebViewFragment extends Fragment{ 22 | View view; 23 | WebView webView; 24 | YPXQQRefreshView refreshableView; 25 | final int SUCCESS = 1; 26 | final int FAILED = 0; 27 | @SuppressLint("HandlerLeak") 28 | Handler handler = new Handler() { 29 | public void handleMessage(android.os.Message msg) { 30 | switch (msg.what) { 31 | case SUCCESS: 32 | refreshableView.finishRefresh(true); 33 | break; 34 | case FAILED: 35 | refreshableView.finishRefresh(false); 36 | break; 37 | default: 38 | break; 39 | } 40 | }; 41 | }; 42 | @Nullable 43 | @Override 44 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 45 | view=LayoutInflater.from(getActivity()).inflate(R.layout.fragment_webview,null); 46 | initView(); 47 | initData(); 48 | return view; 49 | } 50 | 51 | private void initView() { 52 | refreshableView= (YPXQQRefreshView) view.findViewById(R.id.refreshableView1); 53 | webView= (WebView) view.findViewById(R.id.webView1); 54 | webView.loadUrl("http://blog.csdn.net/qq_16674697/article/details/54341455"); 55 | //覆盖WebView默认使用第三方或系统默认浏览器打开网页的行为,使网页用WebView打开 56 | webView.setWebViewClient(new WebViewClient(){ 57 | @Override 58 | public boolean shouldOverrideUrlLoading(WebView view, String url) { 59 | //返回值是true的时候控制去WebView打开,为false调用系统浏览器或第三方浏览器 60 | view.loadUrl(url); 61 | return true; 62 | } 63 | }); 64 | } 65 | 66 | private void initData() { 67 | refreshableView.setRefreshListener(new YPXQQRefreshView.RefreshListener() { 68 | 69 | @Override 70 | public void onRefresh() { 71 | handler.postDelayed(new Runnable() { 72 | 73 | @Override 74 | public void run() { 75 | handler.sendEmptyMessage(SUCCESS); 76 | 77 | } 78 | }, 500); 79 | } 80 | }); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /YPX_RefreshLayout_demo/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 14 | 15 | 19 | 20 | 21 | 26 | 27 | 33 | 34 | 35 | 36 | 42 | 43 |