├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml └── runConfigurations.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── czm │ │ └── main │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── czm │ │ │ ├── main │ │ │ ├── MainActivity.java │ │ │ └── RecyclerViewListAdapter.java │ │ │ ├── model │ │ │ └── TabItem.java │ │ │ ├── tablayout │ │ │ ├── OnTabSelectListener.java │ │ │ └── XCTabLayout.java │ │ │ ├── uphidescrollview │ │ │ ├── BaseListFragment.java │ │ │ ├── ListFragment.java │ │ │ ├── ObservableScrollView.java │ │ │ ├── ScrollViewPager.java │ │ │ ├── ScrollViewPagerAdapter.java │ │ │ ├── ViewUtil.java │ │ │ └── XCUpHideScrollView.java │ │ │ └── utils │ │ │ └── PhoneUtil.java │ └── res │ │ ├── drawable │ │ ├── bg_msg_red_dot.9.png │ │ └── icon_back_orange.png │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── fragment_viewpager_list.xml │ │ ├── layout_list_item.xml │ │ └── layout_tab.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── czm │ └── main │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots └── 01.gif └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XCUpHideScrollView 2 | A UpHideScrollView which is some listviews inner scrollview 3 | 仿微博发现页面ScrollView 内嵌ListView 到顶吸顶 滚动ListView效果 4 | 5 | ## 效果演示图: 6 | 7 | ![iamge](https://raw.githubusercontent.com/jczmdeveloper/XCUpHideScrollView/master/screenshots/01.gif) 8 | 9 | 10 | 如何使用项目: 11 | 首先打开 Project root 的 build.gradle,在 repositories 节点添加上 12 | 13 | maven { url "https://jitpack.io" } 14 | 15 | 16 | ,之后打开想依赖这个 library 的模块,比如这里我们是 app 这个 module,在 dependencies 节点添加上 17 | 18 | 19 | 20 | compile 'com.github.jczmdeveloper:XCUpHideScrollView:v1.0', 21 | 22 | 23 | Sync 一下 Gradle,这样就可以了 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.2" 6 | defaultConfig { 7 | applicationId "com.czm.main" 8 | minSdkVersion 14 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:25.2.0' 28 | compile 'com.android.support:recyclerview-v7:25.2.0' 29 | compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha9' 30 | testCompile 'junit:junit:4.12' 31 | } 32 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Java\AndroidStudio\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 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/czm/main/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.czm.main; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.czm.main", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/czm/main/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.czm.main; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.FragmentActivity; 5 | import android.support.v4.view.ViewPager; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.view.View; 8 | 9 | import com.czm.model.TabItem; 10 | import com.czm.tablayout.XCTabLayout; 11 | import com.czm.uphidescrollview.ObservableScrollView; 12 | import com.czm.uphidescrollview.ScrollViewPager; 13 | import com.czm.uphidescrollview.ScrollViewPagerAdapter; 14 | import com.czm.uphidescrollview.XCUpHideScrollView; 15 | 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | 19 | public class MainActivity extends FragmentActivity { 20 | 21 | private View mRootView; 22 | private View mHeaderView; 23 | private ScrollViewPager mScrollViewPager; 24 | private ScrollViewPagerAdapter mScrollViewPagerAdapter; 25 | private XCTabLayout mTabLayout; 26 | private XCUpHideScrollView mScrollView; 27 | private int mCurPos = 0; 28 | private View mScrollBackView; 29 | 30 | 31 | private boolean mIsCeiling = false;//是否吸顶 32 | 33 | private String[] mTabArr = new String[]{ 34 | "热点","推荐","财经","娱乐","NBA" 35 | }; 36 | 37 | @Override 38 | protected void onCreate(Bundle savedInstanceState) { 39 | super.onCreate(savedInstanceState); 40 | setContentView(R.layout.activity_main); 41 | mRootView = findViewById(R.id.sv_root); 42 | mScrollView = (XCUpHideScrollView) mRootView.findViewById(R.id.sv_root); 43 | mScrollBackView = mRootView.findViewById(R.id.btn_back); 44 | mHeaderView = mRootView.findViewById(R.id.lay_header); 45 | mScrollView.setHeaderView(mHeaderView); 46 | mScrollView.setContentView(mRootView.findViewById(R.id.lay_content)); 47 | 48 | mTabLayout = (XCTabLayout) mRootView.findViewById(R.id.tab_layout_vp); 49 | 50 | mScrollViewPager = (ScrollViewPager) mRootView.findViewById(R.id.vp_list); 51 | 52 | 53 | setListener(); 54 | this.runOnUiThread(new Runnable() { 55 | @Override 56 | public void run() { 57 | List list = new ArrayList(); 58 | for(int i = 0; i < mTabArr.length;i ++){ 59 | TabItem item = new TabItem(); 60 | item.setItemName(mTabArr[i]); 61 | list.add(item); 62 | } 63 | setTabView(list); 64 | } 65 | }); 66 | } 67 | private void setListener() { 68 | mScrollView.setOnScrollListener(new ObservableScrollView.OnScrollChangedListener() { 69 | @Override 70 | public void onScrollChanged(int x, int y, int oldX, int oldY) { 71 | if(mHeaderView.getMeasuredHeight() >0 72 | && y >= mHeaderView.getMeasuredHeight()){ 73 | if(!mIsCeiling){ 74 | mScrollBackView.setVisibility(View.VISIBLE); 75 | mIsCeiling = true; 76 | } 77 | 78 | }else{ 79 | if(mIsCeiling){ 80 | mScrollBackView.setVisibility(View.GONE); 81 | mIsCeiling = false; 82 | } 83 | } 84 | } 85 | }); 86 | mScrollBackView.setOnClickListener(new View.OnClickListener() { 87 | @Override 88 | public void onClick(View v) { 89 | mScrollBackView.setVisibility(View.GONE); 90 | mIsCeiling = false; 91 | mScrollView.smoothScrollToSlow(0,0,800); 92 | ((RecyclerView) mScrollViewPagerAdapter.getSlidableView(mCurPos)).scrollToPosition(0); 93 | } 94 | }); 95 | 96 | mScrollViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { 97 | @Override 98 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 99 | 100 | } 101 | 102 | @Override 103 | public void onPageSelected(int position) { 104 | mCurPos = position; 105 | mScrollView.setContentInnerScrollableView(mScrollViewPagerAdapter.getSlidableView(position)); 106 | } 107 | 108 | @Override 109 | public void onPageScrollStateChanged(int state) { 110 | 111 | } 112 | }); 113 | } 114 | public void setTabView(List data) { 115 | if(mScrollViewPagerAdapter == null){ 116 | mScrollViewPagerAdapter = new ScrollViewPagerAdapter(this.getSupportFragmentManager()); 117 | mScrollViewPagerAdapter.setTabLayoutData(data); 118 | mScrollViewPager.setAdapter(mScrollViewPagerAdapter); 119 | mTabLayout.setViewPager(mScrollViewPager); 120 | mScrollViewPagerAdapter.notifyDataSetChanged(); 121 | } 122 | 123 | mScrollViewPager.postDelayed(new Runnable() { 124 | @Override 125 | public void run() { 126 | mScrollView.setContentInnerScrollableView(mScrollViewPagerAdapter.getSlidableView(0)); 127 | mScrollViewPager.setHeight(mScrollView.getMeasuredHeight()-mTabLayout.getMeasuredHeight()); 128 | } 129 | },100); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /app/src/main/java/com/czm/main/RecyclerViewListAdapter.java: -------------------------------------------------------------------------------- 1 | package com.czm.main; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | /** 14 | * Created by caizhiming on 2016/8/13. 15 | */ 16 | 17 | public class RecyclerViewListAdapter extends RecyclerView.Adapter{ 18 | 19 | private Context mContext; 20 | private List mData = new ArrayList<>(); 21 | public RecyclerViewListAdapter(Context context){ 22 | mContext =context; 23 | } 24 | public void setData(List data){ 25 | mData.clear(); 26 | mData.addAll(data); 27 | notifyDataSetChanged(); 28 | } 29 | 30 | @Override 31 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 32 | LayoutInflater inflater = LayoutInflater.from(mContext); 33 | View view = inflater.inflate(R.layout.layout_list_item,parent,false); 34 | return new ItemViewHolder(view); 35 | } 36 | 37 | @Override 38 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 39 | if(holder instanceof ItemViewHolder){ 40 | ((ItemViewHolder)holder).bindData(mData.get(position),position); 41 | } 42 | } 43 | 44 | @Override 45 | public int getItemCount() { 46 | return mData.size(); 47 | } 48 | 49 | public class ItemViewHolder extends RecyclerView.ViewHolder{ 50 | 51 | TextView item_text; 52 | 53 | public ItemViewHolder(View root){ 54 | super(root); 55 | item_text = (TextView) root.findViewById(R.id.item_text); 56 | } 57 | 58 | public void bindData(final String data, final int pos) { 59 | item_text.setText(data); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/com/czm/model/TabItem.java: -------------------------------------------------------------------------------- 1 | package com.czm.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Created by caizhiming on 2017/4/13. 7 | */ 8 | 9 | public class TabItem implements Serializable{ 10 | private String itemName; 11 | 12 | public String getItemName() { 13 | return itemName; 14 | } 15 | 16 | public void setItemName(String itemName) { 17 | this.itemName = itemName; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/czm/tablayout/OnTabSelectListener.java: -------------------------------------------------------------------------------- 1 | package com.czm.tablayout; 2 | 3 | public interface OnTabSelectListener { 4 | void onTabSelect(int position); 5 | void onTabReselect(int position); 6 | } -------------------------------------------------------------------------------- /app/src/main/java/com/czm/tablayout/XCTabLayout.java: -------------------------------------------------------------------------------- 1 | package com.czm.tablayout; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.graphics.Path; 9 | import android.graphics.Rect; 10 | import android.graphics.drawable.GradientDrawable; 11 | import android.os.Bundle; 12 | import android.os.Parcelable; 13 | import android.support.v4.view.ViewPager; 14 | import android.util.AttributeSet; 15 | import android.util.TypedValue; 16 | import android.view.Gravity; 17 | import android.view.View; 18 | import android.view.ViewGroup; 19 | import android.widget.HorizontalScrollView; 20 | import android.widget.LinearLayout; 21 | import android.widget.TextView; 22 | 23 | import com.czm.main.R; 24 | import com.czm.utils.PhoneUtil; 25 | 26 | import java.util.ArrayList; 27 | import java.util.List; 28 | 29 | /** 30 | * Created by caizhiming on 2016/3/8. 31 | */ 32 | public class XCTabLayout extends HorizontalScrollView implements ViewPager.OnPageChangeListener { 33 | private Context mContext; 34 | private ViewPager mViewPager; 35 | private String[] mTitles; 36 | private LinearLayout mTabsContainer; 37 | private int mCurrentTab; 38 | private float mCurrentPositionOffset; 39 | private int mTabCount; 40 | /** 用于绘制显示器 */ 41 | private Rect mIndicatorRect = new Rect(); 42 | /** 用于实现滚动居中 */ 43 | private Rect mTabRect = new Rect(); 44 | private GradientDrawable mIndicatorDrawable = new GradientDrawable(); 45 | 46 | private Paint mRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 47 | private Paint mDividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 48 | private Paint mTrianglePaint = new Paint(Paint.ANTI_ALIAS_FLAG); 49 | private Path mTrianglePath = new Path(); 50 | private static final int STYLE_NORMAL = 0; 51 | private static final int STYLE_TRIANGLE = 1; 52 | private static final int STYLE_BLOCK = 2; 53 | private int mIndicatorStyle = STYLE_NORMAL; 54 | 55 | private float mTabPadding; 56 | private boolean mTabSpaceEqual; 57 | private float mTabWidth; 58 | 59 | /** indicator */ 60 | private int mIndicatorColor; 61 | private float mIndicatorHeight; 62 | private float mIndicatorWidth; 63 | private float mIndicatorCornerRadius; 64 | private float mIndicatorMarginLeft; 65 | private float mIndicatorMarginTop; 66 | private float mIndicatorMarginRight; 67 | private float mIndicatorMarginBottom; 68 | private int mIndicatorGravity; 69 | private boolean mIndicatorWidthEqualTitle; 70 | 71 | /** underline */ 72 | private int mUnderlineColor; 73 | private float mUnderlineHeight; 74 | private int mUnderlineGravity; 75 | 76 | /** divider */ 77 | private int mDividerColor; 78 | private float mDividerWidth; 79 | private float mDividerPadding; 80 | 81 | /** title */ 82 | private float mTextsize; 83 | private int mTextSelectColor; 84 | private int mTextUnselectColor; 85 | private boolean mTextBold; 86 | private boolean mTextAllCaps; 87 | 88 | private int mLastScrollX; 89 | private int mHeight; 90 | private boolean mShowRedDot = false; 91 | private List mDotList = new ArrayList<>(); 92 | private List mDotDataList = new ArrayList<>(); 93 | public void hideAllDot(){ 94 | for (int i = 0; i < mDotList.size(); i++) { 95 | mDotList.get(i).setVisibility(GONE); 96 | } 97 | } 98 | public void subDotData(int pos){ 99 | int old = mDotDataList.get(pos); 100 | int newNum = old -1 ; 101 | if(newNum <=0) newNum = 0; 102 | mDotDataList.set(pos,newNum); 103 | if(newNum > 0){ 104 | mDotList.get(pos).setVisibility(VISIBLE); 105 | mDotList.get(pos).setText(String.valueOf(newNum)); 106 | if(newNum > 99){ 107 | mDotList.get(pos).setText("99+"); 108 | int padding = PhoneUtil.dip2px(mContext,4); 109 | mDotList.get(pos).setPadding(padding,0,padding,0); 110 | mDotList.get(pos).requestLayout(); 111 | }else{ 112 | mDotList.get(pos).setText(String.valueOf(newNum)); 113 | int padding = PhoneUtil.dip2px(mContext,0); 114 | mDotList.get(pos).setPadding(padding,0,padding,0); 115 | mDotList.get(pos).requestLayout(); 116 | 117 | } 118 | }else{ 119 | mDotList.get(pos).setVisibility(GONE); 120 | } 121 | } 122 | public void setDotDatas(List data){ 123 | if(data.size() != (mDotList.size()+1)) 124 | return; 125 | for (int i = 0; i < mDotList.size(); i++) { 126 | final TextView dot = mDotList.get(i); 127 | int num = data.get(i+1); 128 | mDotDataList.add(num); 129 | if(num > 0){ 130 | dot.setVisibility(VISIBLE); 131 | if(num > 99){ 132 | dot.setText("99+"); 133 | int padding = PhoneUtil.dip2px(mContext,4); 134 | dot.setPadding(padding,0,padding,0); 135 | dot.requestLayout(); 136 | 137 | }else{ 138 | dot.setText(String.valueOf(num)); 139 | int padding = PhoneUtil.dip2px(mContext,0); 140 | dot.setPadding(padding,0,padding,0); 141 | dot.requestLayout(); 142 | } 143 | }else{ 144 | dot.setVisibility(GONE); 145 | } 146 | 147 | } 148 | } 149 | public void showRedDot(boolean showRedDot){ 150 | mShowRedDot = showRedDot; 151 | } 152 | 153 | public XCTabLayout(Context context) { 154 | this(context, null, 0); 155 | } 156 | 157 | public XCTabLayout(Context context, AttributeSet attrs) { 158 | this(context, attrs, 0); 159 | } 160 | 161 | public XCTabLayout(Context context, AttributeSet attrs, int defStyleAttr) { 162 | super(context, attrs, defStyleAttr); 163 | setFillViewport(true);//设置滚动视图是否可以伸缩其内容以填充视口 164 | setWillNotDraw(false);//重写onDraw方法,需要调用这个方法来清除flag 165 | setClipChildren(false); 166 | setClipToPadding(false); 167 | 168 | this.mContext = context; 169 | mTabsContainer = new LinearLayout(context); 170 | 171 | 172 | addView(mTabsContainer); 173 | 174 | obtainAttributes(context, attrs); 175 | 176 | //get layout_height 177 | String height = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_height"); 178 | 179 | //create ViewPager 180 | if (height.equals(ViewGroup.LayoutParams.MATCH_PARENT + "")) { 181 | } else if (height.equals(ViewGroup.LayoutParams.WRAP_CONTENT + "")) { 182 | } else { 183 | int[] systemAttrs = {android.R.attr.layout_height}; 184 | TypedArray a = context.obtainStyledAttributes(attrs, systemAttrs); 185 | mHeight = a.getDimensionPixelSize(0, ViewGroup.LayoutParams.WRAP_CONTENT); 186 | a.recycle(); 187 | } 188 | } 189 | 190 | private void obtainAttributes(Context context, AttributeSet attrs) { 191 | TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SlidingTabLayout); 192 | 193 | mIndicatorStyle = ta.getInt(R.styleable.SlidingTabLayout_tl_indicator_style, STYLE_NORMAL); 194 | mIndicatorColor = ta.getColor(R.styleable.SlidingTabLayout_tl_indicator_color, Color.parseColor(mIndicatorStyle == STYLE_BLOCK ? "#4B6A87" : "#ffffff")); 195 | mIndicatorHeight = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_height, 196 | dp2px(mIndicatorStyle == STYLE_TRIANGLE ? 4 : (mIndicatorStyle == STYLE_BLOCK ? -1 : 2))); 197 | mIndicatorWidth = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_width, dp2px(mIndicatorStyle == STYLE_TRIANGLE ? 10 : -1)); 198 | mIndicatorCornerRadius = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_corner_radius, dp2px(mIndicatorStyle == STYLE_BLOCK ? -1 : 0)); 199 | mIndicatorMarginLeft = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_margin_left, dp2px(0)); 200 | mIndicatorMarginTop = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_margin_top, dp2px(mIndicatorStyle == STYLE_BLOCK ? 7 : 0)); 201 | mIndicatorMarginRight = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_margin_right, dp2px(0)); 202 | mIndicatorMarginBottom = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_margin_bottom, dp2px(mIndicatorStyle == STYLE_BLOCK ? 7 : 0)); 203 | mIndicatorGravity = ta.getInt(R.styleable.SlidingTabLayout_tl_indicator_gravity, Gravity.BOTTOM); 204 | mIndicatorWidthEqualTitle = ta.getBoolean(R.styleable.SlidingTabLayout_tl_indicator_width_equal_title, false); 205 | 206 | mUnderlineColor = ta.getColor(R.styleable.SlidingTabLayout_tl_underline_color, Color.parseColor("#ffffff")); 207 | mUnderlineHeight = ta.getDimension(R.styleable.SlidingTabLayout_tl_underline_height, dp2px(0)); 208 | mUnderlineGravity = ta.getInt(R.styleable.SlidingTabLayout_tl_underline_gravity, Gravity.BOTTOM); 209 | 210 | mDividerColor = ta.getColor(R.styleable.SlidingTabLayout_tl_divider_color, Color.parseColor("#ffffff")); 211 | mDividerWidth = ta.getDimension(R.styleable.SlidingTabLayout_tl_divider_width, dp2px(0)); 212 | mDividerPadding = ta.getDimension(R.styleable.SlidingTabLayout_tl_divider_padding, dp2px(12)); 213 | 214 | mTextsize = ta.getDimension(R.styleable.SlidingTabLayout_tl_textsize, sp2px(14)); 215 | mTextSelectColor = ta.getColor(R.styleable.SlidingTabLayout_tl_textSelectColor, Color.parseColor("#ffffff")); 216 | mTextUnselectColor = ta.getColor(R.styleable.SlidingTabLayout_tl_textUnselectColor, Color.parseColor("#AAffffff")); 217 | mTextBold = ta.getBoolean(R.styleable.SlidingTabLayout_tl_textBold, false); 218 | mTextAllCaps = ta.getBoolean(R.styleable.SlidingTabLayout_tl_textAllCaps, false); 219 | 220 | mTabSpaceEqual = ta.getBoolean(R.styleable.SlidingTabLayout_tl_tab_space_equal, false); 221 | mTabWidth = ta.getDimension(R.styleable.SlidingTabLayout_tl_tab_width, dp2px(-1)); 222 | mTabPadding = ta.getDimension(R.styleable.SlidingTabLayout_tl_tab_padding, mTabSpaceEqual || mTabWidth > 0 ? dp2px(0) : dp2px(20)); 223 | 224 | ta.recycle(); 225 | } 226 | 227 | /** 关联ViewPager */ 228 | public void setViewPager(ViewPager vp) { 229 | if (vp == null || vp.getAdapter() == null) { 230 | throw new IllegalStateException("ViewPager or ViewPager adapter can not be NULL !"); 231 | } 232 | 233 | this.mViewPager = vp; 234 | 235 | this.mViewPager.removeOnPageChangeListener(this); 236 | this.mViewPager.addOnPageChangeListener(this); 237 | notifyDataSetChanged(); 238 | } 239 | 240 | /** 关联ViewPager,用于不想在ViewPager适配器中设置titles数据的情况 */ 241 | public void setViewPager(ViewPager vp, String[] titles) { 242 | if (vp == null || vp.getAdapter() == null) { 243 | throw new IllegalStateException("ViewPager or ViewPager adapter can not be NULL !"); 244 | } 245 | 246 | if (titles == null || titles.length == 0) { 247 | throw new IllegalStateException("Titles can not be EMPTY !"); 248 | } 249 | 250 | if (titles.length != vp.getAdapter().getCount()) { 251 | throw new IllegalStateException("Titles length must be the same as the page count !"); 252 | } 253 | 254 | this.mViewPager = vp; 255 | this.mTitles = titles; 256 | 257 | this.mViewPager.removeOnPageChangeListener(this); 258 | this.mViewPager.addOnPageChangeListener(this); 259 | notifyDataSetChanged(); 260 | } 261 | 262 | // /** 关联ViewPager,用于连适配器都不想自己实例化的情况 */ 263 | // public void setViewPager(ViewPager vp, String[] titles, FragmentActivity fa, ArrayList fragments) { 264 | // if (vp == null) { 265 | // throw new IllegalStateException("ViewPager can not be NULL !"); 266 | // } 267 | // 268 | // if (titles == null || titles.length == 0) { 269 | // throw new IllegalStateException("Titles can not be EMPTY !"); 270 | // } 271 | // 272 | // this.mViewPager = vp; 273 | // this.mViewPager.setAdapter(new InnerPagerAdapter(fa.getSupportFragmentManager(), fragments, titles)); 274 | // 275 | // this.mViewPager.removeOnPageChangeListener(this); 276 | // this.mViewPager.addOnPageChangeListener(this); 277 | // notifyDataSetChanged(); 278 | // } 279 | 280 | /** 更新数据 */ 281 | public void notifyDataSetChanged() { 282 | mTabsContainer.removeAllViews(); 283 | this.mTabCount = mTitles == null ? mViewPager.getAdapter().getCount() : mTitles.length; 284 | View tabView = null; 285 | for (int i = 0; i < mTabCount; i++) { 286 | if (mViewPager.getAdapter() instanceof CustomTabProvider) { 287 | tabView = ((CustomTabProvider) mViewPager.getAdapter()).getCustomTabView(this, i); 288 | } else { 289 | tabView = View.inflate(mContext, R.layout.layout_tab, null); 290 | } 291 | TextView dot = (TextView) tabView.findViewById(R.id.tv_reddot); 292 | mDotList.add(dot); 293 | // if(mShowRedDot){ 294 | // dot.setVisibility(VISIBLE); 295 | // }else{ 296 | // dot.setVisibility(GONE); 297 | // } 298 | CharSequence pageTitle = mTitles == null ? mViewPager.getAdapter().getPageTitle(i) : mTitles[i]; 299 | addTab(i, pageTitle.toString(), tabView); 300 | } 301 | 302 | updateTabStyles(); 303 | } 304 | 305 | /** 创建并添加tab */ 306 | private void addTab(final int position, String title, View tabView) { 307 | TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); 308 | if (tv_tab_title != null) { 309 | if (title != null) tv_tab_title.setText(title); 310 | } 311 | 312 | tabView.setOnClickListener(new OnClickListener() { 313 | @Override 314 | public void onClick(View v) { 315 | if (mViewPager.getCurrentItem() != position) { 316 | mViewPager.setCurrentItem(position); 317 | if (mListener != null) { 318 | mListener.onTabSelect(position); 319 | } 320 | } else { 321 | if (mListener != null) { 322 | mListener.onTabReselect(position); 323 | } 324 | } 325 | } 326 | }); 327 | 328 | /** 每一个Tab的布局参数 */ 329 | LinearLayout.LayoutParams lp_tab = mTabSpaceEqual ? 330 | new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f) : 331 | new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); 332 | if (mTabWidth > 0) { 333 | lp_tab = new LinearLayout.LayoutParams((int) mTabWidth, LayoutParams.MATCH_PARENT); 334 | } 335 | mTabsContainer.addView(tabView, position, lp_tab); 336 | } 337 | 338 | private void updateTabStyles() { 339 | for (int i = 0; i < mTabCount; i++) { 340 | View v = mTabsContainer.getChildAt(i); 341 | // v.setPadding((int) mTabPadding, v.getPaddingTop(), (int) mTabPadding, v.getPaddingBottom()); 342 | TextView tv_tab_title = (TextView) v.findViewById(R.id.tv_tab_title); 343 | if (tv_tab_title != null) { 344 | tv_tab_title.setTextColor(i == mCurrentTab ? mTextSelectColor : mTextUnselectColor); 345 | tv_tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextsize); 346 | tv_tab_title.setPadding((int) mTabPadding, 0, (int) mTabPadding, 0); 347 | if (mTextAllCaps) { 348 | tv_tab_title.setText(tv_tab_title.getText().toString().toUpperCase()); 349 | } 350 | 351 | if (mTextBold) { 352 | tv_tab_title.getPaint().setFakeBoldText(mTextBold); 353 | } 354 | } 355 | } 356 | } 357 | 358 | @Override 359 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 360 | /** 361 | * position:当前View的位置 362 | * mCurrentPositionOffset:当前View的偏移量比例.[0,1) 363 | */ 364 | this.mCurrentTab = position; 365 | this.mCurrentPositionOffset = positionOffset; 366 | scrollToCurrentTab(); 367 | invalidate(); 368 | } 369 | 370 | @Override 371 | public void onPageSelected(int position) { 372 | updateTabSelection(position); 373 | } 374 | 375 | @Override 376 | public void onPageScrollStateChanged(int state) { 377 | } 378 | 379 | /** HorizontalScrollView滚到当前tab,并且居中显示 */ 380 | private void scrollToCurrentTab() { 381 | if (mTabCount <= 0) { 382 | return; 383 | } 384 | 385 | int offset = (int) (mCurrentPositionOffset * mTabsContainer.getChildAt(mCurrentTab).getWidth()); 386 | /**当前Tab的left+当前Tab的Width乘以positionOffset*/ 387 | int newScrollX = mTabsContainer.getChildAt(mCurrentTab).getLeft() + offset; 388 | 389 | if (mCurrentTab > 0 || offset > 0) { 390 | /**HorizontalScrollView移动到当前tab,并居中*/ 391 | newScrollX -= getWidth() / 2 - getPaddingLeft(); 392 | calcIndicatorRect(); 393 | newScrollX += ((mTabRect.right - mTabRect.left) / 2); 394 | } 395 | 396 | if (newScrollX != mLastScrollX) { 397 | mLastScrollX = newScrollX; 398 | /** scrollTo(int x,int y):x,y代表的不是坐标点,而是偏移量 399 | * x:表示离起始位置的x水平方向的偏移量 400 | * y:表示离起始位置的y垂直方向的偏移量 401 | */ 402 | scrollTo(newScrollX, 0); 403 | } 404 | } 405 | 406 | private void updateTabSelection(int position) { 407 | for (int i = 0; i < mTabCount; ++i) { 408 | View tabView = mTabsContainer.getChildAt(i); 409 | final boolean isSelect = i == position; 410 | TextView tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); 411 | 412 | if (tab_title != null) { 413 | tab_title.setTextColor(isSelect ? mTextSelectColor : mTextUnselectColor); 414 | } 415 | 416 | if (mViewPager.getAdapter() instanceof CustomTabProvider) { 417 | if (isSelect) { 418 | ((CustomTabProvider) mViewPager.getAdapter()).tabSelect(tabView); 419 | } else { 420 | ((CustomTabProvider) mViewPager.getAdapter()).tabUnselect(tabView); 421 | } 422 | } 423 | } 424 | } 425 | 426 | private float margin; 427 | 428 | private void calcIndicatorRect() { 429 | View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab); 430 | float left = currentTabView.getLeft(); 431 | float right = currentTabView.getRight(); 432 | 433 | //for mIndicatorWidthEqualTitle 434 | if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) { 435 | TextView tab_title = (TextView) currentTabView.findViewById(R.id.tv_tab_title); 436 | mTextPaint.setTextSize(mTextsize); 437 | float textWidth = mTextPaint.measureText(tab_title.getText().toString()); 438 | margin = (right - left - textWidth) / 2; 439 | } 440 | 441 | if (this.mCurrentTab < mTabCount - 1) { 442 | View nextTabView = mTabsContainer.getChildAt(this.mCurrentTab + 1); 443 | float nextTabLeft = nextTabView.getLeft(); 444 | float nextTabRight = nextTabView.getRight(); 445 | 446 | left = left + mCurrentPositionOffset * (nextTabLeft - left); 447 | right = right + mCurrentPositionOffset * (nextTabRight - right); 448 | 449 | //for mIndicatorWidthEqualTitle 450 | if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) { 451 | TextView next_tab_title = (TextView) nextTabView.findViewById(R.id.tv_tab_title); 452 | mTextPaint.setTextSize(mTextsize); 453 | float nextTextWidth = mTextPaint.measureText(next_tab_title.getText().toString()); 454 | float nextMargin = (nextTabRight - nextTabLeft - nextTextWidth) / 2; 455 | margin = margin + mCurrentPositionOffset * (nextMargin - margin); 456 | } 457 | } 458 | 459 | mIndicatorRect.left = (int) left; 460 | mIndicatorRect.right = (int) right; 461 | //for mIndicatorWidthEqualTitle 462 | if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) { 463 | mIndicatorRect.left = (int) (left + margin - 1); 464 | mIndicatorRect.right = (int) (right - margin - 1); 465 | } 466 | 467 | mTabRect.left = (int) left; 468 | mTabRect.right = (int) right; 469 | 470 | if (mIndicatorWidth < 0) { //indicatorWidth小于0时,原jpardogo's PagerSlidingTabStrip 471 | 472 | } else {//indicatorWidth大于0时,圆角矩形以及三角形 473 | float indicatorLeft = currentTabView.getLeft() + (currentTabView.getWidth() - mIndicatorWidth) / 2; 474 | 475 | if (this.mCurrentTab < mTabCount - 1) { 476 | View nextTab = mTabsContainer.getChildAt(this.mCurrentTab + 1); 477 | indicatorLeft = indicatorLeft + mCurrentPositionOffset * (currentTabView.getWidth() / 2 + nextTab.getWidth() / 2); 478 | } 479 | 480 | mIndicatorRect.left = (int) indicatorLeft; 481 | mIndicatorRect.right = (int) (mIndicatorRect.left + mIndicatorWidth); 482 | } 483 | } 484 | 485 | @Override 486 | protected void onDraw(Canvas canvas) { 487 | super.onDraw(canvas); 488 | 489 | if (isInEditMode() || mTabCount <= 0) { 490 | return; 491 | } 492 | 493 | int height = getHeight(); 494 | int paddingLeft = getPaddingLeft(); 495 | // draw divider 496 | if (mDividerWidth > 0) { 497 | mDividerPaint.setStrokeWidth(mDividerWidth); 498 | mDividerPaint.setColor(mDividerColor); 499 | for (int i = 0; i < mTabCount - 1; i++) { 500 | View tab = mTabsContainer.getChildAt(i); 501 | canvas.drawLine(paddingLeft + tab.getRight(), mDividerPadding, paddingLeft + tab.getRight(), height - mDividerPadding, mDividerPaint); 502 | } 503 | } 504 | 505 | // draw underline 506 | if (mUnderlineHeight > 0) { 507 | mRectPaint.setColor(mUnderlineColor); 508 | if (mUnderlineGravity == Gravity.BOTTOM) { 509 | canvas.drawRect(paddingLeft, height - mUnderlineHeight, mTabsContainer.getWidth() + paddingLeft, height, mRectPaint); 510 | } else { 511 | canvas.drawRect(paddingLeft, 0, mTabsContainer.getWidth() + paddingLeft, mUnderlineHeight, mRectPaint); 512 | } 513 | } 514 | 515 | //draw indicator line 516 | 517 | calcIndicatorRect(); 518 | if (mIndicatorStyle == STYLE_TRIANGLE) { 519 | if (mIndicatorHeight > 0) { 520 | mTrianglePaint.setColor(mIndicatorColor); 521 | mTrianglePath.reset(); 522 | mTrianglePath.moveTo(paddingLeft + mIndicatorRect.left, height); 523 | mTrianglePath.lineTo(paddingLeft + mIndicatorRect.left / 2 + mIndicatorRect.right / 2, height - mIndicatorHeight); 524 | mTrianglePath.lineTo(paddingLeft + mIndicatorRect.right, height); 525 | mTrianglePath.close(); 526 | canvas.drawPath(mTrianglePath, mTrianglePaint); 527 | } 528 | } else if (mIndicatorStyle == STYLE_BLOCK) { 529 | if (mIndicatorHeight < 0) { 530 | mIndicatorHeight = height - mIndicatorMarginTop - mIndicatorMarginBottom; 531 | } else { 532 | 533 | } 534 | 535 | if (mIndicatorHeight > 0) { 536 | if (mIndicatorCornerRadius < 0 || mIndicatorCornerRadius > mIndicatorHeight / 2) { 537 | mIndicatorCornerRadius = mIndicatorHeight / 2; 538 | } 539 | 540 | mIndicatorDrawable.setColor(mIndicatorColor); 541 | mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left, 542 | (int) mIndicatorMarginTop, (int) (paddingLeft + mIndicatorRect.right - mIndicatorMarginRight), 543 | (int) (mIndicatorMarginTop + mIndicatorHeight)); 544 | mIndicatorDrawable.setCornerRadius(mIndicatorCornerRadius); 545 | mIndicatorDrawable.draw(canvas); 546 | } 547 | } else { 548 | /* mRectPaint.setColor(mIndicatorColor); 549 | calcIndicatorRect(); 550 | canvas.drawRect(getPaddingLeft() + mIndicatorRect.left, getHeight() - mIndicatorHeight, 551 | mIndicatorRect.right + getPaddingLeft(), getHeight(), mRectPaint);*/ 552 | 553 | if (mIndicatorHeight > 0) { 554 | mIndicatorDrawable.setColor(mIndicatorColor); 555 | 556 | if (mIndicatorGravity == Gravity.BOTTOM) { 557 | mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left, 558 | height - (int) mIndicatorHeight - (int) mIndicatorMarginBottom, 559 | paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight, 560 | height - (int) mIndicatorMarginBottom); 561 | } else { 562 | mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left, 563 | (int) mIndicatorMarginTop, 564 | paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight, 565 | (int) mIndicatorHeight + (int) mIndicatorMarginTop); 566 | } 567 | mIndicatorDrawable.setCornerRadius(mIndicatorCornerRadius); 568 | mIndicatorDrawable.draw(canvas); 569 | } 570 | } 571 | } 572 | 573 | //setter and getter 574 | public void setCurrentTab(int currentTab) { 575 | this.mCurrentTab = currentTab; 576 | mViewPager.setCurrentItem(currentTab); 577 | } 578 | 579 | public void setIndicatorStyle(int indicatorStyle) { 580 | this.mIndicatorStyle = indicatorStyle; 581 | invalidate(); 582 | } 583 | 584 | public void setTabPadding(float tabPadding) { 585 | this.mTabPadding = dp2px(tabPadding); 586 | updateTabStyles(); 587 | } 588 | 589 | public void setTabSpaceEqual(boolean tabSpaceEqual) { 590 | this.mTabSpaceEqual = tabSpaceEqual; 591 | updateTabStyles(); 592 | } 593 | 594 | public void setTabWidth(float tabWidth) { 595 | this.mTabWidth = dp2px(tabWidth); 596 | updateTabStyles(); 597 | } 598 | 599 | public void setIndicatorColor(int indicatorColor) { 600 | this.mIndicatorColor = indicatorColor; 601 | invalidate(); 602 | } 603 | 604 | public void setIndicatorHeight(float indicatorHeight) { 605 | this.mIndicatorHeight = dp2px(indicatorHeight); 606 | invalidate(); 607 | } 608 | 609 | public void setIndicatorWidth(float indicatorWidth) { 610 | this.mIndicatorWidth = dp2px(indicatorWidth); 611 | invalidate(); 612 | } 613 | 614 | public void setIndicatorCornerRadius(float indicatorCornerRadius) { 615 | this.mIndicatorCornerRadius = dp2px(indicatorCornerRadius); 616 | invalidate(); 617 | } 618 | 619 | public void setIndicatorGravity(int indicatorGravity) { 620 | this.mIndicatorGravity = indicatorGravity; 621 | invalidate(); 622 | } 623 | 624 | public void setIndicatorMargin(float indicatorMarginLeft, float indicatorMarginTop, 625 | float indicatorMarginRight, float indicatorMarginBottom) { 626 | this.mIndicatorMarginLeft = dp2px(indicatorMarginLeft); 627 | this.mIndicatorMarginTop = dp2px(indicatorMarginTop); 628 | this.mIndicatorMarginRight = dp2px(indicatorMarginRight); 629 | this.mIndicatorMarginBottom = dp2px(indicatorMarginBottom); 630 | invalidate(); 631 | } 632 | 633 | public void setIndicatorWidthEqualTitle(boolean indicatorWidthEqualTitle) { 634 | this.mIndicatorWidthEqualTitle = indicatorWidthEqualTitle; 635 | invalidate(); 636 | } 637 | 638 | public void setUnderlineColor(int underlineColor) { 639 | this.mUnderlineColor = underlineColor; 640 | invalidate(); 641 | } 642 | 643 | public void setUnderlineHeight(float underlineHeight) { 644 | this.mUnderlineHeight = dp2px(underlineHeight); 645 | invalidate(); 646 | } 647 | 648 | public void setUnderlineGravity(int underlineGravity) { 649 | this.mUnderlineGravity = underlineGravity; 650 | invalidate(); 651 | } 652 | 653 | public void setDividerColor(int dividerColor) { 654 | this.mDividerColor = dividerColor; 655 | invalidate(); 656 | } 657 | 658 | public void setDividerWidth(float dividerWidth) { 659 | this.mDividerWidth = dp2px(dividerWidth); 660 | invalidate(); 661 | } 662 | 663 | public void setDividerPadding(float dividerPadding) { 664 | this.mDividerPadding = dp2px(dividerPadding); 665 | invalidate(); 666 | } 667 | 668 | public void setTextsize(float textsize) { 669 | this.mTextsize = sp2px(textsize); 670 | updateTabStyles(); 671 | } 672 | 673 | public void setTextSelectColor(int textSelectColor) { 674 | this.mTextSelectColor = textSelectColor; 675 | updateTabStyles(); 676 | } 677 | 678 | public void setTextUnselectColor(int textUnselectColor) { 679 | this.mTextUnselectColor = textUnselectColor; 680 | updateTabStyles(); 681 | } 682 | 683 | public void setTextBold(boolean textBold) { 684 | this.mTextBold = textBold; 685 | updateTabStyles(); 686 | } 687 | 688 | public void setTextAllCaps(boolean textAllCaps) { 689 | this.mTextAllCaps = textAllCaps; 690 | updateTabStyles(); 691 | } 692 | 693 | 694 | public int getTabCount() { 695 | return mTabCount; 696 | } 697 | 698 | public int getCurrentTab() { 699 | return mCurrentTab; 700 | } 701 | 702 | public int getIndicatorStyle() { 703 | return mIndicatorStyle; 704 | } 705 | 706 | public float getTabPadding() { 707 | return mTabPadding; 708 | } 709 | 710 | public boolean isTabSpaceEqual() { 711 | return mTabSpaceEqual; 712 | } 713 | 714 | public float getTabWidth() { 715 | return mTabWidth; 716 | } 717 | 718 | public int getIndicatorColor() { 719 | return mIndicatorColor; 720 | } 721 | 722 | public float getIndicatorHeight() { 723 | return mIndicatorHeight; 724 | } 725 | 726 | public float getIndicatorWidth() { 727 | return mIndicatorWidth; 728 | } 729 | 730 | public float getIndicatorCornerRadius() { 731 | return mIndicatorCornerRadius; 732 | } 733 | 734 | public float getIndicatorMarginLeft() { 735 | return mIndicatorMarginLeft; 736 | } 737 | 738 | public float getIndicatorMarginTop() { 739 | return mIndicatorMarginTop; 740 | } 741 | 742 | public float getIndicatorMarginRight() { 743 | return mIndicatorMarginRight; 744 | } 745 | 746 | public float getIndicatorMarginBottom() { 747 | return mIndicatorMarginBottom; 748 | } 749 | 750 | public int getUnderlineColor() { 751 | return mUnderlineColor; 752 | } 753 | 754 | public float getUnderlineHeight() { 755 | return mUnderlineHeight; 756 | } 757 | 758 | public int getDividerColor() { 759 | return mDividerColor; 760 | } 761 | 762 | public float getDividerWidth() { 763 | return mDividerWidth; 764 | } 765 | 766 | public float getDividerPadding() { 767 | return mDividerPadding; 768 | } 769 | 770 | public float getTextsize() { 771 | return mTextsize; 772 | } 773 | 774 | public int getTextSelectColor() { 775 | return mTextSelectColor; 776 | } 777 | 778 | public int getTextUnselectColor() { 779 | return mTextUnselectColor; 780 | } 781 | 782 | public boolean isTextBold() { 783 | return mTextBold; 784 | } 785 | 786 | public boolean isTextAllCaps() { 787 | return mTextAllCaps; 788 | } 789 | 790 | public TextView getTitleView(int tab) { 791 | View tabView = mTabsContainer.getChildAt(tab); 792 | TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title); 793 | return tv_tab_title; 794 | } 795 | 796 | //setter and getter 797 | 798 | // show MsgTipView 799 | private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 800 | 801 | 802 | private OnTabSelectListener mListener; 803 | 804 | public void setOnTabSelectListener(OnTabSelectListener listener) { 805 | this.mListener = listener; 806 | } 807 | 808 | 809 | public interface CustomTabProvider { 810 | View getCustomTabView(ViewGroup parent, int position); 811 | 812 | void tabSelect(View tab); 813 | 814 | void tabUnselect(View tab); 815 | } 816 | 817 | @Override 818 | protected Parcelable onSaveInstanceState() { 819 | Bundle bundle = new Bundle(); 820 | bundle.putParcelable("instanceState", super.onSaveInstanceState()); 821 | bundle.putInt("mCurrentTab", mCurrentTab); 822 | return bundle; 823 | } 824 | 825 | @Override 826 | protected void onRestoreInstanceState(Parcelable state) { 827 | if (state instanceof Bundle) { 828 | Bundle bundle = (Bundle) state; 829 | mCurrentTab = bundle.getInt("mCurrentTab"); 830 | state = bundle.getParcelable("instanceState"); 831 | if (mCurrentTab != 0 && mTabsContainer.getChildCount() > 0) { 832 | updateTabSelection(mCurrentTab); 833 | scrollToCurrentTab(); 834 | } 835 | } 836 | super.onRestoreInstanceState(state); 837 | } 838 | 839 | protected int dp2px(float dp) { 840 | final float scale = mContext.getResources().getDisplayMetrics().density; 841 | return (int) (dp * scale + 0.5f); 842 | } 843 | 844 | protected int sp2px(float sp) { 845 | final float scale = this.mContext.getResources().getDisplayMetrics().scaledDensity; 846 | return (int) (sp * scale + 0.5f); 847 | } 848 | } 849 | -------------------------------------------------------------------------------- /app/src/main/java/com/czm/uphidescrollview/BaseListFragment.java: -------------------------------------------------------------------------------- 1 | package com.czm.uphidescrollview; 2 | 3 | import android.content.Context; 4 | import android.support.v4.app.Fragment; 5 | import android.view.View; 6 | 7 | /** 8 | * Created by caizhiming on 2016/11/14. 9 | */ 10 | public abstract class BaseListFragment extends Fragment { 11 | 12 | protected Context mContext; 13 | abstract View getSlidableView(); 14 | 15 | 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/czm/uphidescrollview/ListFragment.java: -------------------------------------------------------------------------------- 1 | package com.czm.uphidescrollview; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v7.widget.LinearLayoutManager; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | 12 | import com.czm.main.R; 13 | import com.czm.main.RecyclerViewListAdapter; 14 | import com.czm.model.TabItem; 15 | 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | 19 | /** 20 | * Created by caizhiming on 2016/11/14. 21 | */ 22 | public class ListFragment extends BaseListFragment { 23 | protected RecyclerView mRecyclerView; 24 | private TabItem mTabItem; 25 | private View mRootView; 26 | private RecyclerViewListAdapter mListAdapter; 27 | 28 | @Override 29 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 30 | mTabItem = (TabItem) getArguments().getSerializable("tab_item"); 31 | mRootView = inflater.inflate(R.layout.fragment_viewpager_list,null); 32 | 33 | return mRootView; 34 | } 35 | 36 | @Override 37 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 38 | super.onViewCreated(view, savedInstanceState); 39 | mContext = view.getContext(); 40 | mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerview); 41 | mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); 42 | mListAdapter = new RecyclerViewListAdapter(getContext()); 43 | mRecyclerView.setAdapter(mListAdapter); 44 | 45 | //fix bug: recyclerView & scrollView 46 | //see http://stackoverflow.com/questions/38074949/recyclerview-inside-scrollview-some-items-are-not-shown 47 | mRecyclerView.setNestedScrollingEnabled(false); 48 | 49 | List data = new ArrayList<>(); 50 | int i = 0; 51 | while (i < 30){ 52 | data.add(new String(mTabItem.getItemName()+": Item list "+(i+1))); 53 | i++; 54 | } 55 | mListAdapter.setData(data); 56 | } 57 | 58 | private int mLoginMode = -1; 59 | @Override 60 | public void onResume() { 61 | super.onResume(); 62 | } 63 | 64 | @Override 65 | View getSlidableView() { 66 | return mRecyclerView; 67 | } 68 | 69 | 70 | @Override 71 | public Context getContext(){ 72 | return mContext; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/com/czm/uphidescrollview/ObservableScrollView.java: -------------------------------------------------------------------------------- 1 | package com.czm.uphidescrollview; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.ScrollView; 6 | 7 | /** 8 | * Created by caizhiming on 15/12/21. 9 | */ 10 | public class ObservableScrollView extends ScrollView { 11 | 12 | public ObservableScrollView(Context context) { 13 | super(context); 14 | } 15 | 16 | public ObservableScrollView(Context context, AttributeSet attrs) { 17 | super(context, attrs); 18 | } 19 | 20 | public ObservableScrollView(Context context, AttributeSet attrs, int defStyle) { 21 | super(context, attrs, defStyle); 22 | } 23 | 24 | public interface OnScrollChangedListener { 25 | void onScrollChanged(int x, int y, int oldX, int oldY); 26 | } 27 | 28 | private OnScrollChangedListener onScrollChangedListener; 29 | 30 | public void setOnScrollListener(OnScrollChangedListener onScrollChangedListener) { 31 | this.onScrollChangedListener = onScrollChangedListener; 32 | } 33 | 34 | @Override 35 | protected void onScrollChanged(int x, int y, int oldX, int oldY) { 36 | super.onScrollChanged(x, y, oldX, oldY); 37 | if (onScrollChangedListener != null) { 38 | onScrollChangedListener.onScrollChanged(x, y, oldX, oldY); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /app/src/main/java/com/czm/uphidescrollview/ScrollViewPager.java: -------------------------------------------------------------------------------- 1 | package com.czm.uphidescrollview; 2 | 3 | import android.content.Context; 4 | import android.support.v4.view.ViewPager; 5 | import android.util.AttributeSet; 6 | 7 | /** 8 | * Created by caizhiming on 2017/2/22. 9 | */ 10 | public class ScrollViewPager extends ViewPager { 11 | public ScrollViewPager(Context context) { 12 | super(context); 13 | } 14 | 15 | public ScrollViewPager(Context context, AttributeSet attrs) { 16 | super(context, attrs); 17 | } 18 | 19 | private int mHeight; 20 | 21 | public void setHeight(int height) { 22 | mHeight = height; 23 | requestLayout(); 24 | } 25 | 26 | @Override 27 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 28 | if (mHeight > 0) { 29 | heightMeasureSpec = MeasureSpec.makeMeasureSpec(mHeight, MeasureSpec.EXACTLY); 30 | } 31 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/czm/uphidescrollview/ScrollViewPagerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.czm.uphidescrollview; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v4.app.FragmentManager; 6 | import android.support.v4.app.FragmentPagerAdapter; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | import com.czm.model.TabItem; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | /** 16 | * Created by caizhiming on 2016/11/14. 17 | */ 18 | public class ScrollViewPagerAdapter extends FragmentPagerAdapter { 19 | private List mFragmentList = new ArrayList<>(); 20 | private List mTitleList = new ArrayList<>(); 21 | public BaseListFragment getFragment(int pos){ 22 | return mFragmentList.get(pos); 23 | } 24 | public void setTabLayoutData(List list){ 25 | if(list != null && list.size() > 0){ 26 | mTitleList.clear(); 27 | mTitleList.addAll(list); 28 | 29 | mFragmentList.clear(); 30 | for (int i = 0; i < mTitleList.size(); i++) { 31 | ListFragment item = new ListFragment(); 32 | Bundle bundle = new Bundle(); 33 | bundle.putSerializable("tab_item",mTitleList.get(i)); 34 | item.setArguments(bundle); 35 | mFragmentList.add(item); 36 | } 37 | } 38 | } 39 | public ScrollViewPagerAdapter(FragmentManager fm) { 40 | super(fm); 41 | 42 | } 43 | 44 | public View getSlidableView (int index) { 45 | return mFragmentList.get(index).getSlidableView(); 46 | } 47 | 48 | @Override 49 | public Fragment getItem(int position) { 50 | if(mFragmentList!= null && mFragmentList.size() > 0){ 51 | return mFragmentList.get(position); 52 | }else{ 53 | return null; 54 | } 55 | } 56 | 57 | @Override 58 | public void destroyItem(ViewGroup container, int position, Object object) { 59 | // super.destroyItem(container, position, object); 60 | } 61 | 62 | @Override 63 | public int getCount() { 64 | return mTitleList.size(); 65 | } 66 | 67 | @Override 68 | public CharSequence getPageTitle(int position) { 69 | return mTitleList.get(position).getItemName(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/com/czm/uphidescrollview/ViewUtil.java: -------------------------------------------------------------------------------- 1 | package com.czm.uphidescrollview; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | import android.widget.ListView; 7 | import android.widget.ScrollView; 8 | 9 | /** 10 | * Created by caizhiming on 16/11/16. 11 | */ 12 | 13 | public class ViewUtil { 14 | public static boolean isScrollToTop(View view) { 15 | if (view instanceof ListView) { 16 | ListView listView = (ListView) view; 17 | int first = listView.getFirstVisiblePosition(); 18 | return first == 0; 19 | } else if (view instanceof RecyclerView) { 20 | RecyclerView recyclerView = (RecyclerView) view; 21 | return !recyclerView.canScrollVertically(-1); 22 | } else if (view instanceof ScrollView) { 23 | ScrollView scrollView = (ScrollView) view; 24 | return scrollView.getScrollY() == 0; 25 | } 26 | return true; 27 | } 28 | 29 | 30 | public static void scrollToTop (View view) { 31 | if (view instanceof ScrollView) { 32 | ScrollView scrollView = (ScrollView) view; 33 | scrollView.smoothScrollTo(0,0); 34 | } else if (view instanceof ListView) { 35 | ListView listView = (ListView) view; 36 | listView.setSelection(0); 37 | } 38 | } 39 | 40 | public static T findView(View view, Class tClass) { 41 | if (view.getClass() == tClass) { 42 | return (T) view; 43 | } else if (view instanceof ViewGroup) { 44 | ViewGroup viewGroup = (ViewGroup) view; 45 | for (int i=0;i mFirstY; 106 | boolean isUp = mCurrentY < mFirstY; 107 | 108 | if (isUp) { 109 | if (getScrollY() >= maxMoveY) { 110 | isIntercept = true; 111 | event.transform(eventMatrix); 112 | return scrollableView.dispatchTouchEvent(event); 113 | } 114 | } else if (isDown) { 115 | if (!ViewUtil.isScrollToTop(scrollableView)) { 116 | isIntercept = true; 117 | event.transform(eventMatrix); 118 | return scrollableView.dispatchTouchEvent(event); 119 | }else{ 120 | if(getScrollY()>=maxMoveY){ 121 | isIntercept = true; 122 | return scrollableView.dispatchTouchEvent(event); 123 | } 124 | } 125 | } 126 | } 127 | break; 128 | case MotionEvent.ACTION_UP: 129 | 130 | break; 131 | } 132 | return super.dispatchTouchEvent(event); 133 | } 134 | 135 | 136 | private ObservableScrollView.OnScrollChangedListener onScrollChangedListener; 137 | 138 | public void setOnScrollListener(ObservableScrollView.OnScrollChangedListener onScrollChangedListener) { 139 | this.onScrollChangedListener = onScrollChangedListener; 140 | } 141 | 142 | @Override 143 | protected void onScrollChanged(int x, int y, int oldX, int oldY) { 144 | super.onScrollChanged(x, y, oldX, oldY); 145 | if (onScrollChangedListener != null) { 146 | onScrollChangedListener.onScrollChanged(x, y, oldX, oldY); 147 | } 148 | } 149 | 150 | private Scroller mScroller; 151 | //调用此方法滚动到目标位置 duration滚动时间 152 | public void smoothScrollToSlow(int fx, int fy, int duration) { 153 | int dx = fx - getScrollX();//mScroller.getFinalX(); 普通view使用这种方法 154 | int dy = fy - getScrollY(); //mScroller.getFinalY(); 155 | smoothScrollBySlow(dx, dy, duration); 156 | } 157 | 158 | //调用此方法设置滚动的相对偏移 159 | public void smoothScrollBySlow(int dx, int dy,int duration) { 160 | 161 | //设置mScroller的滚动偏移量 162 | mScroller.startScroll(getScrollX(), getScrollY(), dx, dy,duration);//scrollView使用的方法(因为可以触摸拖动) 163 | // mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy, duration); //普通view使用的方法 164 | invalidate();//这里必须调用invalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果 165 | } 166 | 167 | @Override 168 | public void computeScroll() { 169 | 170 | //先判断mScroller滚动是否完成 171 | if (mScroller.computeScrollOffset()) { 172 | 173 | //这里调用View的scrollTo()完成实际的滚动 174 | scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); 175 | 176 | //必须调用该方法,否则不一定能看到滚动效果 177 | postInvalidate(); 178 | } 179 | super.computeScroll(); 180 | } 181 | 182 | } 183 | -------------------------------------------------------------------------------- /app/src/main/java/com/czm/utils/PhoneUtil.java: -------------------------------------------------------------------------------- 1 | package com.czm.utils; 2 | 3 | import android.app.Activity; 4 | import android.app.ActivityManager; 5 | import android.content.Context; 6 | import android.content.pm.ConfigurationInfo; 7 | import android.opengl.EGL14; 8 | import android.opengl.EGLConfig; 9 | import android.opengl.EGLContext; 10 | import android.opengl.EGLDisplay; 11 | import android.opengl.EGLSurface; 12 | import android.opengl.GLES10; 13 | import android.opengl.GLES20; 14 | import android.os.Build; 15 | import android.support.v7.widget.RecyclerView; 16 | import android.util.DisplayMetrics; 17 | import android.view.Display; 18 | import android.view.View; 19 | import android.view.inputmethod.InputMethodManager; 20 | 21 | /** 22 | * Created by caizhiming on 15/12/18. 23 | */ 24 | public class PhoneUtil { 25 | public static int TAB_BOTTOM_TYPE = 0; 26 | public static int TAB_TOP_TYPE = 0; 27 | private static boolean deviceDataInited = false; 28 | private static float displayMetricsDensity; 29 | private static int displayMetricsWidthPixels; 30 | private static int displayMetricsHeightPixels; 31 | private static int SCREEN_WIDTH_PX_CACHE = -1; 32 | private static int SCREEN_HEIGHT_PX_CACHE = -1; 33 | //android 5.0 以下 34 | private static final int DEFAULT_MAX_BITMAP_DIMENSION = 8196; 35 | 36 | public static void initDeviceData(Context context) { 37 | DisplayMetrics displayMetrics = null; 38 | if (context.getResources() != null && (displayMetrics = context.getResources().getDisplayMetrics()) != null) { 39 | displayMetricsDensity = displayMetrics.density; 40 | displayMetricsWidthPixels = displayMetrics.widthPixels; 41 | displayMetricsHeightPixels = displayMetrics.heightPixels; 42 | } 43 | deviceDataInited = true; 44 | } 45 | 46 | public static int dip2px(Context context, float dipValue) { 47 | if (!deviceDataInited) { 48 | initDeviceData(context); 49 | } 50 | 51 | return (int) (dipValue * displayMetricsDensity + 0.5f); 52 | } 53 | 54 | public static int px2dip(Context context, float pxValue) { 55 | if (!deviceDataInited) { 56 | initDeviceData(context); 57 | } 58 | 59 | return (int) (pxValue / displayMetricsDensity + 0.5f); 60 | } 61 | 62 | public static int getScreenWidthPx(Context context) { 63 | if (SCREEN_WIDTH_PX_CACHE < 0) { 64 | Display display = ((Activity) context).getWindowManager().getDefaultDisplay(); 65 | SCREEN_WIDTH_PX_CACHE = display.getWidth(); 66 | } 67 | 68 | return SCREEN_WIDTH_PX_CACHE; 69 | } 70 | 71 | public static int getScreenHeightPx(Context context) { 72 | if (SCREEN_HEIGHT_PX_CACHE < 0) { 73 | Display display = ((Activity) context).getWindowManager().getDefaultDisplay(); 74 | SCREEN_HEIGHT_PX_CACHE = display.getHeight(); 75 | } 76 | 77 | return SCREEN_HEIGHT_PX_CACHE; 78 | } 79 | 80 | 81 | public static View getCenterXChild(RecyclerView recyclerView) { 82 | int childCount = recyclerView.getChildCount(); 83 | if (childCount > 0) { 84 | for (int i = 0; i < childCount; ++i) { 85 | View child = recyclerView.getChildAt(i); 86 | if (isChildInCenterX(recyclerView, child)) { 87 | return child; 88 | } 89 | } 90 | } 91 | 92 | return null; 93 | } 94 | 95 | public static int getCenterXChildPosition(RecyclerView recyclerView) { 96 | int childCount = recyclerView.getChildCount(); 97 | if (childCount > 0) { 98 | for (int i = 0; i < childCount; ++i) { 99 | View child = recyclerView.getChildAt(i); 100 | if (isChildInCenterX(recyclerView, child)) { 101 | return recyclerView.getChildAdapterPosition(child); 102 | } 103 | } 104 | } 105 | 106 | return childCount; 107 | } 108 | 109 | public static View getCenterYChild(RecyclerView recyclerView) { 110 | int childCount = recyclerView.getChildCount(); 111 | if (childCount > 0) { 112 | for (int i = 0; i < childCount; ++i) { 113 | View child = recyclerView.getChildAt(i); 114 | if (isChildInCenterY(recyclerView, child)) { 115 | return child; 116 | } 117 | } 118 | } 119 | 120 | return null; 121 | } 122 | 123 | public static int getCenterYChildPosition(RecyclerView recyclerView) { 124 | int childCount = recyclerView.getChildCount(); 125 | if (childCount > 0) { 126 | for (int i = 0; i < childCount; ++i) { 127 | View child = recyclerView.getChildAt(i); 128 | if (isChildInCenterY(recyclerView, child)) { 129 | return recyclerView.getChildAdapterPosition(child); 130 | } 131 | } 132 | } 133 | 134 | return childCount; 135 | } 136 | 137 | public static boolean isChildInCenterX(RecyclerView recyclerView, View view) { 138 | int childCount = recyclerView.getChildCount(); 139 | int[] lvLocationOnScreen = new int[2]; 140 | int[] vLocationOnScreen = new int[2]; 141 | recyclerView.getLocationOnScreen(lvLocationOnScreen); 142 | int middleX = lvLocationOnScreen[0] + recyclerView.getWidth() / 2; 143 | if (childCount > 0) { 144 | view.getLocationOnScreen(vLocationOnScreen); 145 | if (vLocationOnScreen[0] <= middleX && vLocationOnScreen[0] + view.getWidth() >= middleX) { 146 | return true; 147 | } 148 | } 149 | 150 | return false; 151 | } 152 | 153 | public static boolean isChildInCenterY(RecyclerView recyclerView, View view) { 154 | int childCount = recyclerView.getChildCount(); 155 | int[] lvLocationOnScreen = new int[2]; 156 | int[] vLocationOnScreen = new int[2]; 157 | recyclerView.getLocationOnScreen(lvLocationOnScreen); 158 | int middleY = lvLocationOnScreen[1] + recyclerView.getHeight() / 2; 159 | if (childCount > 0) { 160 | view.getLocationOnScreen(vLocationOnScreen); 161 | if (vLocationOnScreen[1] <= middleY && vLocationOnScreen[1] + view.getHeight() >= middleY) { 162 | return true; 163 | } 164 | } 165 | 166 | return false; 167 | } 168 | 169 | //隐藏键盘 170 | public static void hideSoftInput(Context context, View view) { 171 | // Log.e(TAG, Log.getStackTraceString(new Exception("hideSoftInput"))); 172 | 173 | try { 174 | InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); 175 | imm.hideSoftInputFromWindow(view.getWindowToken(), 0); 176 | } catch (Exception e) { 177 | e.printStackTrace(); 178 | } 179 | } 180 | 181 | //显示键盘 182 | public static void showSoftInput(Context context, View view) { 183 | 184 | try { 185 | InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); 186 | // 如果输入法打开则关闭,如果没打开则打开 187 | imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS); 188 | imm.showSoftInput(view, InputMethodManager.SHOW_FORCED); 189 | } catch (Exception e) { 190 | e.printStackTrace(); 191 | } 192 | } 193 | 194 | /** 195 | * get the phone max textrure size (height) 196 | * caizhiming 197 | */ 198 | public static int getMaxTextureSize(Context context, int maxHeight){ 199 | if(maxHeight > 0 ){ 200 | return maxHeight; 201 | } 202 | int[] maxSize = new int[1]; 203 | try { 204 | ConfigurationInfo configurationInfo = ((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getDeviceConfigurationInfo(); 205 | int glesVersion = configurationInfo.reqGlEsVersion; 206 | if(Build.VERSION.SDK_INT >= 21) { 207 | //configureEGLContext 208 | EGLDisplay mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); 209 | if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) { 210 | throw new IllegalStateException("No EGL14 display"); 211 | } 212 | int[] version = new int[2]; 213 | if (!EGL14.eglInitialize(mEGLDisplay, version, /*offset*/ 0, version, /*offset*/ 1)) { 214 | throw new IllegalStateException("Cannot initialize EGL14"); 215 | } 216 | int[] attribList = { 217 | EGL14.EGL_RED_SIZE, 8, 218 | EGL14.EGL_GREEN_SIZE, 8, 219 | EGL14.EGL_BLUE_SIZE, 8, 220 | EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT, 221 | //EGL_RECORDABLE_ANDROID, 1, 222 | EGL14.EGL_SURFACE_TYPE, EGL14.EGL_PBUFFER_BIT | EGL14.EGL_WINDOW_BIT, 223 | EGL14.EGL_NONE 224 | }; 225 | EGLConfig[] configs = new EGLConfig[1]; 226 | int[] numConfigs = new int[1]; 227 | EGL14.eglChooseConfig(mEGLDisplay, attribList, /*offset*/ 0, configs, /*offset*/ 0, 228 | configs.length, numConfigs, /*offset*/ 0); 229 | if (EGL14.eglGetError() != EGL14.EGL_SUCCESS) { 230 | throw new IllegalStateException("eglCreateContext RGB888+recordable ES2" + ": EGL error: 0x" + Integer.toHexString(EGL14.eglGetError())); 231 | } 232 | int[] attrib_list = { 233 | EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, 234 | EGL14.EGL_NONE 235 | }; 236 | EGLContext mEGLContext = EGL14.eglCreateContext(mEGLDisplay, configs[0], EGL14.EGL_NO_CONTEXT, 237 | attrib_list, /*offset*/ 0); 238 | if (EGL14.eglGetError() != EGL14.EGL_SUCCESS) { 239 | throw new IllegalStateException("eglCreateContext" + ": EGL error: 0x" + Integer.toHexString(EGL14.eglGetError())); 240 | } 241 | if (mEGLContext == EGL14.EGL_NO_CONTEXT) { 242 | throw new IllegalStateException("No EGLContext could be made"); 243 | } 244 | int[] surfaceAttribs = { 245 | EGL14.EGL_WIDTH, 64, 246 | EGL14.EGL_HEIGHT, 64, 247 | EGL14.EGL_NONE 248 | }; 249 | EGLSurface surface = EGL14.eglCreatePbufferSurface(mEGLDisplay, configs[0], surfaceAttribs, 0); 250 | EGL14.eglMakeCurrent(mEGLDisplay, surface, surface, mEGLContext); 251 | //getMaxTextureSize 252 | if(glesVersion >= 0x20000) { 253 | GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, maxSize, 0); 254 | }else if(glesVersion >= 0x10000) { 255 | GLES10.glGetIntegerv(GLES10.GL_MAX_TEXTURE_SIZE, maxSize, 0); 256 | } 257 | //releaseEGLContext 258 | EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT); 259 | EGL14.eglDestroyContext(mEGLDisplay, mEGLContext); 260 | EGL14.eglReleaseThread(); 261 | EGL14.eglTerminate(mEGLDisplay); 262 | }else { 263 | if(glesVersion >= 0x20000) { 264 | GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, maxSize, 0); 265 | }else if(glesVersion >= 0x10000) { 266 | GLES10.glGetIntegerv(GLES10.GL_MAX_TEXTURE_SIZE, maxSize, 0); 267 | } 268 | } 269 | } catch (IllegalStateException e) { 270 | e.printStackTrace(); 271 | } 272 | maxHeight = maxSize[0] > 0 ? maxSize[0] : DEFAULT_MAX_BITMAP_DIMENSION; 273 | return maxHeight; 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_msg_red_dot.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jczmdeveloper/XCUpHideScrollView/767dddf2f7fa9febe4bab078d3272cfdb9f02750/app/src/main/res/drawable/bg_msg_red_dot.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon_back_orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jczmdeveloper/XCUpHideScrollView/767dddf2f7fa9febe4bab078d3272cfdb9f02750/app/src/main/res/drawable/icon_back_orange.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 14 | 15 | 20 | 21 | 29 | 30 | 31 | 32 | 38 | 39 | 43 | 52 | 65 | 66 | 67 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_viewpager_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 11 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_tab.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jczmdeveloper/XCUpHideScrollView/767dddf2f7fa9febe4bab078d3272cfdb9f02750/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jczmdeveloper/XCUpHideScrollView/767dddf2f7fa9febe4bab078d3272cfdb9f02750/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jczmdeveloper/XCUpHideScrollView/767dddf2f7fa9febe4bab078d3272cfdb9f02750/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jczmdeveloper/XCUpHideScrollView/767dddf2f7fa9febe4bab078d3272cfdb9f02750/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jczmdeveloper/XCUpHideScrollView/767dddf2f7fa9febe4bab078d3272cfdb9f02750/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jczmdeveloper/XCUpHideScrollView/767dddf2f7fa9febe4bab078d3272cfdb9f02750/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jczmdeveloper/XCUpHideScrollView/767dddf2f7fa9febe4bab078d3272cfdb9f02750/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jczmdeveloper/XCUpHideScrollView/767dddf2f7fa9febe4bab078d3272cfdb9f02750/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jczmdeveloper/XCUpHideScrollView/767dddf2f7fa9febe4bab078d3272cfdb9f02750/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jczmdeveloper/XCUpHideScrollView/767dddf2f7fa9febe4bab078d3272cfdb9f02750/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 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 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 279 | 280 | 281 | 282 | 283 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | XCUpHideScrollView 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/com/czm/main/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.czm.main; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.3.0' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jczmdeveloper/XCUpHideScrollView/767dddf2f7fa9febe4bab078d3272cfdb9f02750/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Apr 13 10:25:54 CST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /screenshots/01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jczmdeveloper/XCUpHideScrollView/767dddf2f7fa9febe4bab078d3272cfdb9f02750/screenshots/01.gif -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------