创建自定义ScrollView
/**
* ProjectName: yuanxinclan_new
* Author: lgq
* Date: 2017/12/20 0020 10:07
*/
public class StickyScrollView extends ScrollView {
/**
* Tag for views that should stick and have constant drawing. e.g.
* TextViews, ImageViews etc
*/
public static final String STICKY_TAG = "sticky";
/**
* Flag for views that should stick and have non-constant drawing. e.g.
* Buttons, ProgressBars etc
*/
public static final String FLAG_NONCONSTANT = "-nonconstant";
/**
* Flag for views that have aren't fully opaque
*/
public static final String FLAG_HASTRANSPARANCY = "-hastransparancy";
private ArrayList<View> stickyViews;
private View currentlyStickingView;
private float stickyViewTopOffset;
private boolean redirectTouchesToStickyView;
private boolean clippingToPadding;
private boolean clipToPaddingHasBeenSet;
private final Runnable invalidateRunnable = new Runnable() {
@Override
public void run() {
if (currentlyStickingView != null) {
int l = getLeftForViewRelativeOnlyChild(currentlyStickingView);
int t = getBottomForViewRelativeOnlyChild(currentlyStickingView);
int r = getRightForViewRelativeOnlyChild(currentlyStickingView);
int b = (int) (getScrollY() + (currentlyStickingView
.getHeight() + stickyViewTopOffset));
invalidate(l, t, r, b);
}
postDelayed(this, 16);
}
};
public StickyScrollView(Context context) {
this(context, null);
}
public StickyScrollView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.scrollViewStyle);
}
public StickyScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setup();
}
public void setup() {
stickyViews = new ArrayList<View>();
}
private int getLeftForViewRelativeOnlyChild(View v) {
int left = v.getLeft();
while (v.getParent() != getChildAt(0)) {
v = (View) v.getParent();
left += v.getLeft();
}
return left;
}
private int getTopForViewRelativeOnlyChild(View v) {
int top = v.getTop();
while (v.getParent() != getChildAt(0)) {
v = (View) v.getParent();
top += v.getTop();
}
return top;
}
private int getRightForViewRelativeOnlyChild(View v) {
int right = v.getRight();
while (v.getParent() != getChildAt(0)) {
v = (View) v.getParent();
right += v.getRight();
}
return right;
}
private int getBottomForViewRelativeOnlyChild(View v) {
int bottom = v.getBottom();
while (v.getParent() != getChildAt(0)) {
v = (View) v.getParent();
bottom += v.getBottom();
}
return bottom;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (!clipToPaddingHasBeenSet) {
clippingToPadding = true;
}
notifyHierarchyChanged();
}
@Override
public void setClipToPadding(boolean clipToPadding) {
super.setClipToPadding(clipToPadding);
clippingToPadding = clipToPadding;
clipToPaddingHasBeenSet = true;
}
@Override
public void addView(View child) {
super.addView(child);
findStickyViews(child);
}
@Override
public void addView(View child, int index) {
super.addView(child, index);
findStickyViews(child);
}
@Override
public void addView(View child, int index,
ViewGroup.LayoutParams params) {
super.addView(child, index, params);
findStickyViews(child);
}
@Override
public void addView(View child, int width, int height) {
super.addView(child, width, height);
findStickyViews(child);
}
@Override
public void addView(View child, ViewGroup.LayoutParams params) {
super.addView(child, params);
findStickyViews(child);
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (currentlyStickingView != null) {
canvas.save();
canvas.translate(getPaddingLeft(), getScrollY()
+ stickyViewTopOffset
+ (clippingToPadding ? getPaddingTop() : 0));
canvas.clipRect(0, (clippingToPadding ? -stickyViewTopOffset : 0),
getWidth(), currentlyStickingView.getHeight());
if (getStringTagForView(currentlyStickingView).contains(
FLAG_HASTRANSPARANCY)) {
showView(currentlyStickingView);
currentlyStickingView.draw(canvas);
hideView(currentlyStickingView);
} else {
currentlyStickingView.draw(canvas);
}
canvas.restore();
}
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
redirectTouchesToStickyView = true;
}
if (redirectTouchesToStickyView) {
redirectTouchesToStickyView = currentlyStickingView != null;
if (redirectTouchesToStickyView) {
redirectTouchesToStickyView = ev.getY() <= (currentlyStickingView
.getHeight() + stickyViewTopOffset)
&& ev.getX() >= getLeftForViewRelativeOnlyChild(currentlyStickingView)
&& ev.getX() <= getRightForViewRelativeOnlyChild(currentlyStickingView);
}
} else if (currentlyStickingView == null) {
redirectTouchesToStickyView = false;
}
if (redirectTouchesToStickyView) {
ev.offsetLocation(
0,
-1
* ((getScrollY() + stickyViewTopOffset) - getTopForViewRelativeOnlyChild(currentlyStickingView)));
}
return super.dispatchTouchEvent(ev);
}
private boolean hasNotDoneActionDown = true;
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (redirectTouchesToStickyView) {
ev.offsetLocation(
0,
((getScrollY() + stickyViewTopOffset) - getTopForViewRelativeOnlyChild(currentlyStickingView)));
}
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
hasNotDoneActionDown = false;
}
if (hasNotDoneActionDown) {
MotionEvent down = MotionEvent.obtain(ev);
down.setAction(MotionEvent.ACTION_DOWN);
super.onTouchEvent(down);
hasNotDoneActionDown = false;
}
if (ev.getAction() == MotionEvent.ACTION_UP
|| ev.getAction() == MotionEvent.ACTION_CANCEL) {
hasNotDoneActionDown = true;
}
return super.onTouchEvent(ev);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
doTheStickyThing();
}
private void doTheStickyThing() {
View viewThatShouldStick = null;
View approachingView = null;
for (View v : stickyViews) {
int viewTop = getTopForViewRelativeOnlyChild(v) - getScrollY()
+ (clippingToPadding ? 0 : getPaddingTop());
if (viewTop <= 0) {
if (viewThatShouldStick == null
|| viewTop > (getTopForViewRelativeOnlyChild(viewThatShouldStick)
- getScrollY() + (clippingToPadding ? 0
: getPaddingTop()))) {
viewThatShouldStick = v;
}
} else {
if (approachingView == null
|| viewTop < (getTopForViewRelativeOnlyChild(approachingView)
- getScrollY() + (clippingToPadding ? 0
: getPaddingTop()))) {
approachingView = v;
}
}
}
if (viewThatShouldStick != null) {
stickyViewTopOffset = approachingView == null ? 0 : Math.min(0,
getTopForViewRelativeOnlyChild(approachingView)
- getScrollY()
+ (clippingToPadding ? 0 : getPaddingTop())
- viewThatShouldStick.getHeight());
if (viewThatShouldStick != currentlyStickingView) {
if (currentlyStickingView != null) {
stopStickingCurrentlyStickingView();
}
startStickingView(viewThatShouldStick);
}
} else if (currentlyStickingView != null) {
stopStickingCurrentlyStickingView();
}
}
private void startStickingView(View viewThatShouldStick) {
currentlyStickingView = viewThatShouldStick;
if (getStringTagForView(currentlyStickingView).contains(
FLAG_HASTRANSPARANCY)) {
hideView(currentlyStickingView);
}
if (((String) currentlyStickingView.getTag())
.contains(FLAG_NONCONSTANT)) {
post(invalidateRunnable);
}
}
private void stopStickingCurrentlyStickingView() {
if (getStringTagForView(currentlyStickingView).contains(
FLAG_HASTRANSPARANCY)) {
showView(currentlyStickingView);
}
currentlyStickingView = null;
removeCallbacks(invalidateRunnable);
}
/**
* Notify that the sticky attribute has been added or removed from one or
* more views in the View hierarchy
*/
public void notifyStickyAttributeChanged() {
notifyHierarchyChanged();
}
private void notifyHierarchyChanged() {
if (currentlyStickingView != null) {
stopStickingCurrentlyStickingView();
}
stickyViews.clear();
findStickyViews(getChildAt(0));
doTheStickyThing();
invalidate();
}
private void findStickyViews(View v) {
if (v instanceof ViewGroup) {
ViewGroup vg = (ViewGroup) v;
for (int i = 0; i < vg.getChildCount(); i++) {
String tag = getStringTagForView(vg.getChildAt(i));
if (tag != null && tag.contains(STICKY_TAG)) {
stickyViews.add(vg.getChildAt(i));
} else if (vg.getChildAt(i) instanceof ViewGroup) {
findStickyViews(vg.getChildAt(i));
}
}
} else {
String tag = (String) v.getTag();
if (tag != null && tag.contains(STICKY_TAG)) {
stickyViews.add(v);
}
}
}
private String getStringTagForView(View v) {
Object tagObject = v.getTag();
return String.valueOf(tagObject);
}
private void hideView(View v) {
// if (Build.VERSION.SDK_INT >= 11) {
// v.setAlpha(0);
// } else {
AlphaAnimation anim = new AlphaAnimation(1, 0);
anim.setDuration(0);
anim.setFillAfter(true);
v.startAnimation(anim);
// }
}
private void showView(View v) {
// if (Build.VERSION.SDK_INT >= 11) {
// v.setAlpha(1);
// } else {
AlphaAnimation anim = new AlphaAnimation(0, 1);
anim.setDuration(0);
anim.setFillAfter(true);
v.startAnimation(anim);
// }
}
}
使用自定义scrollView 在scrollView中给任一View添加属性 android:tag="sticky"即可。该View滑动到顶部时即固定
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/gray_b7">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="44dp"
android:background="@color/businesstop"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/activity_business_district_library_left_layout"
android:layout_width="70dp"
android:layout_height="match_parent"
android:layout_marginLeft="9dp"
android:gravity="center_vertical">
<ImageView
android:layout_width="25dp"
android:layout_height="25dp"
android:src="@drawable/ease_mm_title_back"
/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="商圈"
android:textColor="@color/white"
android:textSize="18sp"/>
<LinearLayout
android:id="@+id/activity_business_district_library_right_layout"
android:layout_width="50dp"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:gravity="center_vertical|right"
android:visibility="gone"
android:paddingRight="12dp"
>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/enterprise_list_nav_icon_search"
/>
</LinearLayout>
</RelativeLayout>
<com.yuanxin.clan.mvp.view.PullToRefreshView
android:layout_below="@+id/myre"
android:id="@+id/p2rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.yuanxin.clan.core.util.StickyScrollView
android:id="@+id/slv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/gray_b7"
android:fillViewport="false">
<LinearLayout
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.bigkoo.convenientbanner.ConvenientBanner
android:id="@+id/bannerTop"
android:layout_width="match_parent"
android:layout_height="175dp"
android:background="@drawable/banner01"
app:image_scale_type="center_crop"
app:indicator_drawable_selected="@drawable/banner_iocn_pre"
app:indicator_drawable_unselected="@drawable/banner_iocn_nomal"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:gravity="center_vertical"
android:background="@color/white"
android:orientation="horizontal">
<LinearLayout
android:layout_width="48dp"
android:layout_marginLeft="12dp"
android:layout_height="match_parent"
android:gravity="center_vertical">
<ImageView
android:id="@+id/imageView6"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/business_list_voice"/>
</LinearLayout>
<com.yuanxin.clan.core.adapter.verticalRollingTextView.VerticalRollingTextView
android:id="@+id/noticeBoard"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_marginRight="12dp"
android:textColor="@color/login_black"
android:textSize="12sp"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="10dp"
android:background="@color/gray_b7"></LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:orientation="horizontal"
android:background="@color/white"
android:weightSum="4">
<LinearLayout
android:id="@+id/shanghuili"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="49dp"
android:layout_height="49dp"
android:src="@drawable/business_icon"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/login_black"
android:textSize="14dp"
android:text="商会"
android:layout_marginTop="8dp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/xiehuili"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="49dp"
android:layout_height="49dp"
android:src="@drawable/business_siehui"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/login_black"
android:textSize="14dp"
android:text="协会"
android:layout_marginTop="8dp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/quanzili"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="49dp"
android:layout_height="49dp"
android:src="@drawable/business_list_quanzi"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/login_black"
android:textSize="14dp"
android:text="圈子"
android:layout_marginTop="8dp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/yuanquli"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="49dp"
android:layout_height="49dp"
android:src="@drawable/business_list_yuanqu"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/login_black"
android:textSize="14dp"
android:text="园区"
android:layout_marginTop="8dp"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="10dp"
android:background="@color/gray_b7"></LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="49dp"
android:background="@color/white"
android:layout_alignParentTop="true"
android:tag="sticky"
>
<TextView
android:id="@+id/activity_business_district_library_area"
android:layout_width="wrap_content"
android:layout_height="49dp"
android:layout_centerVertical="true"
android:drawablePadding="4dp"
android:drawableRight="@drawable/arrow_down"
android:gravity="center_vertical"
android:paddingLeft="20dp"
android:text="区域"
android:textColor="@color/common_register_black"
android:textSize="14sp"/>
<TextView
android:id="@+id/activity_business_district_library_industry"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:drawablePadding="4dp"
android:drawableRight="@drawable/arrow_down"
android:text="行业"
android:textColor="@color/common_register_black"
android:textSize="14sp"/>
<TextView
android:id="@+id/activity_business_district_library_shangxi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="4dp"
android:drawableRight="@drawable/arrow_down"
android:text="商系"
android:textColor="@color/common_register_black"
android:textSize="14sp"
android:layout_alignBaseline="@+id/activity_business_district_library_industry"
android:layout_alignBottom="@+id/activity_business_district_library_industry"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_marginRight="19dp"
android:layout_marginEnd="19dp"/>
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/gray_b7"></LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/activity_business_district_library_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">
</android.support.v7.widget.RecyclerView>
<!--<TextView-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="0.5dp"-->
<!--android:layout_marginTop="5dp"-->
<!--android:layout_marginBottom="5dp"-->
<!--android:background="@color/gray_white"/>-->
<!--<TextView-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="1dp"-->
<!--android:background="@drawable/line"/>-->
</LinearLayout>
</com.yuanxin.clan.core.util.StickyScrollView>
</com.yuanxin.clan.mvp.view.PullToRefreshView>
</LinearLayout>
附加PullToRefreshView
public class PullToRefreshView extends LinearLayout {
private static final int REFRESHING_TYPE_HEADER = 1;
private static final int REFRESHING_TYPE_FOOTER = 2;
private int nRefreshingType = 0;
// refresh states
private static final int PULL_TO_REFRESH = 2;
private static final int RELEASE_TO_REFRESH = 3;
private static final int REFRESHING = 4;
// pull state
private static final int PULL_UP_STATE = 0;
private static final int PULL_DOWN_STATE = 1;
private boolean enablePullTorefresh = true;
private boolean enablePullLoadMoreDataStatus = true;
/**
* last y
*/
private int mLastMotionY;
/**
* last x
*/
private int mLastMotionX;
/**
* lock
*/
private boolean mLock;
/**
* header view
*/
private View mHeaderView;
/**
* footer view
*/
private View mFooterView;
/**
* list or grid
*/
private AdapterView<?> mAdapterView;
/**
* scrollview
*/
private ScrollView mScrollView;
/**
* header view height
*/
private int mHeaderViewHeight;
/**
* footer view height
*/
private int mFooterViewHeight;
/**
* header view image
*/
private ImageView mHeaderImageView;
/**
* footer view image
*/
private ImageView mFooterImageView;
/**
* header tip text
*/
private TextView mHeaderTextView;
/**
* footer tip text
*/
private TextView mFooterTextView;
/**
* header refresh time
*/
private TextView mHeaderUpdateTextView;
/**
* footer refresh time
*/
// private TextView mFooterUpdateTextView;
/**
* header progress bar
*/
private ProgressBar mHeaderProgressBar;
/**
* footer progress bar
*/
private ProgressBar mFooterProgressBar;
/**
* layout inflater
*/
private LayoutInflater mInflater;
/**
* header view current state
*/
private int mHeaderState;
/**
* footer view current state
*/
private int mFooterState;
/**
* pull state,pull up or pull down;PULL_UP_STATE or PULL_DOWN_STATE
*/
private int mPullState;
/**
* 变为向下的箭头,改变箭头方向
*/
private RotateAnimation mFlipAnimation;
/**
* 变为逆向的箭头,旋转
*/
private RotateAnimation mReverseFlipAnimation;
/**
* footer refresh listener
*/
private OnFooterRefreshListener mOnFooterRefreshListener;
/**
* footer refresh listener
*/
private OnHeaderRefreshListener mOnHeaderRefreshListener;
/**
* last update time
*/
private Context context;
public PullToRefreshView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
init();
}
public PullToRefreshView(Context context) {
super(context);
this.context = context;
init();
}
/**
* init
*
* @description
*/
private void init() {
// Load all of the animations we need in code rather than through XML
mFlipAnimation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
mFlipAnimation.setInterpolator(new LinearInterpolator());
mFlipAnimation.setDuration(100);
mFlipAnimation.setFillAfter(true);
mReverseFlipAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
mReverseFlipAnimation.setInterpolator(new LinearInterpolator());
mReverseFlipAnimation.setDuration(100);
mReverseFlipAnimation.setFillAfter(true);
mInflater = LayoutInflater.from(getContext());
// header view 在此添加,保证是第一个添加到linearlayout的最上端
addHeaderView();
}
private void addHeaderView() {
// header view
mHeaderView = mInflater.inflate(R.layout.refresh_header, this, false);
mHeaderImageView = (ImageView) mHeaderView.findViewById(R.id.pull_to_refresh_image);
mHeaderTextView = (TextView) mHeaderView.findViewById(R.id.pull_to_refresh_text);
mHeaderUpdateTextView = (TextView) mHeaderView.findViewById(R.id.pull_to_refresh_updated_at);
mHeaderProgressBar = (ProgressBar) mHeaderView.findViewById(R.id.pull_to_refresh_progress);
// header layout
measureView(mHeaderView);
mHeaderViewHeight = mHeaderView.getMeasuredHeight();
LinearLayout.LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
// 设置topMargin的值为负的header View高度,即将其隐藏在最上方
params.topMargin = -(mHeaderViewHeight);
mHeaderView.setLayoutParams(params);
addView(mHeaderView, params);
}
public void setBarColor(int nColor) {
mHeaderView.setBackgroundColor(nColor);
mFooterView.setBackgroundColor(nColor);
}
private void addFooterView() {
// footer view
mFooterView = mInflater.inflate(R.layout.refresh_footer, this, false);
mFooterImageView = (ImageView) mFooterView.findViewById(R.id.pull_to_load_image);
mFooterTextView = (TextView) mFooterView.findViewById(R.id.pull_to_load_text);
mFooterProgressBar = (ProgressBar) mFooterView.findViewById(R.id.pull_to_load_progress);
// footer layout
measureView(mFooterView);
mFooterViewHeight = mFooterView.getMeasuredHeight();
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mFooterViewHeight);
// int top = getHeight();
// params.topMargin
// =getHeight();//在这里getHeight()==0,但在onInterceptTouchEvent()方法里getHeight()已经有值了,不再是0;
// getHeight()什么时候会赋值,稍候再研究一下
// 由于是线性布局可以直接添加,只要AdapterView的高度是MATCH_PARENT,那么footer view就会被添加到最后,并隐藏
addView(mFooterView, params);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
// footer view 在此添加保证添加到linearlayout中的最后
addFooterView();
initContentAdapterView();
}
/**
* init AdapterView like ListView,GridView and so on;or init ScrollView
*/
private void initContentAdapterView() {
int count = getChildCount();
if (count < 3) {
throw new IllegalArgumentException(
"this layout must contain 3 child views,and AdapterView or ScrollView must in the second position!");
}
View view = null;
for (int i = 0; i < count - 1; ++i) {
view = getChildAt(i);
if (view instanceof AdapterView<?>) {
mAdapterView = (AdapterView<?>) view;
}
if (view instanceof ScrollView) {
// finish later
mScrollView = (ScrollView) view;
}
}
if (mAdapterView == null && mScrollView == null) {
throw new IllegalArgumentException(
"must contain a AdapterView or ScrollView in this layout!");
}
}
private void measureView(View child) {
ViewGroup.LayoutParams p = child.getLayoutParams();
if (p == null) {
p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);
int lpHeight = p.height;
int childHeightSpec;
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
MeasureSpec.EXACTLY);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(0,
MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
int y = (int) e.getRawY();
int x = (int) e.getRawX();
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
// 首先拦截down事件,记录y坐标
mLastMotionY = y;
mLastMotionX = x;
break;
case MotionEvent.ACTION_MOVE:
// deltaY > 0 是向下运动,< 0是向上运动
int deltaY = y - mLastMotionY;
int deltaX = x - mLastMotionX;
if (Math.abs(deltaY) > Math.abs(deltaX) * 1.5
&& isRefreshViewScroll(deltaY)) {
return true;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
break;
}
return false;
}
/*
* 如果在onInterceptTouchEvent()方法中没有拦截(即onInterceptTouchEvent()方法中 return
* false)则由PullToRefreshView 的子View来处理;否则由下面的方法来处理(即由PullToRefreshView自己来处理)
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mLock) {
return true;
}
int y = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// onInterceptTouchEvent已经记录
// mLastMotionY = y;
break;
case MotionEvent.ACTION_MOVE:
int deltaY = y - mLastMotionY;
if (mPullState == PULL_DOWN_STATE) {
// PullToRefreshView执行下拉
headerPrepareToRefresh(deltaY);
// setHeaderPadding(-mHeaderViewHeight);
} else if (mPullState == PULL_UP_STATE) {
// PullToRefreshView执行上拉
footerPrepareToRefresh(deltaY);
}
mLastMotionY = y;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
int topMargin = getHeaderTopMargin();
if (mPullState == PULL_DOWN_STATE) {
if (topMargin >= 0) {
// 开始刷新
headerRefreshing();
} else {
// 还没有执行刷新,重新隐藏
setHeaderTopMargin(-mHeaderViewHeight);
}
} else if (mPullState == PULL_UP_STATE) {
if (Math.abs(topMargin) >= mHeaderViewHeight
+ mFooterViewHeight) {
// 开始执行footer 刷新
footerRefreshing();
} else {
// 还没有执行刷新,重新隐藏
setHeaderTopMargin(-mHeaderViewHeight);
}
}
break;
}
return super.onTouchEvent(event);
}
/**
* 是否应该到了父View,即PullToRefreshView滑动
*
* @param deltaY , deltaY > 0 是向下运动,< 0是向上运动
* @return
*/
private boolean isRefreshViewScroll(int deltaY) {
if (mHeaderState == REFRESHING || mFooterState == REFRESHING) {
return false;
}
// 对于ListView和GridView
if (mAdapterView != null) {
// 子view(ListView or GridView)滑动到最顶端
if (deltaY > 0) {
// 判断是否禁用下拉刷新操作
if (!enablePullTorefresh) {
return false;
}
View child = mAdapterView.getChildAt(0);
if (child == null) {
// 如果mAdapterView中没有数据,不拦截
mPullState = PULL_DOWN_STATE;
return true;
}
if (mAdapterView.getFirstVisiblePosition() == 0
&& child.getTop() == 0) {
mPullState = PULL_DOWN_STATE;
return true;
}
int top = child.getTop();
int padding = mAdapterView.getPaddingTop();
if (mAdapterView.getFirstVisiblePosition() == 0
&& Math.abs(top - padding) <= 11) {// 这里之前用3可以判断,但现在不行,还没找到原因
mPullState = PULL_DOWN_STATE;
return true;
}
} else if (deltaY < 0) {
// 判断是否禁用上拉加载更多操作
if (!enablePullLoadMoreDataStatus) {
return false;
}
View lastChild = mAdapterView.getChildAt(mAdapterView
.getChildCount() - 1);
if (lastChild == null) {
// 如果mAdapterView中没有数据,不拦截
return false;
}
// 最后一个子view的Bottom小于父View的高度说明mAdapterView的数据没有填满父view,
// 等于父View的高度说明mAdapterView已经滑动到最后
if (lastChild.getBottom() <= getHeight()
&& mAdapterView.getLastVisiblePosition() == mAdapterView
.getCount() - 1) {
mPullState = PULL_UP_STATE;
return true;
}
}
}
// 对于ScrollView
if (mScrollView != null) {
// 子scroll view滑动到最顶端
View child = mScrollView.getChildAt(0);
if (deltaY > 0 && mScrollView.getScrollY() == 0) {
if (!enablePullTorefresh) {
return false;
}
mPullState = PULL_DOWN_STATE;
return true;
} else if (deltaY < 0
&& child.getMeasuredHeight() <= getHeight()
+ mScrollView.getScrollY()) {
if (!enablePullLoadMoreDataStatus) {
return false;
}
mPullState = PULL_UP_STATE;
return true;
}
}
return false;
}
/**
* header 准备刷新,手指移动过程,还没有释放
*
* @param deltaY ,手指滑动的距离
*/
private void headerPrepareToRefresh(int deltaY) {
int newTopMargin = changingHeaderViewTopMargin(deltaY, 0.3f);
// 当header view的topMargin>=0时,说明已经完全显示出来了,修改header view 的提示状态
if (newTopMargin >= 0 && mHeaderState != RELEASE_TO_REFRESH) {
mHeaderTextView.setText(R.string.pull_to_refresh_release_label);
mHeaderUpdateTextView.setVisibility(View.GONE);
mHeaderImageView.clearAnimation();
mHeaderImageView.startAnimation(mFlipAnimation);
mHeaderState = RELEASE_TO_REFRESH;
} else if (newTopMargin < 0 && newTopMargin > -mHeaderViewHeight) {// 拖动时没有释放
mHeaderImageView.clearAnimation();
mHeaderImageView.startAnimation(mFlipAnimation);
mHeaderUpdateTextView.setVisibility(View.GONE);
// mHeaderImageView.
mHeaderTextView.setText(R.string.pull_to_refresh_pull_label);
mHeaderState = PULL_TO_REFRESH;
}
}
/**
* footer 准备刷新,手指移动过程,还没有释放 移动footer view高度同样和移动header view
* 高度是一样,都是通过修改header view的topmargin的值来达到
*
* @param deltaY ,手指滑动的距离
*/
private void footerPrepareToRefresh(int deltaY) {
int newTopMargin = changingHeaderViewTopMargin(deltaY, 1.0f);
// 如果header view topMargin 的绝对值大于或等于header + footer 的高度
// 说明footer view 完全显示出来了,修改footer view 的提示状态
if (Math.abs(newTopMargin) >= (mHeaderViewHeight + mFooterViewHeight)
&& mFooterState != RELEASE_TO_REFRESH) {
mFooterTextView
.setText(R.string.pull_to_refresh_footer_release_label);
mFooterImageView.clearAnimation();
mFooterImageView.startAnimation(mFlipAnimation);
mFooterState = RELEASE_TO_REFRESH;
} else if (Math.abs(newTopMargin) < (mHeaderViewHeight + mFooterViewHeight)) {
mFooterImageView.clearAnimation();
mFooterImageView.startAnimation(mFlipAnimation);
mFooterTextView.setText(R.string.pull_to_refresh_footer_pull_label);
mFooterState = PULL_TO_REFRESH;
}
}
/**
* 修改Header view top margin的值
*
* @param deltaY
* @description
*/
private int changingHeaderViewTopMargin(int deltaY, float percentage) {
LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams();
float newTopMargin = params.topMargin + deltaY * percentage;
// 这里对上拉做一下限制,因为当前上拉后然后不释放手指直接下拉,会把下拉刷新给触发了,感谢网友yufengzungzhe的指出
// 表示如果是在上拉后一段距离,然后直接下拉
if (deltaY > 0 && mPullState == PULL_UP_STATE && Math.abs(params.topMargin) <= mHeaderViewHeight) {
return params.topMargin;
}
// 同样地,对下拉做一下限制,避免出现跟上拉操作时一样的bug
if (deltaY < 0 && mPullState == PULL_DOWN_STATE && Math.abs(params.topMargin) >= mHeaderViewHeight) {
return params.topMargin;
}
params.topMargin = (int) newTopMargin;
mHeaderView.setLayoutParams(params);
invalidate();
return params.topMargin;
}
/**
* header refreshing
*/
public void headerRefreshing() {
mHeaderState = REFRESHING;
setHeaderTopMargin(0);
mHeaderImageView.setVisibility(View.GONE);
mHeaderImageView.clearAnimation();
mHeaderImageView.setImageDrawable(null);
mHeaderProgressBar.setVisibility(View.VISIBLE);
mHeaderTextView.setText(R.string.pull_to_refresh_refreshing_label);
if (!TextUtils.isEmpty(mHeaderUpdateTextView.getText().toString().trim()))
mHeaderUpdateTextView.setVisibility(View.VISIBLE);
if (mOnHeaderRefreshListener != null) {
mOnHeaderRefreshListener.onHeaderRefresh(this);
}
nRefreshingType = REFRESHING_TYPE_HEADER;
}
/**
* footer refreshing
*/
private void footerRefreshing() {
mFooterState = REFRESHING;
int top = mHeaderViewHeight + mFooterViewHeight;
setHeaderTopMargin(-top);
mFooterImageView.setVisibility(View.GONE);
mFooterImageView.clearAnimation();
mFooterImageView.setImageDrawable(null);
mFooterProgressBar.setVisibility(View.VISIBLE);
mFooterTextView
.setText(R.string.pull_to_refresh_footer_refreshing_label);
if (mOnFooterRefreshListener != null) {
mOnFooterRefreshListener.onFooterRefresh(this);
}
nRefreshingType = REFRESHING_TYPE_FOOTER;
}
/**
* 设置header view 的topMargin的值
*
* @param topMargin ,为0时,说明header view 刚好完全显示出来; 为-mHeaderViewHeight时,说明完全隐藏了
* @description
*/
private void setHeaderTopMargin(int topMargin) {
LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams();
params.topMargin = topMargin;
mHeaderView.setLayoutParams(params);
invalidate();
}
/**
* header view 完成更新后恢复初始状态
*/
private void onHeaderRefreshComplete() {
setHeaderTopMargin(-mHeaderViewHeight);
mHeaderImageView.setVisibility(View.VISIBLE);
mHeaderImageView.setImageResource(R.drawable.ic_pulltorefresh_arrow);
mHeaderTextView.setText(R.string.pull_to_refresh_pull_label);
mHeaderProgressBar.setVisibility(View.GONE);
mHeaderState = PULL_TO_REFRESH;
long between = Calendar.getInstance().getTimeInMillis() - System.currentTimeMillis();
setLastUpdated(String.format(context
.getString(R.string.pull_to_refresh_refresh_time_label), new SimpleDateFormat((between >= 86400000 ? "MM-dd" : "HH:mm")).format(System.currentTimeMillis())));
}
/**
* Resets the list to a normal state after a refresh.
*
* @param lastUpdated Last updated at.
*/
public void onHeaderRefreshComplete(CharSequence lastUpdated) {
setLastUpdated(lastUpdated);
onHeaderRefreshComplete();
}
/**
* footer view 完成更新后恢复初始状态
*/
private void onFooterRefreshComplete() {
setHeaderTopMargin(-mHeaderViewHeight);
mFooterImageView.setVisibility(View.VISIBLE);
mFooterImageView.setImageResource(R.drawable.ic_pulltorefresh_arrow_up);
mFooterTextView.setText(R.string.pull_to_refresh_footer_pull_label);
mFooterProgressBar.setVisibility(View.GONE);
// mHeaderUpdateTextView.setText("");
mFooterState = PULL_TO_REFRESH;
}
/**
* footer view 完成更新后恢复初始状态
*/
public void onFooterRefreshComplete(int size) {
if (size > 0) {
mFooterView.setVisibility(View.VISIBLE);
} else {
mFooterView.setVisibility(View.GONE);
}
setHeaderTopMargin(-mHeaderViewHeight);
mFooterImageView.setVisibility(View.VISIBLE);
mFooterImageView.setImageResource(R.drawable.ic_pulltorefresh_arrow_up);
mFooterTextView.setText(R.string.pull_to_refresh_footer_pull_label);
mFooterProgressBar.setVisibility(View.GONE);
// mHeaderUpdateTextView.setText("");
mFooterState = PULL_TO_REFRESH;
}
/**
* 完成更新后恢复初始状态
*/
public void setRefreshComplete() {
switch (nRefreshingType) {
case REFRESHING_TYPE_HEADER:
onHeaderRefreshComplete();
break;
case REFRESHING_TYPE_FOOTER:
onFooterRefreshComplete();
break;
default:
break;
}
}
/**
* Set a text to represent when the list was last updated.
*
* @param lastUpdated Last updated at.
*/
public void setLastUpdated(CharSequence lastUpdated) {
if (lastUpdated != null) {
mHeaderUpdateTextView.setVisibility(View.VISIBLE);
mHeaderUpdateTextView.setText(lastUpdated);
} else {
mHeaderUpdateTextView.setVisibility(View.GONE);
}
}
/**
* 获取当前header view 的topMargin
*
* @description
*/
private int getHeaderTopMargin() {
LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams();
return params.topMargin;
}
// /**
// * lock
// *
// */
// private void lock() {
// mLock = true;
// }
//
// /**
// * unlock
// *
// */
// private void unlock() {
// mLock = false;
// }
/**
* set headerRefreshListener
*
* @param headerRefreshListener
* @description
*/
public void setOnHeaderRefreshListener(
OnHeaderRefreshListener headerRefreshListener) {
mOnHeaderRefreshListener = headerRefreshListener;
}
public void setOnFooterRefreshListener(
OnFooterRefreshListener footerRefreshListener) {
mOnFooterRefreshListener = footerRefreshListener;
}
/**
* Interface definition for a callback to be invoked when list/grid footer
* view should be refreshed.
*/
public interface OnFooterRefreshListener {
public void onFooterRefresh(PullToRefreshView view);
}
/**
* Interface definition for a callback to be invoked when list/grid header
* view should be refreshed.
*/
public interface OnHeaderRefreshListener {
public void onHeaderRefresh(PullToRefreshView view);
}
public boolean isEnablePullTorefresh() {
return enablePullTorefresh;
}
public void setEnablePullTorefresh(boolean enablePullTorefresh) {
this.enablePullTorefresh = enablePullTorefresh;
}
public boolean isEnablePullLoadMoreDataStatus() {
return enablePullLoadMoreDataStatus;
}
public void setEnablePullLoadMoreDataStatus(
boolean enablePullLoadMoreDataStatus) {
this.enablePullLoadMoreDataStatus = enablePullLoadMoreDataStatus;
}
}
在fragment使用完整Class
public class GongYinFragment extends BaseFragment implements PullToRefreshView.OnFooterRefreshListener,PullToRefreshView.OnHeaderRefreshListener{
@BindView(R.id.fragment_my_all_crowd_funding_recycler_view)
RecyclerView fragmentMyAllCrowdFundingRecyclerView;
@BindView(R.id.p2rv)
PullToRefreshView p2rv;
@BindView(R.id.sosli)
LinearLayout sosli;
@BindView(R.id.noticeBoard)
MarqueeView noticeBoard;
@BindView(R.id.kongli)
LinearLayout kongli;
private List<GongXuEntity> mGongXuEntities = new ArrayList<>();
private AllGongXuAdapter adapter;
private SubscriberOnNextListener getBusinessSearchListOnNextListener;
private IntentFilter intentFilter;
private LocalBroadcastManager localBroadcastManager;
private int ab = 1,pageCount;// 当前页面,从0开始计数
private String detail;
public Unbinder unbinder;
private More_LoadDialog mMore_loadDialog;
private List<HomePageAnnouncementEntity> mStrings=new ArrayList<>();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public int getViewLayout() {
return R.layout.allgongxufragmentla;
}
@Override
protected void initView(Bundle savedInstanceState) {
initRecyclerView();
mMore_loadDialog = new More_LoadDialog(getContext());
// sosli.setVisibility(View.GONE);
getMyBusinessDistrict(1);
initNoticeBoard();
p2rv.setOnFooterRefreshListener(this);
p2rv.setOnHeaderRefreshListener(this);
}
private void initNoticeBoard() {
String url = Url.homePageAnnouncement;
RequestParams params = new RequestParams();
/*1:首页广告位 2:供需成功案例*/
params.put("announcementType", 2);
doHttpGet(url, params, new RequestCallback(){
@Override
public void onFailure(int i, Header[] headers, String s, Throwable throwable) {
// Toasty.error(getActivity(), "网络连接异常", Toast.LENGTH_SHORT, true).show();
}
@Override
public void onSuccess(int i, Header[] headers, String s) {
try {
// Log.v("Lgq","w d z HomeFragment===="+s);
JSONObject object = new JSONObject(s);
if (object.getString("success").equals("true")) {
mStrings.addAll(FastJsonUtils.getObjectsList(object.getString("data"), HomePageAnnouncementEntity.class));
ArrayList<String> notices = new ArrayList<String>();
for (HomePageAnnouncementEntity str: mStrings) {
notices.add(str.getAnnouncementTitle());
}
noticeBoard.startWithList(notices, R.anim.anim_bottom_in, R.anim.anim_top_out);
noticeBoard.setOnItemClickListener(new MarqueeView.OnItemClickListener() {
@Override
public void onItemClick(int position, TextView textView) {
String url = mStrings.get(position).getAnnouncementContent();
if (url.startsWith("http")) {
startActivity(new Intent(getActivity(), HomeADactivity.class).putExtra("url", url));
}
}
});
}
} catch (JSONException e) {
// Toast.makeText(getActivity(), "数据解析出错", Toast.LENGTH_SHORT).show();
Logger.d("json 解析出错");
}
}
});
}
private void getMyBusinessDistrict(int pageNumber) {
String url = Url.getgongxu;
RequestParams params = new RequestParams();
mMore_loadDialog.show();
params.put("pageNumber", pageNumber);
params.put("supplyDemand", 0);
params.put("status", 1);
doHttpGet(url, params, new RequestCallback() {
@Override
public void onFailure(int i, Header[] headers, String s, Throwable throwable) {
Toast.makeText(getContext(), "网络连接异常", Toast.LENGTH_SHORT).show();
mMore_loadDialog.dismiss();
p2rv.setRefreshComplete();
}
@Override
public void onSuccess(int i, Header[] headers, String s) {
mMore_loadDialog.dismiss();
p2rv.setRefreshComplete();
try {
JSONObject object = new JSONObject(s);
pageCount = object.getInt("pageCount");
if (object.getString("success").equals("true")) {
JSONArray jsonArray = object.getJSONArray("data");
if (jsonArray.length()==0){
kongli.setVisibility(View.VISIBLE);
}
for (int a = 0; a < jsonArray.length(); a++) {
JSONObject businessObject = jsonArray.getJSONObject(a);
String supplyDemandId = businessObject.getString("supplyDemandId");//商圈id
String image1 = businessObject.getString("image1");//图片
String image11 = Url.img_domain + image1+Url.imageStyle640x640;
String image2 = businessObject.getString("image2");//图片
String image22 = Url.img_domain + image2+Url.imageStyle640x640;
String image3 = businessObject.getString("image3");//图片
String image33 = Url.img_domain + image3+Url.imageStyle640x640;
String content = businessObject.getString("content");//商圈名称
String createDt = businessObject.getString("createDt");
String epId = businessObject.getString("epId");
String supplyDemand = businessObject.getString("supplyDemand");
String userId = businessObject.getString("userId");
String title = businessObject.getString("title");
String address = businessObject.getString("address");
JSONObject twoob=new JSONObject(address);
String city = twoob.getString("city");
// Log.v("Lgq","....... " +image11+" ... "+image22+" 。。。 "+image33);
GongXuEntity entity = new GongXuEntity();
entity.setImage1(TextUtil.isEmpty(image1)?image1:image11);
entity.setImage2(TextUtil.isEmpty(image2)?image2:image22);
entity.setImage3(TextUtil.isEmpty(image3)?image3:image33);
entity.setContent(content);
entity.setCreateDt(createDt);
entity.setEpId(epId);
entity.setSupplyDemandId(supplyDemandId);
entity.setSupplyDemand(supplyDemand);
entity.setUserId(userId);
entity.setTitle(title);
entity.setCity(city);
mGongXuEntities.add(entity);
}
adapter.notifyDataSetChanged();
} else {
Toast.makeText(getContext(), object.getString("msg"), Toast.LENGTH_SHORT).show();
}
} catch (JSONException e) {
// Toast.makeText(getContext(), "数据解析出错", Toast.LENGTH_SHORT).show();
Logger.e("数据解析出错");
}
}
});
sosli.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (! UserNative.readIsLogin()){
toLogin();
return;
}
startActivity(new Intent(getActivity(), GongxuSOS_Activity.class).putExtra("supplyDemand", 0));
}
});
}
private void initRecyclerView() {
adapter = new AllGongXuAdapter(getContext(), mGongXuEntities);
adapter.setOnItemClickListener(new AllGongXuAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
// 未登陆要求登陆
if (! UserNative.readIsLogin()){
toLogin();
return;
}
String link = Url.urlWeb+"/market-supply_demand-info¶m="+mGongXuEntities.get(position).getSupplyDemandId()+"&appFlg=0";
Intent intent = new Intent(getContext(), GongXuDetailActivity.class);//商圈详情
intent.putExtra("url", link);
intent.putExtra("title", mGongXuEntities.get(position).getTitle());
startActivity(intent);
}
});
fragmentMyAllCrowdFundingRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
fragmentMyAllCrowdFundingRecyclerView.setAdapter(adapter);
fragmentMyAllCrowdFundingRecyclerView.setFocusable(false);//导航栏切换不再focuse
fragmentMyAllCrowdFundingRecyclerView.setNestedScrollingEnabled(false);//禁止滑动
}
@Override
public void onFooterRefresh(PullToRefreshView view) {
ab++;
if (ab> pageCount) {
p2rv.onFooterRefreshComplete(1);
Toast.makeText(getContext(), "没有更多数据", Toast.LENGTH_SHORT).show();
return;
}
getMyBusinessDistrict(ab);
}
@Override
public void onHeaderRefresh(PullToRefreshView view) {
mGongXuEntities.clear();
ab = 1;
getMyBusinessDistrict(ab);
}
@Override
public void onDestroyView() {
super.onDestroyView();
// unbinder.unbind();
}
}