In Android how to synchronize scrollview with different scrolling speeds? - android

I have some dependent scrollview means (when I scroll one view others will also scroll). I am able to do it properly, but now I want to manage the speed of scroll means (when I scroll my scrollview1 than scrollview2 should scroll +10 and scrollview3 should scroll +20 or whatever speed) same for other (scrollview2, and scrollview3) also.
I check there is a method called scrollview.scrollto(x,y). Which used to manage the scroll but when i increase scollto(x, y+scrollviews(i).getSpeed()) than it gives me stackOverflow exception.
I am attaching my code please look into this and give me some suggestion how can solve this problem.
My custom scrollView class is:
public class CustomVerticalObserveScroll extends ScrollView {
private GestureDetector mGestureDetector;
View.OnTouchListener mGestureListener;
public CustomVerticalObserveScroll(Context context, AttributeSet attrs) {
super(context, attrs);
mGestureDetector = new GestureDetector(context, new YScrollDetector());
setFadingEdgeLength(0);
// TODO Auto-generated constructor stub
}
private CustomScrollLisner scrollViewListener = null;
public CustomVerticalObserveScroll(Context context) {
super(context);
mGestureDetector = new GestureDetector(context, new YScrollDetector());
setFadingEdgeLength(0);
}
public CustomVerticalObserveScroll(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
mGestureDetector = new GestureDetector(context, new YScrollDetector());
setFadingEdgeLength(0);
}
public void setScrollViewListener(CustomScrollLisner scrollViewListener) {
this.scrollViewListener = scrollViewListener;
}
#Override
protected void onScrollChanged(int x, int y, int oldx, int oldy) {
super.onScrollChanged(x, y, oldx, oldy);
if (scrollViewListener != null) {
scrollViewListener.onScrollChanged(this, x, y, oldx, oldy);
}
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return super.onInterceptTouchEvent(ev)
&& mGestureDetector.onTouchEvent(ev);
}
// Return false if we're scrolling in the x direction
class YScrollDetector extends SimpleOnGestureListener {
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
if (Math.abs(distanceY) > Math.abs(distanceX)) {
return true;
}
if (Math.abs(distanceX) > Math.abs(distanceY)) {
return true;
}
return false;
}
}
}
and this code I am using to make scroll dependent scroll views.
public class RelativePanoFeature implements IFeaturetype, OnTouchListener {
private String type;
private FeatureCordinates locationCordinates;
private int mOrientation;
private String image;
private FeatureCordinates triggerCordinates;
private String scrollDirection;
private String scrollSpeed;
private String scrollHandler;
CustomVerticalObserveScroll vertical_scroll;
CustomHorizontalObserveScroll horizontal_scroll;
RelativeLayout vsChild;
long timeonDown, timeonUp;
Thread t;
Handler mhandler;
float downx, downy;
int touchId;
public static int scrollid = 0;
public static ArrayList<RelativePanoHandler> storePanoHandler = new ArrayList<RelativePanoHandler>();
public RelativePanoFeature(String type) {
this.type = type;
}
#Override
public void setType(String type) {
this.type = type;
}
#Override
public String getType() {
return type;
}
public void setImage(String image) {
this.image = image;
}
public String getImage() {
return image;
}
public FeatureCordinates getLocation() {
return locationCordinates;
}
public void setLocation(FeatureCordinates featureCordinates) {
this.locationCordinates = featureCordinates;
}
public void setOrientation(int mOrientation) {
this.mOrientation = mOrientation;
}
public int getOrientation() {
return mOrientation;
}
public FeatureCordinates getTrigger() {
return triggerCordinates;
}
public void setTrigger(FeatureCordinates trigger) {
this.triggerCordinates = trigger;
}
public void setScrollDirection(String scrollDirection) {
this.scrollDirection = scrollDirection;
}
public String getScrollDirection() {
return scrollDirection;
}
public void setScrollSpeed(String scrollSpeed) {
this.scrollSpeed = scrollSpeed;
}
public String getScrollSpeed() {
return scrollSpeed;
}
public void setScrollHandler(String scrollHandler) {
this.scrollHandler = scrollHandler;
}
public String getScrollHandler() {
return scrollHandler;
}
public void setTouchId(int touchid) {
this.touchId = touchid;
}
public int getTOuchId() {
return touchId;
}
/* function to draw relative pano */
public void drawRelativePano(final Context con,
final RelativeLayout parent, final Handler handle) {
/* splitting the path from images key in the string */
RelativePanoHandler panHandler = new RelativePanoHandler();
final int height;
final int width;
vsChild = new RelativeLayout(con);
mhandler = handle;
/* giving size of of vertical scroll's child */
LayoutParams imageViewLayoutParams = new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
vsChild.setLayoutParams(imageViewLayoutParams);
/* splitting the path from images key in the string */
String path[] = getImage().split("images");
try {
/* Initialise loader to load the image inside child */
BackgroundImageLoader loader = new BackgroundImageLoader(vsChild,
Property.FILEPATH + path[1], con);
try {
loader.execute();
} catch (IllegalStateException e) {
e.printStackTrace();
}
/* getting height and width of image from loader object */
height = loader.get().getHeight();
width = loader.get().getWidth();
/*
* condition for putting the child view in vertical scroll and
* implementing the multi directional scroll for event pano
*/
int locWidth = getLocation().getWidth(), locHeight = getLocation()
.getHeight();
System.out.println("Width= " + width + " Location width= "
+ locWidth);
System.out.println("Heoght= " + height + " Location Height= "
+ locHeight
);
if (width > (getLocation().getWidth())
|| height > (getLocation().getHeight())) {
vertical_scroll = new CustomVerticalObserveScroll(con);
horizontal_scroll = new CustomHorizontalObserveScroll(con);
vertical_scroll.setFillViewport(true);
horizontal_scroll.setFillViewport(true);
vertical_scroll.setId(scrollid);
horizontal_scroll.setFadingEdgeLength(0);
/*
* adding the soft later on vertical and horizontal scroll if
* the detected device is on api level 10 or more than that
*/
if (Build.VERSION.SDK_INT > 10) {
vertical_scroll
.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
horizontal_scroll.setLayerType(View.LAYER_TYPE_SOFTWARE,
null);
}
vsChild.setEnabled(true);
/*
* parameters for setting the height and width of vertical
* scroll
*/
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
getLocation().getWidth(), getLocation().getHeight());
params.leftMargin = getLocation().getX();
params.topMargin = getLocation().getY();
vertical_scroll.setLayoutParams(params);
/* adding vertical scroll child this child will hold the image */
vertical_scroll.addView(vsChild, width, height);
horizontal_scroll.setLayoutParams(params);
/*
* adding vertical scroll as a child of horizontal scroll for
* multidirectional scrolling
*/
horizontal_scroll.addView(vertical_scroll);
/*
* at last add this horizontal scroll in side parent which will
* hold the multidirectional scroll
*/
parent.setTag(getScrollHandler());
parent.addView(horizontal_scroll);
// vertical_scroll.setId(id)
panHandler.setVerticalScroll(vertical_scroll);
panHandler.setHandlerTag(getScrollHandler());
panHandler.setPanoSpeed(Integer.parseInt(getScrollSpeed()));
storePanoHandler.add(panHandler);
int size = storePanoHandler.size();
System.out.println("Vertical Scroll objec size=" + size);
}
System.out.println("TAg= " + parent.getTag());
String scdir = getScrollDirection();
System.out.println("Scroll Directoion= " + scdir);
scrollid++;
if (getScrollDirection().equalsIgnoreCase("Y")) {
vertical_scroll.setScrollViewListener(new CustomScrollLisner() {
#Override
public void onScrollChanged(
CustomHorizontalObserveScroll scrollView, int x,
int y, int oldx, int oldy) {
}
#Override
public void onScrollChanged(
CustomVerticalObserveScroll scrollView, int x,
int y, int oldx, int oldy) {
if (scrollView == storePanoHandler.get(getTOuchId())
.getVerticalScroll()) {
for (int i = 0; i < storePanoHandler.size(); i++) {
storePanoHandler.get(i).getVerticalScroll()
.scrollTo(x, y);
storePanoHandler.get(i).getVerticalScroll().
// storePanoHandler.
// .get(i)
// .getVerticalScroll()
// .scrollTo(
// x,
// oldy
// + storePanoHandler.get(
// i)
// .getPanoSpeed());
}
}
}
});
}
// if (getScrollDirection().equalsIgnoreCase("X")) {
// vertical_scroll.setScrollViewListener(new CustomScrollLisner() {
//
// #Override
// public void onScrollChanged(
// CustomHorizontalObserveScroll scrollView, int x,
// int y, int oldx, int oldy) {
// // if (scrollView == storePanoHandler.get(getTOuchId())
// // .getVerticalScroll()) {
// //
// // for (int i = 0; i < storePanoHandler.size(); i++) {
// // storePanoHandler.get(i).getVerticalScroll()
// // .smoothScrollTo(x, y);
// //
// // }
// // }
// }
//
// #Override
// public void onScrollChanged(
// CustomVerticalObserveScroll scrollView, int x,
// int y, int oldx, int oldy) {
// }
// });
// }
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
/*
* set touch listeners on vertical and horizontal scrolls it will use to
* disable the scroll for it's parent like [image or view pager when
* user interacting with any of custom scroll]
*/
horizontal_scroll.setOnTouchListener(this);
vertical_scroll.setOnTouchListener(this);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
boolean scrollingPanaroma = true;
// changing token value for getting scroll
if (v == vertical_scroll || v == horizontal_scroll) {
/*
* Disabling the parent control [list, pager] when user interacting
* with multidirectional scroll
*/
System.out.println("Pano touch Id= " + vertical_scroll.getId());
setTouchId(vertical_scroll.getId());
if (scrollingPanaroma == true) {
v.getParent().getParent().getParent()
.requestDisallowInterceptTouchEvent(true);
}
/*
* enable the parent control [list, pager] when user done with
* multidirectional scroll
*/
else {
v.getParent().getParent().getParent()
.requestDisallowInterceptTouchEvent(false);
}
}
return false;
}
}
Please help me to solve this out because I am really stucked at this point. Thnaks.

Here is the code I used to slow down the scroll speed of ScrollView programmatically,
ObjectAnimator anim = ObjectAnimator.ofInt(mScrollView, "scrollY", mScrollView.getBottom());
anim.setDuration(9000);
anim.start();
mScrollView - Your ScrollView
mScrollView = (ScrollView) findViewById(R.id.scrollView1);
anima.setDuration(int Value) - greater the value, slower the scroll
I used the code block in Switch Button OnCheckedChangedListener.

Related

AutoScroll Horizontally (Right to Left) in Android Recyclerview using UniformSpeedInterpolator OR AutoScroll RecyclerView

I have a RecyclerView with a HORIZONTAL orientation. I want to scroll RecyclerView automatically from Right to Left.
also, I need below options
should scroll in an infinite loop
support touch while auto-scroll
support reverse auto-scroll (Left to Right)
should work in all Layout manager (LinearLayoutManager, GridLayoutManager, StaggeredGridLayoutManager)
Finally, I found a solution to the above question with all the options.
For start Autoscrolling
recyclerView.startAutoScroll();
For infinite loop
recyclerView.setLoopEnabled(true);
For touch
recyclerView.setCanTouch(true);
For pause Autoscrolling
recyclerView.pauseAutoScroll(true);
It will work with all Layout manager (LinearLayoutManager, GridLayoutManager, StaggeredGridLayoutManager)
AutoScrollRecyclerView
public class AutoScrollRecyclerView extends RecyclerView {
private static final String TAG = AutoScrollRecyclerView.class.getSimpleName();
private static final int SPEED = 10;
/**
* Sliding estimator
*/
private UniformSpeedInterpolator mInterpolator;
/**
* Dx and dy between units
*/
private int mSpeedDx, mSpeedDy;
/**
* Sliding speed, default 100
*/
private int mCurrentSpeed = SPEED;
/**
* Whether to display the list infinitely
*/
private boolean mLoopEnabled;
/**
* Whether to slide backwards
*/
private boolean mReverse;
/**
* Whether to turn on automatic sliding
*/
private boolean mIsOpenAuto;
/**
* Whether the user can manually slide the screen
*/
private boolean mCanTouch = true;
/**
* Whether the user clicks on the screen
*/
private boolean mPointTouch;
/**
* Are you ready for data?
*/
private boolean mReady;
/**
* Whether initialization is complete
*/
private boolean mInflate;
/**
* Whether to stop scroll
*/
private boolean isStopAutoScroll = false;
public AutoScrollRecyclerView(Context context) {
this(context, null);
}
public AutoScrollRecyclerView(Context context, #Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public AutoScrollRecyclerView(Context context, #Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mInterpolator = new UniformSpeedInterpolator();
mReady = false;
}
/**
* Start sliding
*/
public void startAutoScroll() {
isStopAutoScroll = false;
openAutoScroll(mCurrentSpeed, false);
}
/**
* Start sliding
*
* #param speed Sliding distance (determining the sliding speed)
* #param reverse Whether to slide backwards
*/
public void openAutoScroll(int speed, boolean reverse) {
mReverse = reverse;
mCurrentSpeed = speed;
mIsOpenAuto = true;
notifyLayoutManager();
startScroll();
}
/**
* Is it possible to manually slide when swiping automatically?
*/
public void setCanTouch(boolean b) {
mCanTouch = b;
}
public boolean canTouch() {
return mCanTouch;
}
/**
* Set whether to display the list infinitely
*/
public void setLoopEnabled(boolean loopEnabled) {
this.mLoopEnabled = loopEnabled;
if (getAdapter() != null) {
getAdapter().notifyDataSetChanged();
startScroll();
}
}
/**
* Whether to slide infinitely
*/
public boolean isLoopEnabled() {
return mLoopEnabled;
}
/**
* Set whether to reverse
*/
public void setReverse(boolean reverse) {
mReverse = reverse;
notifyLayoutManager();
startScroll();
}
/**
* #param isStopAutoScroll
*/
public void pauseAutoScroll(boolean isStopAutoScroll) {
this.isStopAutoScroll = isStopAutoScroll;
}
public boolean getReverse() {
return mReverse;
}
/**
* Start scrolling
*/
private void startScroll() {
if (!mIsOpenAuto)
return;
if (getScrollState() == SCROLL_STATE_SETTLING)
return;
if (mInflate && mReady) {
mSpeedDx = mSpeedDy = 0;
smoothScroll();
}
}
private void smoothScroll() {
if (!isStopAutoScroll) {
int absSpeed = Math.abs(mCurrentSpeed);
int d = mReverse ? -absSpeed : absSpeed;
smoothScrollBy(d, d, mInterpolator);
}
}
private void notifyLayoutManager() {
LayoutManager layoutManager = getLayoutManager();
if (layoutManager instanceof LinearLayoutManager) {
LinearLayoutManager linearLayoutManager = ((LinearLayoutManager) layoutManager);
if (linearLayoutManager != null) {
linearLayoutManager.setReverseLayout(mReverse);
}
} else {
StaggeredGridLayoutManager staggeredGridLayoutManager = ((StaggeredGridLayoutManager) layoutManager);
if (staggeredGridLayoutManager != null) {
staggeredGridLayoutManager.setReverseLayout(mReverse);
}
}
}
#Override
public void swapAdapter(Adapter adapter, boolean removeAndRecycleExistingViews) {
super.swapAdapter(generateAdapter(adapter), removeAndRecycleExistingViews);
mReady = true;
}
#Override
public void setAdapter(Adapter adapter) {
super.setAdapter(generateAdapter(adapter));
mReady = true;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent e) {
if (mCanTouch) {
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
mPointTouch = true;
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (mIsOpenAuto) {
return true;
}
}
return super.onInterceptTouchEvent(e);
} else return true;
}
#Override
public boolean onTouchEvent(MotionEvent e) {
if (mCanTouch) {
switch (e.getAction()) {
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (mIsOpenAuto) {
mPointTouch = false;
smoothScroll();
return true;
}
}
return super.onTouchEvent(e);
} else return true;
}
#Override
public boolean performClick() {
return super.performClick();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
startScroll();
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
mInflate = true;
}
#Override
public void onScrolled(int dx, int dy) {
if (mPointTouch) {
mSpeedDx = 0;
mSpeedDy = 0;
return;
}
boolean vertical;
if (dx == 0) {//Vertical scrolling
mSpeedDy += dy;
vertical = true;
} else {//Horizontal scrolling
mSpeedDx += dx;
vertical = false;
}
if (vertical) {
if (Math.abs(mSpeedDy) >= Math.abs(mCurrentSpeed)) {
mSpeedDy = 0;
smoothScroll();
}
} else {
if (Math.abs(mSpeedDx) >= Math.abs(mCurrentSpeed)) {
mSpeedDx = 0;
smoothScroll();
}
}
}
#NonNull
#SuppressWarnings("unchecked")
private NestingRecyclerViewAdapter generateAdapter(Adapter adapter) {
return new NestingRecyclerViewAdapter(this, adapter);
}
/**
* Custom estimator
* Swipe the list at a constant speed
*/
private static class UniformSpeedInterpolator implements Interpolator {
#Override
public float getInterpolation(float input) {
return input;
}
}
/**
* Customize the Adapter container so that the list can be displayed in an infinite loop
*/
private static class NestingRecyclerViewAdapter<VH extends RecyclerView.ViewHolder>
extends RecyclerView.Adapter<VH> {
private AutoScrollRecyclerView mRecyclerView;
RecyclerView.Adapter<VH> mAdapter;
NestingRecyclerViewAdapter(AutoScrollRecyclerView recyclerView, RecyclerView.Adapter<VH> adapter) {
mAdapter = adapter;
mRecyclerView = recyclerView;
}
#NonNull
#Override
public VH onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return mAdapter.onCreateViewHolder(parent, viewType);
}
#Override
public void registerAdapterDataObserver(#NonNull RecyclerView.AdapterDataObserver observer) {
super.registerAdapterDataObserver(observer);
mAdapter.registerAdapterDataObserver(observer);
}
#Override
public void unregisterAdapterDataObserver(#NonNull RecyclerView.AdapterDataObserver observer) {
super.unregisterAdapterDataObserver(observer);
mAdapter.unregisterAdapterDataObserver(observer);
}
#Override
public void onBindViewHolder(#NonNull VH holder, int position) {
mAdapter.onBindViewHolder(holder, generatePosition(position));
}
#Override
public void setHasStableIds(boolean hasStableIds) {
super.setHasStableIds(hasStableIds);
mAdapter.setHasStableIds(hasStableIds);
}
#Override
public int getItemCount() {
//If it is an infinite scroll mode, set an unlimited number of items
return getLoopEnable() ? Integer.MAX_VALUE : mAdapter.getItemCount();
}
#Override
public int getItemViewType(int position) {
return mAdapter.getItemViewType(generatePosition(position));
}
#Override
public long getItemId(int position) {
return mAdapter.getItemId(generatePosition(position));
}
/**
* Returns the corresponding position according to the current scroll mode
*/
private int generatePosition(int position) {
if (getLoopEnable()) {
return getActualPosition(position);
} else {
return position;
}
}
/**
* Returns the actual position of the item
*
* #param position The position after starting to scroll will grow indefinitely
* #return Item actual location
*/
private int getActualPosition(int position) {
int itemCount = mAdapter.getItemCount();
return position >= itemCount ? position % itemCount : position;
}
private boolean getLoopEnable() {
return mRecyclerView.mLoopEnabled;
}
public boolean getReverse() {
return mRecyclerView.mReverse;
}
}
}

LinearLayout addView doesn't work

I put addView() in onTouchEvent() method,but it doesn't work. What's the problem? When I put the addView in the construction function it works properly.
onTouchEvent() works properly. The main problem is the new addview doesn't visible. But it really added to the parent view.
setOrientation(LinearLayout.VERTICAL) is already added in the construction function.
This is the code:
public class RecyclerViewRefresh extends LinearLayout{
private static final String LOG_TAG=RecyclerViewRefresh.class.getSimpleName();
private static final int INVALID_POINTER=-1;
//Default offset in dips from the top of the view to where the progress
//spinner should stop
private static final int DEFAULT_CIRCLE_TARGET=64;
private static final float DRAG_RATE=.5f;
private Context context;
private View headerView,footerView,thisView;
private View mTarget; //the target of the gesture
private ImageView arrowIv;
private TextView refreshTv;
private ProgressBar progressBar,footerProgressBar;
private OnPullToRefresh refreshListener=null;
private OnDragToLoad loadListener=null;
float startY=0;
private int headerHeight=0,currentHeaderHeight=0,currentFooterHeight=0;
private boolean mReturningToStart;
private boolean mRefreshing=false;
private boolean mNestedScrollInProgress;
private int mCurrentTargetOffsetTop;
protected int mOriginalOffsetTop;
private boolean mIsBeingDragged;
private boolean mIsBeingPullUp;
private boolean isAddFooter=false;
private int mActivePointerId=INVALID_POINTER;
private float mInitailDownY;
private int mTouchSlop;
private float mTotalDragDistance=-1;
private float mInitialMotionY;
private float mSpinnerFinalOffset;
private boolean updateHeader=true;
private Handler handler=new Handler();
private Timer timer;
public RecyclerViewRefresh(Context context) {
super(context);
initView(context);
}
public RecyclerViewRefresh(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public RecyclerViewRefresh(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
private void initView(Context context)
{
this.setOrientation(LinearLayout.VERTICAL);
this.context=context;
thisView=this;
mTouchSlop= ViewConfiguration.get(context).getScaledTouchSlop();
headerView=LayoutInflater.from(context).inflate(R.layout.header_layout,null);
footerView=LayoutInflater.from(context).inflate(R.layout.footer_layout,null);
measureView(headerView);
measureView(footerView);
arrowIv=(ImageView)headerView.findViewById(R.id.arrow);
refreshTv=(TextView)headerView.findViewById(R.id.tip);
progressBar=(ProgressBar)headerView.findViewById(R.id.progress);
headerHeight=headerView.getMeasuredHeight();
currentHeaderHeight=headerHeight;
LinearLayout.LayoutParams lp=new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
headerView.getMeasuredHeight());
this.addView(headerView,lp);
setTopHeader(headerHeight);
final DisplayMetrics metrics=getResources().getDisplayMetrics();
mSpinnerFinalOffset=DEFAULT_CIRCLE_TARGET*metrics.density;
mTotalDragDistance=mSpinnerFinalOffset;
}
/**
* 通知父布局,占用的宽,高;
*
* #param view
*/
private void measureView(View view) {
ViewGroup.LayoutParams p = view.getLayoutParams();
if (p == null) {
p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
int width = ViewGroup.getChildMeasureSpec(0, 0, p.width);
int height;
int tempHeight = p.height;
if (tempHeight > 0) {
height = MeasureSpec.makeMeasureSpec(tempHeight,
MeasureSpec.EXACTLY);
} else {
height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
}
view.measure(width, height);
}
private void setTopHeader(int height)
{
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB)
{
this.setY(-height);
}else{
LayoutParams lp=new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,height);
lp.topMargin=-height;
this.setLayoutParams(lp);
}
headerView.invalidate();
}
/**
* Set the listener to be notified when a refresh is triggered via the
* pull gesture.
* #param listener
*/
public void setOnPullToRefresh(OnPullToRefresh listener)
{
this.refreshListener=listener;
}
/**
* Set the listener to be notified when a load is triggered via the
* drag gesture
* #param listener
*/
public void setOnDragToLoad(OnDragToLoad listener)
{
this.loadListener=listener;
}
private void ensureTarget(){
if(mTarget==null){
for(int i=0;i<getChildCount();i++)
{
View child=getChildAt(i);
if(child instanceof RecyclerView)
{
mTarget=child;
break;
}
}
}
}
/**
* #return Whether it is possible for the child view of this layout to
* scroll up.Override this if the child view is a custom view.
*/
public boolean canChildScrollUp(){
if(mTarget==null)
{
ensureTarget();
}
if(Build.VERSION.SDK_INT<14)
{
if(mTarget instanceof AbsListView)
{
final AbsListView absListView=(AbsListView)mTarget;
return absListView.getChildCount()>0
&&(absListView.getFirstVisiblePosition()>0
||absListView.getChildAt(0).getTop()<absListView.getPaddingTop());
}else{
return ViewCompat.canScrollVertically(mTarget,-1)|| mTarget.getScrollY()>0;
}
}else{
return ViewCompat.canScrollVertically(mTarget,-1);
}
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
ensureTarget();
final int action=MotionEventCompat.getActionMasked(ev);
if(mReturningToStart && action == MotionEvent.ACTION_DOWN){
mReturningToStart = false;
}
if(!isEnabled() || mReturningToStart || (canChildScrollUp()&&!ifLastItemVisible())
||mRefreshing || mNestedScrollInProgress){
return false;
}
switch (action){
case MotionEvent.ACTION_DOWN:
setTargetOffsetTopAndBottom(mOriginalOffsetTop-headerView.getTop(),true);
mActivePointerId=MotionEventCompat.getPointerId(ev,0);
mIsBeingDragged=false;
mIsBeingPullUp=false;
final float initialDownY=getMotionEventY(ev,mActivePointerId);
if(initialDownY==-1){
return false;
}
mInitailDownY=initialDownY;
updateHeader=true;
break;
case MotionEvent.ACTION_MOVE:
if(mActivePointerId==INVALID_POINTER){
Log.e(LOG_TAG, "Got ACTION_MOVE event but don't have an active pointer id.");
return false;
}
final float y=getMotionEventY(ev,mActivePointerId);
if(y==-1){
return false;
}
final float yDiff=y-mInitailDownY;
if(yDiff>mTouchSlop && !mIsBeingDragged){
mInitialMotionY=mInitailDownY+mTouchSlop;
mIsBeingDragged=true;
}
if(yDiff<-mTouchSlop&&!mIsBeingPullUp&&ifLastItemVisible()&&!isAddFooter)
{
Log.d(LOG_TAG,"pullUp");
mInitialMotionY=mInitailDownY+mTouchSlop;
mIsBeingPullUp=true;
return true;
}
if(ifLastItemVisible()&&yDiff>mTouchSlop)
{
isAddFooter=false;
return false;
}
break;
case MotionEventCompat.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mIsBeingDragged=false;
mActivePointerId=INVALID_POINTER;
break;
}
return mIsBeingDragged;
}
private boolean ifLastItemVisible()
{
final RecyclerView recyclerView=(RecyclerView)mTarget;
LinearLayoutManager manager=(LinearLayoutManager)recyclerView.getLayoutManager();
if((manager.findLastVisibleItemPosition()+1)==manager.getItemCount())
{
return true;
}
return false;
}
private float getMotionEventY(MotionEvent ev,int activePointerId){
final int index=MotionEventCompat.findPointerIndex(ev,activePointerId);
if(index<0){
return -1;
}
return MotionEventCompat.getY(ev,index);
}
private void setTargetOffsetTopAndBottom(int offset,boolean requiresUpdate){
if(currentHeaderHeight>-5)
{
currentHeaderHeight-=offset;
this.setY(-currentHeaderHeight);
mCurrentTargetOffsetTop=this.getTop();
if(requiresUpdate && Build.VERSION.SDK_INT<11){
invalidate();
}
if(currentHeaderHeight<0)
{
if(updateHeader){
updateHeader=false;
refreshTv.setText(getResources().getText(R.string.releasetorefresh));
RotateAnimation animation=new RotateAnimation(0,180,
Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
animation.setDuration(800);
animation.setFillAfter(true);
arrowIv.startAnimation(animation);
}
Log.d(LOG_TAG,"top="+this.getY());
}
}
}
private void onSecondaryPointerUp(MotionEvent ev){
final int pointerIndex=MotionEventCompat.getActionIndex(ev);
final int pointerId=MotionEventCompat.getPointerId(ev,pointerIndex);
if(pointerId==mActivePointerId){
//This was our active pointer going up. Choose a new
//active pointer and adjust accordingly.
final int newPointerIndex=pointerIndex==0?1:0;
mActivePointerId=MotionEventCompat.getPointerId(ev,newPointerIndex);
}
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
final int action=MotionEventCompat.getActionMasked(event);
int pointerIndex=-1;
if(mReturningToStart&&action==MotionEvent.ACTION_DOWN){
mReturningToStart=false;
}
if(!isEnabled() || mReturningToStart
|| (canChildScrollUp()&&!ifLastItemVisible()) || mNestedScrollInProgress){
//Fail fast if we're not in a state where a swipe is possible
return false;
}
switch(action){
case MotionEvent.ACTION_DOWN:
mActivePointerId=MotionEventCompat.getPointerId(event,0);
mIsBeingDragged=false;
break;
case MotionEvent.ACTION_MOVE:{
pointerIndex=MotionEventCompat.findPointerIndex(event,mActivePointerId);
if(pointerIndex<0){
Log.e(LOG_TAG, "Got ACTION_MOVE event but have an invalid active pointer id.");
return false;
}
final float y=MotionEventCompat.getY(event,pointerIndex);
final float overscrollTop=(y-mInitialMotionY)*DRAG_RATE;
Log.d(LOG_TAG,"move overscroll="+overscrollTop+" y="+y+" mInitialMotionY="+mInitialMotionY+" mIsBeingDragged="+(mIsBeingDragged?"true":"false")
+" mIsBeingPullUp="+(mIsBeingPullUp?"true":"false"));
if(mIsBeingDragged){
if(overscrollTop>0){
moveSpinner(overscrollTop);
}else{
return false;
}
}
if(mIsBeingPullUp&&!isAddFooter){
Log.d(LOG_TAG,"isAddFooter="+(isAddFooter?"true":"false"));
if(overscrollTop<0&&!isAddFooter){
isAddFooter=true;
LinearLayout.LayoutParams lp=new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
footerView.getMeasuredHeight());
Log.d(LOG_TAG,"addFooterView height="+footerView.getMeasuredHeight()
+" childcount="+this.getChildCount());
if(this.getChildCount()==2)
{
this.addView(footerView,lp);
footerView.setVisibility(View.VISIBLE);
invalidate();
}
Log.d(LOG_TAG,"childcount="+this.getChildCount());
}else{
return false;
}
}
break;
}
case MotionEventCompat.ACTION_POINTER_DOWN:{
pointerIndex=MotionEventCompat.getActionIndex(event);
if(pointerIndex<0){
Log.e(LOG_TAG, "Got ACTION_POINTER_DOWN event but have an invalid action index.");
return false;
}
mActivePointerId=MotionEventCompat.getPointerId(event,pointerIndex);
break;
}
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(event);
break;
case MotionEvent.ACTION_UP:{
pointerIndex=MotionEventCompat.findPointerIndex(event,mActivePointerId);
if(pointerIndex<0){
Log.e(LOG_TAG, "Got ACTION_UP event but don't have an active pointer id.");
return false;
}
final float y=MotionEventCompat.getY(event,pointerIndex);
mIsBeingDragged=false;
finishSpinner();
mActivePointerId=INVALID_POINTER;
return false;
}
case MotionEvent.ACTION_CANCEL:
return false;
}
return true;
}
private void moveSpinner(float overscrollTop){
float originalDragPercent=overscrollTop/mTotalDragDistance;
float dragPercent=Math.min(1f,Math.abs(originalDragPercent));
float adjustedPercent=(float)Math.max(dragPercent-.4,0)*5/3;
float extraOS=Math.abs(overscrollTop)-mTotalDragDistance;
float slingshotDist=mSpinnerFinalOffset;
float tensionSlingshotPercent=Math.max(0,Math.min(extraOS,slingshotDist*2)/slingshotDist);
float tensionPercent=(float)((tensionSlingshotPercent/4)-Math.pow(
(tensionSlingshotPercent/4),2))*2f;
float extraMove=(slingshotDist)*tensionPercent*2;
int targetY=mOriginalOffsetTop+(int)((slingshotDist*dragPercent)+extraMove);
setTargetOffsetTopAndBottom(targetY-mCurrentTargetOffsetTop,true);
}
private void finishSpinner(){
if(currentHeaderHeight<0){
setRefreshing(true,true);
}else{
//cancel refresh
mRefreshing=false;
animateOffsetToStartPosition();
}
}
private void setRefreshing(boolean refreshing,final boolean notify)
{
if(mRefreshing!=refreshing){
ensureTarget();
mRefreshing=refreshing;
if(mRefreshing){
refreshListener.onRefresh();
arrowIv.setVisibility(View.GONE);
arrowIv.clearAnimation();
progressBar.setVisibility(View.VISIBLE);
}else{
arrowIv.setVisibility(View.GONE);
progressBar.setVisibility(View.GONE);
refreshTv.setText(getResources().getText(R.string.afterrefresh));
animateOffsetToStartPosition();
}
}
}
public void setRefreshing(boolean refreshing){
if(!refreshing){
setRefreshing(refreshing,false);
}
}
private void animateOffsetToStartPosition(){
refreshTv.setText(getResources().getText(R.string.pulltorefresh));
arrowIv.clearAnimation();
if(timer==null&&currentHeaderHeight<headerHeight)
{
timer=new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
#Override
public void run() {
if(currentHeaderHeight<headerHeight)
{
currentHeaderHeight+=5;
thisView.setY(-currentHeaderHeight);
mCurrentTargetOffsetTop = headerView.getTop();
if ( Build.VERSION.SDK_INT < 11) {
invalidate();
}
}else{
if(timer!=null)
{
arrowIv.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
timer.cancel();
timer=null;
}
}
}
});
}
},10,10);
}
}
/**
* Classes that wish to be notified when the pull gesture correctly
* triggers a refresh should implement this interface.
*/
public interface OnPullToRefresh{
public void onRefresh();
}
/**
* Classes that wish to be notified when the drag gesture correctly
* triggers a load should implement this interface.
*/
public interface OnDragToLoad{
public void onLoad();
}}
If you're sure the view is added but it's not visible, make sure you have set the orientation of your LinearLayout. The default orientation is horizontal and maybe the view is added to the side of your existing views and is not visible. You can set it to vertical orientation by using:
myLayout.setOrientation(LinearLayout.VERTICAL);
Put your linear layout inside scroll view.
You need to implement View.OnTouchListener. Just modify your code like below :
public class RecyclerViewRefresh extends LinearLayout implements View.OnTouchListener
{
#Override
public boolean onTouchEvent(MotionEvent event)
{
......
measureView(footerView);
footerView.setVisibility(View.VISIBLE);
thisView.addView(footerView,lp);
invalidate();
.....
}
}
Try calling invalidate(); after addView();

LinearLayout scroll to the top

I write a RecyclerViewRefresh follow SwipeRefreshLayout.class. When I pull the view until it doesn't move and then release,the view reset to the original. The issue is that view should trigger Timer and then that Timer reset the view. I couldn't find the reason.
Please tell me why offsetTopAndBottom() can make the view automatically back to the original place. Thanks.
I use setY() to solve this problem. But I also want to know why. And I read the offsetTopAndBottom()'s source,also can not find any clue.
RecyclerViewRefresh's code:
public class RecyclerViewRefresh extends LinearLayout {
private static final String LOG_TAG=RecyclerViewRefresh.class.getSimpleName();
private static final int INVALID_POINTER=-1;
//Default offset in dips from the top of the view to where the progress
//spinner should stop
private static final int DEFAULT_CIRCLE_TARGET=64;
private static final float DRAG_RATE=.5f;
private View headerView,footerView,thisView;
private View mTarget; //the target of the gesture
private ImageView arrowIv;
private TextView refreshTv;
private ProgressBar progressBar;
private OnPullToRefresh refreshListener=null;
private OnDragToLoad loadListener=null;
float startY=0;
private int headerHeight=0;
private boolean mReturningToStart;
private boolean mRefreshing=false;
private boolean mNestedScrollInProgress;
private int mCurrentTargetOffsetTop;
protected int mOriginalOffsetTop;
private boolean mIsBeingDragged;
private int mActivePointerId=INVALID_POINTER;
private float mInitailDownY;
private int mTouchSlop;
private float mTotalDragDistance=-1;
private float mInitialMotionY;
private float mSpinnerFinalOffset;
private boolean updateHeader=true;
private Handler handler=new Handler();
private Timer timer;
public RecyclerViewRefresh(Context context) {
super(context);
initView(context);
}
public RecyclerViewRefresh(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public RecyclerViewRefresh(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
private void initView(Context context)
{
thisView=this;
mTouchSlop= ViewConfiguration.get(context).getScaledTouchSlop();
headerView=LayoutInflater.from(context).inflate(R.layout.header_layout,null);
footerView=LayoutInflater.from(context).inflate(R.layout.header_layout,null);
measureView(headerView);
arrowIv=(ImageView)headerView.findViewById(R.id.arrow);
refreshTv=(TextView)headerView.findViewById(R.id.tip);
progressBar=(ProgressBar)headerView.findViewById(R.id.progress);
headerHeight=headerView.getMeasuredHeight();
LinearLayout.LayoutParams lp=new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
headerView.getMeasuredHeight());
this.addView(headerView,lp);
setTopHeader(headerHeight);
final DisplayMetrics metrics=getResources().getDisplayMetrics();
mSpinnerFinalOffset=DEFAULT_CIRCLE_TARGET*metrics.density;
mTotalDragDistance=mSpinnerFinalOffset;
}
/**
* 通知父布局,占用的宽,高;
*
* #param view
*/
private void measureView(View view) {
ViewGroup.LayoutParams p = view.getLayoutParams();
if (p == null) {
p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
int width = ViewGroup.getChildMeasureSpec(0, 0, p.width);
int height;
int tempHeight = p.height;
if (tempHeight > 0) {
height = MeasureSpec.makeMeasureSpec(tempHeight,
MeasureSpec.EXACTLY);
} else {
height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
}
view.measure(width, height);
}
private void setTopHeader(int height)
{
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB)
{
this.setY(-height);
}else{
LayoutParams lp=new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,height);
lp.topMargin=-height;
this.setLayoutParams(lp);
}
headerView.invalidate();
}
/**
* Set the listener to be notified when a refresh is triggered via the
* pull gesture.
* #param listener
*/
public void setOnPullToRefresh(OnPullToRefresh listener)
{
this.refreshListener=listener;
}
/**
* Set the listener to be notified when a load is triggered via the
* drag gesture
* #param listener
*/
public void setOnDragToLoad(OnDragToLoad listener)
{
this.loadListener=listener;
}
private void ensureTarget(){
if(mTarget==null){
for(int i=0;i<getChildCount();i++)
{
View child=getChildAt(i);
if(child instanceof RecyclerView)
{
mTarget=child;
break;
}
}
}
}
/**
* #return Whether it is possible for the child view of this layout to
* scroll up.Override this if the child view is a custom view.
*/
public boolean canChildScrollUp(){
if(mTarget==null)
{
ensureTarget();
}
if(Build.VERSION.SDK_INT<14)
{
if(mTarget instanceof AbsListView)
{
final AbsListView absListView=(AbsListView)mTarget;
return absListView.getChildCount()>0
&&(absListView.getFirstVisiblePosition()>0
||absListView.getChildAt(0).getTop()<absListView.getPaddingTop());
}else{
return ViewCompat.canScrollVertically(mTarget,-1)|| mTarget.getScrollY()>0;
}
}else{
return ViewCompat.canScrollVertically(mTarget,-1);
}
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
ensureTarget();
final int action=MotionEventCompat.getActionMasked(ev);
if(mReturningToStart && action == MotionEvent.ACTION_DOWN){
mReturningToStart = false;
}
if(!isEnabled() || mReturningToStart || canChildScrollUp()
||mRefreshing || mNestedScrollInProgress){
return false;
}
switch (action){
case MotionEvent.ACTION_DOWN:
setTargetOffsetTopAndBottom(mOriginalOffsetTop-headerView.getTop(),true);
mActivePointerId=MotionEventCompat.getPointerId(ev,0);
mIsBeingDragged=false;
final float initialDownY=getMotionEventY(ev,mActivePointerId);
if(initialDownY==-1){
return false;
}
mInitailDownY=initialDownY;
updateHeader=true;
break;
case MotionEvent.ACTION_MOVE:
if(mActivePointerId==INVALID_POINTER){
Log.e(LOG_TAG, "Got ACTION_MOVE event but don't have an active pointer id.");
return false;
}
final float y=getMotionEventY(ev,mActivePointerId);
if(y==-1){
return false;
}
final float yDiff=y-mInitailDownY;
if(yDiff>mTouchSlop && !mIsBeingDragged){
mInitialMotionY=mInitailDownY+mTouchSlop;
mIsBeingDragged=true;
}
break;
case MotionEventCompat.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mIsBeingDragged=false;
mActivePointerId=INVALID_POINTER;
break;
}
return mIsBeingDragged;
}
private float getMotionEventY(MotionEvent ev,int activePointerId){
final int index=MotionEventCompat.findPointerIndex(ev,activePointerId);
if(index<0){
return -1;
}
return MotionEventCompat.getY(ev,index);
}
private void setTargetOffsetTopAndBottom(int offset,boolean requiresUpdate){
if(this.getTop()<headerHeight+5)
{
this.offsetTopAndBottom(offset);
mCurrentTargetOffsetTop=this.getTop();
if(requiresUpdate && Build.VERSION.SDK_INT<11){
invalidate();
}
if(this.getTop()>headerHeight)
{
if(updateHeader){
updateHeader=false;
refreshTv.setText(getResources().getText(R.string.releasetorefresh));
RotateAnimation animation=new RotateAnimation(0,180,
Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
animation.setDuration(800);
animation.setFillAfter(true);
arrowIv.startAnimation(animation);
}
}
}
}
private void onSecondaryPointerUp(MotionEvent ev){
final int pointerIndex=MotionEventCompat.getActionIndex(ev);
final int pointerId=MotionEventCompat.getPointerId(ev,pointerIndex);
if(pointerId==mActivePointerId){
//This was our active pointer going up. Choose a new
//active pointer and adjust accordingly.
final int newPointerIndex=pointerIndex==0?1:0;
mActivePointerId=MotionEventCompat.getPointerId(ev,newPointerIndex);
}
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
final int action=MotionEventCompat.getActionMasked(event);
int pointerIndex=-1;
if(mReturningToStart&&action==MotionEvent.ACTION_DOWN){
mReturningToStart=false;
}
if(!isEnabled() || mReturningToStart
|| canChildScrollUp() || mNestedScrollInProgress){
//Fail fast if we're not in a state where a swipe is possible
return false;
}
switch(action){
case MotionEvent.ACTION_DOWN:
mActivePointerId=MotionEventCompat.getPointerId(event,0);
mIsBeingDragged=false;
break;
case MotionEvent.ACTION_MOVE:{
pointerIndex=MotionEventCompat.findPointerIndex(event,mActivePointerId);
if(pointerIndex<0){
Log.e(LOG_TAG, "Got ACTION_MOVE event but have an invalid active pointer id.");
return false;
}
final float y=MotionEventCompat.getY(event,pointerIndex);
final float overscrollTop=(y-mInitialMotionY)*DRAG_RATE;
if(mIsBeingDragged){
if(overscrollTop>0){
moveSpinner(overscrollTop);
}else{
return false;
}
}
break;
}
case MotionEventCompat.ACTION_POINTER_DOWN:{
pointerIndex=MotionEventCompat.getActionIndex(event);
if(pointerIndex<0){
Log.e(LOG_TAG, "Got ACTION_POINTER_DOWN event but have an invalid action index.");
return false;
}
mActivePointerId=MotionEventCompat.getPointerId(event,pointerIndex);
break;
}
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(event);
break;
case MotionEvent.ACTION_UP:{
pointerIndex=MotionEventCompat.findPointerIndex(event,mActivePointerId);
if(pointerIndex<0){
Log.e(LOG_TAG, "Got ACTION_UP event but don't have an active pointer id.");
return false;
}
final float y=MotionEventCompat.getY(event,pointerIndex);
mIsBeingDragged=false;
finishSpinner();
mActivePointerId=INVALID_POINTER;
return false;
}
case MotionEvent.ACTION_CANCEL:
return false;
}
return true;
}
private void moveSpinner(float overscrollTop){
float originalDragPercent=overscrollTop/mTotalDragDistance;
float dragPercent=Math.min(1f,Math.abs(originalDragPercent));
float adjustedPercent=(float)Math.max(dragPercent-.4,0)*5/3;
float extraOS=Math.abs(overscrollTop)-mTotalDragDistance;
float slingshotDist=mSpinnerFinalOffset;
float tensionSlingshotPercent=Math.max(0,Math.min(extraOS,slingshotDist*2)/slingshotDist);
float tensionPercent=(float)((tensionSlingshotPercent/4)-Math.pow(
(tensionSlingshotPercent/4),2))*2f;
float extraMove=(slingshotDist)*tensionPercent*2;
int targetY=mOriginalOffsetTop+(int)((slingshotDist*dragPercent)+extraMove);
setTargetOffsetTopAndBottom(targetY-mCurrentTargetOffsetTop,true);
}
private void finishSpinner(){
if(this.getTop()>headerHeight){
setRefreshing(true,true);
}else{
//cancel refresh
mRefreshing=false;
animateOffsetToStartPosition();
}
}
private void setRefreshing(boolean refreshing,final boolean notify)
{
if(mRefreshing!=refreshing){
ensureTarget();
mRefreshing=refreshing;
if(mRefreshing){
refreshListener.onRefresh();
arrowIv.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
}else{
arrowIv.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
animateOffsetToStartPosition();
}
}
}
public void setRefreshing(boolean refreshing){
if(!refreshing){
setRefreshing(refreshing,false);
}
}
private void animateOffsetToStartPosition(){
refreshTv.setText(getResources().getText(R.string.pulltorefresh));
arrowIv.clearAnimation();
Log.d(LOG_TAG,"getTop="+this.getTop()+" timer="+((timer==null)?"null":"notnumm"));
if(timer==null&&this.getTop()>0)
{
timer=new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
#Override
public void run() {
if(thisView.getTop()>0)
{
thisView.offsetTopAndBottom(-1);
mCurrentTargetOffsetTop = headerView.getTop();
if ( Build.VERSION.SDK_INT < 11) {
invalidate();
}
}else{
Log.d(LOG_TAG,"cancel");
timer.cancel();
timer=null;
}
}
});
}
},10,10);
}
}
/**
* Classes that wish to be notified when the pull gesture correctly
* triggers a refresh should implement this interface.
*/
public interface OnPullToRefresh{
public void onRefresh();
}
/**
* Classes that wish to be notified when the drag gesture correctly
* triggers a load should implement this interface.
*/
public interface OnDragToLoad{
public void onLoad();
}}
offsetTopAndBottom(offset) will add mTop and mBottom of View by offset.
private void animateOffsetToStartPosition(){
refreshTv.setText(getResources().getText(R.string.pulltorefresh));
arrowIv.clearAnimation();
Log.d(LOG_TAG,"getTop="+this.getTop()+" timer="+((timer==null)?"null":"notnumm"));
if(timer==null&&this.getTop()>0)
{
timer=new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
#Override
public void run() {
if(thisView.getTop()>0)
{
//this line says that if top of thisView is not 0,add mtop and mBottom of thisView by -1
//this timer will change the mTop to 0.thisView will be back to original place if mTop == 0.
thisView.offsetTopAndBottom(-1);
mCurrentTargetOffsetTop = headerView.getTop();
if ( Build.VERSION.SDK_INT < 11) {
invalidate();
}
}else{
Log.d(LOG_TAG,"cancel");
timer.cancel();
timer=null;
}
}
});
}
},10,10);
}
}
setY() calls setTranslationY(), which makes two calls to invalidateViewProperty(boolean invalidateParent, boolean forceRedraw).
In setTranslationY(), when it calls invalidateViewProperty, it is passing forceRedraw as true, which redraws the view and puts it back to the original state.

Swipe refresh layout is not working for web view.

I am using swipe refresh layout but it is not working for web view. It is working for a simple activity layout, but when i am using a web view it's not working properly.
Here is my code.
public class SwipeActivity extends Activity implements OnRefreshListener{
SwipeRefreshLayout swipeLayout;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_swipe);
swipeLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_container);
swipeLayout.setOnRefreshListener(this);
swipeLayout.setColorScheme(android.R.color.holo_blue_bright,
android.R.color.holo_green_light,
android.R.color.holo_orange_light,
android.R.color.holo_red_light);
}
public void onRefresh() {
new Handler().postDelayed(new Runnable() {
#Override public void run() {
swipeLayout.setRefreshing(false);
}
}, 5000);
}
}
And this one is swipe refresh layout.
public class SwipeRefreshLayout extends ViewGroup {
private static final long RETURN_TO_ORIGINAL_POSITION_TIMEOUT = 300;
private static final float ACCELERATE_INTERPOLATION_FACTOR = 1.5f;
private static final float DECELERATE_INTERPOLATION_FACTOR = 2f;
private static final float PROGRESS_BAR_HEIGHT = 4;
private static final float MAX_SWIPE_DISTANCE_FACTOR = .6f;
private static final int REFRESH_TRIGGER_DISTANCE = 120;
private SwipeProgressBar mProgressBar; //the thing that shows progress is going
private View mTarget; //the content that gets pulled down
private int mOriginalOffsetTop;
private OnRefreshListener mListener;
private MotionEvent mDownEvent;
private int mFrom;
private boolean mRefreshing = false;
private int mTouchSlop;
private float mDistanceToTriggerSync = -1;
private float mPrevY;
private int mMediumAnimationDuration;
private float mFromPercentage = 0;
private float mCurrPercentage = 0;
private int mProgressBarHeight;
private int mCurrentTargetOffsetTop;
// Target is returning to its start offset because it was cancelled or a
// refresh was triggered.
private boolean mReturningToStart;
private final DecelerateInterpolator mDecelerateInterpolator;
private final AccelerateInterpolator mAccelerateInterpolator;
private static final int[] LAYOUT_ATTRS = new int[] {
android.R.attr.enabled
};
private final Animation mAnimateToStartPosition = new Animation() {
#Override
public void applyTransformation(float interpolatedTime, Transformation t) {
int targetTop = 0;
if (mFrom != mOriginalOffsetTop) {
targetTop = (mFrom + (int)((mOriginalOffsetTop - mFrom) * interpolatedTime));
}
int offset = targetTop - mTarget.getTop();
final int currentTop = mTarget.getTop();
if (offset + currentTop < 0) {
offset = 0 - currentTop;
}
setTargetOffsetTopAndBottom(offset);
}
};
private Animation mShrinkTrigger = new Animation() {
#Override
public void applyTransformation(float interpolatedTime, Transformation t) {
float percent = mFromPercentage + ((0 - mFromPercentage) * interpolatedTime);
mProgressBar.setTriggerPercentage(percent);
}
};
private final AnimationListener mReturnToStartPositionListener = new BaseAnimationListener() {
#Override
public void onAnimationEnd(Animation animation) {
// Once the target content has returned to its start position, reset
// the target offset to 0
mCurrentTargetOffsetTop = 0;
}
};
private final AnimationListener mShrinkAnimationListener = new BaseAnimationListener() {
#Override
public void onAnimationEnd(Animation animation) {
mCurrPercentage = 0;
}
};
private final Runnable mReturnToStartPosition = new Runnable() {
#Override
public void run() {
mReturningToStart = true;
animateOffsetToStartPosition(mCurrentTargetOffsetTop + getPaddingTop(),
mReturnToStartPositionListener);
}
};
// Cancel the refresh gesture and animate everything back to its original state.
private final Runnable mCancel = new Runnable() {
#Override
public void run() {
mReturningToStart = true;
// Timeout fired since the user last moved their finger; animate the
// trigger to 0 and put the target back at its original position
if (mProgressBar != null) {
mFromPercentage = mCurrPercentage;
mShrinkTrigger.setDuration(mMediumAnimationDuration);
mShrinkTrigger.setAnimationListener(mShrinkAnimationListener);
mShrinkTrigger.reset();
mShrinkTrigger.setInterpolator(mDecelerateInterpolator);
startAnimation(mShrinkTrigger);
}
animateOffsetToStartPosition(mCurrentTargetOffsetTop + getPaddingTop(),
mReturnToStartPositionListener);
}
};
/**
* Simple constructor to use when creating a SwipeRefreshLayout from code.
* #param context
*/
public SwipeRefreshLayout(Context context) {
this(context, null);
}
/**
* Constructor that is called when inflating SwipeRefreshLayout from XML.
* #param context
* #param attrs
*/
public SwipeRefreshLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mMediumAnimationDuration = getResources().getInteger(
android.R.integer.config_mediumAnimTime);
setWillNotDraw(false);
mProgressBar = new SwipeProgressBar(this);
final DisplayMetrics metrics = getResources().getDisplayMetrics();
mProgressBarHeight = (int) (metrics.density * PROGRESS_BAR_HEIGHT);
mDecelerateInterpolator = new DecelerateInterpolator(DECELERATE_INTERPOLATION_FACTOR);
mAccelerateInterpolator = new AccelerateInterpolator(ACCELERATE_INTERPOLATION_FACTOR);
final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS);
setEnabled(a.getBoolean(0, true));
a.recycle();
}
#Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
removeCallbacks(mCancel);
removeCallbacks(mReturnToStartPosition);
}
#Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
removeCallbacks(mReturnToStartPosition);
removeCallbacks(mCancel);
}
private void animateOffsetToStartPosition(int from, AnimationListener listener) {
mFrom = from;
mAnimateToStartPosition.reset();
mAnimateToStartPosition.setDuration(mMediumAnimationDuration);
mAnimateToStartPosition.setAnimationListener(listener);
mAnimateToStartPosition.setInterpolator(mDecelerateInterpolator);
mTarget.startAnimation(mAnimateToStartPosition);
}
/**
* Set the listener to be notified when a refresh is triggered via the swipe
* gesture.
*/
public void setOnRefreshListener(SwipeActivity swipeActivity) {
mListener = swipeActivity;
}
private void setTriggerPercentage(float percent) {
if (percent == 0f) {
// No-op. A null trigger means it's uninitialized, and setting it to zero-percent
// means we're trying to reset state, so there's nothing to reset in this case.
mCurrPercentage = 0;
return;
}
mCurrPercentage = percent;
mProgressBar.setTriggerPercentage(percent);
}
/**
* Notify the widget that refresh state has changed. Do not call this when
* refresh is triggered by a swipe gesture.
*
* #param refreshing Whether or not the view should show refresh progress.
*/
public void setRefreshing(boolean refreshing) {
if (mRefreshing != refreshing) {
ensureTarget();
mCurrPercentage = 0;
mRefreshing = refreshing;
if (mRefreshing) {
mProgressBar.start();
} else {
mProgressBar.stop();
}
}
}
/**
* Set the four colors used in the progress animation. The first color will
* also be the color of the bar that grows in response to a user swipe
* gesture.
*
* #param colorRes1 Color resource.
* #param colorRes2 Color resource.
* #param colorRes3 Color resource.
* #param colorRes4 Color resource.
*/
public void setColorScheme(int colorRes1, int colorRes2, int colorRes3, int colorRes4) {
ensureTarget();
final Resources res = getResources();
final int color1 = res.getColor(colorRes1);
final int color2 = res.getColor(colorRes2);
final int color3 = res.getColor(colorRes3);
final int color4 = res.getColor(colorRes4);
mProgressBar.setColorScheme(color1, color2, color3,color4);
}
/**
* #return Whether the SwipeRefreshWidget is actively showing refresh
* progress.
*/
public boolean isRefreshing() {
return mRefreshing;
}
private void ensureTarget() {
// Don't bother getting the parent height if the parent hasn't been laid out yet.
if (mTarget == null) {
if (getChildCount() > 1 && !isInEditMode()) {
throw new IllegalStateException(
"SwipeRefreshLayout can host only one direct child");
}
mTarget = getChildAt(0);
mOriginalOffsetTop = mTarget.getTop() + getPaddingTop();
}
if (mDistanceToTriggerSync == -1) {
if (getParent() != null && ((View)getParent()).getHeight() > 0) {
final DisplayMetrics metrics = getResources().getDisplayMetrics();
mDistanceToTriggerSync = (int) Math.min(
((View) getParent()) .getHeight() * MAX_SWIPE_DISTANCE_FACTOR,
REFRESH_TRIGGER_DISTANCE * metrics.density);
}
}
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
mProgressBar.draw(canvas);
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
final int width = getMeasuredWidth();
final int height = getMeasuredHeight();
mProgressBar.setBounds(0, 0, width, mProgressBarHeight);
if (getChildCount() == 0) {
return;
}
final View child = getChildAt(0);
final int childLeft = getPaddingLeft();
final int childTop = mCurrentTargetOffsetTop + getPaddingTop();
final int childWidth = width - getPaddingLeft() - getPaddingRight();
final int childHeight = height - getPaddingTop() - getPaddingBottom();
child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (getChildCount() > 1 && !isInEditMode()) {
throw new IllegalStateException("SwipeRefreshLayout can host only one direct child");
}
if (getChildCount() > 0) {
getChildAt(0).measure(
MeasureSpec.makeMeasureSpec(
getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(
getMeasuredHeight() - getPaddingTop() - getPaddingBottom(),
MeasureSpec.EXACTLY));
}
}
/**
* #return Whether it is possible for the child view of this layout to
* scroll up. Override this if the child view is a custom view.
*/
public boolean canChildScrollUp() {
if (android.os.Build.VERSION.SDK_INT < 14) {
if (mTarget instanceof AbsListView) {
final AbsListView absListView = (AbsListView) mTarget;
return absListView.getChildCount() > 0
&& (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)
.getTop() < absListView.getPaddingTop());
} else {
return mTarget.getScrollY() > 0;
}
} else {
return ViewCompat.canScrollVertically(mTarget, -1);
}
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
ensureTarget();
boolean handled = false;
if (mReturningToStart && ev.getAction() == MotionEvent.ACTION_DOWN) {
mReturningToStart = false;
}
if (isEnabled() && !mReturningToStart && !canChildScrollUp()) {
handled = onTouchEvent(ev);
}
return !handled ? super.onInterceptTouchEvent(ev) : handled;
}
#Override
public void requestDisallowInterceptTouchEvent(boolean b) {
// Nope.
}
#Override
public boolean onTouchEvent(MotionEvent event) {
final int action = event.getAction();
boolean handled = false;
switch (action) {
case MotionEvent.ACTION_DOWN:
mCurrPercentage = 0;
mDownEvent = MotionEvent.obtain(event);
mPrevY = mDownEvent.getY();
break;
case MotionEvent.ACTION_MOVE:
if (mDownEvent != null && !mReturningToStart) {
final float eventY = event.getY();
float yDiff = eventY - mDownEvent.getY();
if (yDiff > mTouchSlop) {
// User velocity passed min velocity; trigger a refresh
if (yDiff > mDistanceToTriggerSync) {
// User movement passed distance; trigger a refresh
startRefresh();
handled = true;
break;
} else {
// Just track the user's movement
setTriggerPercentage(
mAccelerateInterpolator.getInterpolation(
yDiff / mDistanceToTriggerSync));
float offsetTop = yDiff;
if (mPrevY > eventY) {
offsetTop = yDiff - mTouchSlop;
}
updateContentOffsetTop((int) (offsetTop));
if (mPrevY > eventY && (mTarget.getTop() < mTouchSlop)) {
// If the user puts the view back at the top, we
// don't need to. This shouldn't be considered
// cancelling the gesture as the user can restart from the top.
removeCallbacks(mCancel);
} else {
updatePositionTimeout();
}
mPrevY = event.getY();
handled = true;
}
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (mDownEvent != null) {
mDownEvent.recycle();
mDownEvent = null;
}
break;
}
return handled;
}
private void startRefresh() {
removeCallbacks(mCancel);
mReturnToStartPosition.run();
setRefreshing(true);
mListener.onRefresh();
}
private void updateContentOffsetTop(int targetTop) {
final int currentTop = mTarget.getTop();
if (targetTop > mDistanceToTriggerSync) {
targetTop = (int) mDistanceToTriggerSync;
} else if (targetTop < 0) {
targetTop = 0;
}
setTargetOffsetTopAndBottom(targetTop - currentTop);
}
private void setTargetOffsetTopAndBottom(int offset) {
mTarget.offsetTopAndBottom(offset);
mCurrentTargetOffsetTop = mTarget.getTop();
}
private void updatePositionTimeout() {
removeCallbacks(mCancel);
postDelayed(mCancel, RETURN_TO_ORIGINAL_POSITION_TIMEOUT);
}
/**
* Classes that wish to be notified when the swipe gesture correctly
* triggers a refresh should implement this interface.
*/
public interface OnRefreshListener {
public void onRefresh();
}
/**
* Simple AnimationListener to avoid having to implement unneeded methods in
* AnimationListeners.
*/
private class BaseAnimationListener implements AnimationListener {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
}
}

Touch events is becoming slow and sometimes not handled in Listview in android

I am using touch listener for an imageview in the listview item .It is working fine when I just do that like an sample application(I mean I have that Listview item as an sample one). But when I put this in a listview it is really becoming very slow.
I just wants to drag the image only horizantally,for that purpose I used ConstrainedDragandDrop View class which I got from the Github.
In my sample application:
public class HorizontalScroll extends Activity {
ImageView full_left,heart;
RelativeLayout rlMainLayout,rlImages,Cartoon_image,half_left,play_btn,centre,centre_leftanimate;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.inflated_bloops);
half_left=(RelativeLayout)findViewById(R.id.half_left);
Cartoon_image=(RelativeLayout)findViewById(R.id.cartoon_image);
play_btn=(RelativeLayout)findViewById(R.id.play_btn);
heart=(ImageView)findViewById(R.id.ivheart);
ConstrainedDragAndDropView dndView = (ConstrainedDragAndDropView) findViewById(R.id.dndView);
dndView.setDragHandle(findViewById(R.id.cartoon_image),findViewById(R.id.half_left),heart);
dndView.setAllowVerticalDrag(false,HorizontalScroll.this);
}
}
When I used in my Listview:
public class Cars extends BaseAdapter
{
public View getView(int position, View convertView, ViewGroup parent)
{
View v = convertView;
LayoutInflater inflator = getLayoutInflater();
v= inflator.inflate(R.layout.inflated_bloops, null);
ConstrainedDragAndDropView dndView = (ConstrainedDragAndDropView) v.findViewById(R.id.dndView);
dndView.setDragHandle(v.findViewById(R.id.cartoon_image),v.findViewById(R.id.half_left),heart);
dndView.setAllowVerticalDrag(false,FeedModeActivity.this);
RelativeLayout Cartoon_image=(RelativeLayout)v.findViewById(R.id.cartoon_image);
ImageView ivDummy =(ImageView)v.findViewById(R.id.dummy);
try{
loader.DisplayImageRelative( al_new.get(position).replace(" ", "%20"),ivDummy, Cartoon_image);
}
catch(Exception e){
e.printStackTrace();
}
return v;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return al_new.size();
}
#Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
}
Here is my custom dragDrop view:
public class ConstrainedDragAndDropView extends LinearLayout {
Activity main;
protected View dragHandle,half,heart;
protected List<View> dropTargets = new ArrayList<View>();
protected boolean dragging = false;
protected int pointerId;
protected int selectedDropTargetIndex = -1;
protected int lastSelectedDropTargetIndex = -1;
protected int lastDroppedIndex = -1;
protected boolean allowHorizontalDrag = true;
protected boolean allowVerticalDrag = true;
protected DropListener dropListener;
public interface DropListener {
public void onDrop(final int dropIndex, final View dropTarget);
}
public ConstrainedDragAndDropView(Context context) {
super(context);
}
public ConstrainedDragAndDropView(Context context, AttributeSet attrs) {
super(context, attrs);
applyAttrs(context, attrs);
}
#SuppressLint("NewApi")
public ConstrainedDragAndDropView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
applyAttrs(context, attrs);
}
public DropListener getDropListener() {
return dropListener;
}
public void setDropListener(DropListener dropListener) {
this.dropListener = dropListener;
}
public View getDragHandle() {
return dragHandle;
}
public void setDragHandle(View dragHandle,View half_left,View heart) {
this.dragHandle = dragHandle;
this.half=half_left;
this.heart=heart;
setupDragHandle();
}
public List<View> getDropTargets() {
return dropTargets;
}
public void setDropTargets(List<View> dropTargets) {
this.dropTargets = dropTargets;
}
public void addDropTarget(View target) {
if (dropTargets == null) {
dropTargets = new ArrayList<View>();
}
dropTargets.add(target);
}
public boolean isAllowHorizontalDrag() {
return allowHorizontalDrag;
}
public void setAllowHorizontalDrag(boolean allowHorizontalDrag) {
this.allowHorizontalDrag = allowHorizontalDrag;
}
public boolean isAllowVerticalDrag() {
return allowVerticalDrag;
}
public void setAllowVerticalDrag(boolean allowVerticalDrag,Activity c) {
this.allowVerticalDrag = allowVerticalDrag;
this.main=c;
}
protected void applyAttrs(Context context, AttributeSet attrs) {
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ConstrainedDragAndDropView, 0, 0);
try {
/*
layoutId = a.getResourceId(R.styleable.ConstrainedDragAndDropView_layoutId, 0);
if (layoutId > 0) {
LayoutInflater.from(context).inflate(layoutId, this, true);
}
*/
} finally {
a.recycle();
}
}
protected void setupDragHandle() {
this.setOnTouchListener(new DragAreaTouchListener());
}
protected class DragAreaTouchListener implements OnTouchListener {
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d("Action down", "action down in listener");
onActionDown(view, motionEvent);
break;
case MotionEvent.ACTION_UP:
Log.d("Action up", "action up in listener");
onActionUp(view, motionEvent);
break;
case MotionEvent.ACTION_MOVE:
Log.d("Action move", "action move in listener");
onActionMove(view, motionEvent);
break;
default:
break;
}
return true;
}
}
public static int param;
protected void onActionDown(View view, MotionEvent motionEvent) {
// if we're not already dragging, and the touch position is on the drag handle,
// then start dragging
if(!dragging && isDragHandleTouch(motionEvent)) {
pointerId = motionEvent.getPointerId(0);
Float s1= dragHandle.getX();
param=Integer.valueOf(s1.intValue());
Log.e("param",""+param);
// updateDragPosition(motionEvent);
dragging = true;
Log.d("drag", "drag start");
}
}
protected void onActionUp(View view, MotionEvent motionEvent) {
Log.d("Action up", "action up");
// if we're dragging, then stop dragging
if (dragging && motionEvent.getPointerId(0) == pointerId) {
Log.e("condition","satisfied");
Log.e("x val"+(int)motionEvent.getX(),"y val"+(int)motionEvent.getY());
Log.e("x1"+half.getLeft(),"y1"+half.getTop());
Log.e("x4"+half.getRight(),"y4"+half.getBottom());
Float s1=motionEvent.getX();
Float s2=motionEvent.getY();
int x=Integer.valueOf(s1.intValue());
dragging = false;
int y=Integer.valueOf(s2.intValue());
if((half.getLeft()<x)&&(x<half.getRight())&&((half.getTop()<y)&&(y<half.getBottom())))
{
Log.e("drop","on target");
try {
Thread.sleep(1000);
dragHandle.setX(param);
heart.setVisibility(View.VISIBLE);
Animation pulse = AnimationUtils.loadAnimation(main, R.anim.pulse);
heart.startAnimation(pulse);
// heart.setVisibility(View.GONE);
pulse.setAnimationListener(new AnimationListener() {
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
Log.e("animation","start");
}
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
public void onAnimationEnd(Animation animation) {
// TODO Auto-generated method stub
Log.e("animation","end");
heart.setVisibility(View.GONE);
}
});
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// class SimpleThread extends Thread {
//
// public void run() {
//
// try {
// sleep(1000);
// runOnUiThread(new Runnable() {
// public void run() {
// dragHandle.setX(param);
// heart.setVisibility(View.VISIBLE);
//
// Animation pulse = AnimationUtils.loadAnimation(main, R.anim.pulse);
// heart.startAnimation(pulse);
// }
// });
//
// }
// catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
//
// }
// }
//
// new SimpleThread().start();
}
else{
Log.e("drop",""+"outside target");
dragHandle.setX(param);
// TranslateAnimation transAnimation= new TranslateAnimation(x, 300, y, 300);
// transAnimation.setDuration(1000);//set duration
// view.startAnimation(transAnimation);
}
// if()
// updateDragPosition(motionEvent);
Log.d("drag", "drag end");
// find out what drop target, if any, the drag handle was dropped on
int dropTargetIndex = findDropTargetIndexUnderDragHandle();
if(dropTargetIndex >= 0) { // if drop was on a target, select the target
Log.d("drag", "drop on target " + dropTargetIndex);
// selectDropTarget(dropTargetIndex);
// snapDragHandleToDropTarget(dropTargetIndex);
// lastDroppedIndex = dropTargetIndex;
if(dropListener != null) {
dropListener.onDrop(dropTargetIndex, dropTargets.get(dropTargetIndex));
}
} else { // if drop was not on a target, re-select the last selected target
// deselectDropTarget();
// snapDragHandleToDropTarget(lastDroppedIndex);
}
}
else{
Log.e("condition not","satisfied");
}
}
protected void onActionMove(View view, MotionEvent motionEvent) {
Log.d("Action move", "action move");
if (dragging && motionEvent.getPointerId(0) == pointerId) {
updateDragPosition(motionEvent);
int dropTargetIndex = findDropTargetIndexUnderDragHandle();
if(dropTargetIndex >= 0) {
Log.d("drag", "hover on target " + dropTargetIndex);
// selectDropTarget(dropTargetIndex);
} else {
// deselectDropTarget();
}
}
}
#SuppressLint("NewApi")
protected void updateDragPosition(MotionEvent motionEvent) {
// this is where we constrain the movement of the dragHandle
if(allowHorizontalDrag) {
float candidateX = motionEvent.getX() - dragHandle.getWidth() / 2;
if(candidateX > 0 && candidateX + dragHandle.getWidth() < this.getWidth()) {
dragHandle.setX(candidateX);
}
}
if(allowVerticalDrag) {
float candidateY = motionEvent.getY() - dragHandle.getHeight() / 2;
if(candidateY > 0 && candidateY + dragHandle.getHeight() < this.getHeight()) {
dragHandle.setY(candidateY);
}
}
}
#SuppressLint("NewApi")
protected void snapDragHandleToDropTarget(int dropTargetIndex) {
if(dropTargetIndex > -1) {
View dropTarget = dropTargets.get(dropTargetIndex);
float xCenter = dropTarget.getX() + dropTarget.getWidth() / 2;
float yCenter = dropTarget.getY() + dropTarget.getHeight() / 2;
float xOffset = dragHandle.getWidth() / 2;
float yOffset = dragHandle.getHeight() / 2;
float x = xCenter - xOffset;
float y = yCenter - yOffset;
dragHandle.setX(x);
dragHandle.setY(y);
}
}
protected boolean isDragHandleTouch(MotionEvent motionEvent) {
Point point = new Point(
new Float(motionEvent.getRawX()).intValue(),
new Float(motionEvent.getRawY()).intValue()
);
return isPointInView(point, dragHandle);
}
protected int findDropTargetIndexUnderDragHandle() {
int dropTargetIndex = -1;
for(int i = 0; i < dropTargets.size(); i++) {
if(isCollision(dragHandle, dropTargets.get(i))) {
dropTargetIndex = i;
break;
}
}
return dropTargetIndex;
}
/**
* Determines whether a raw screen coordinate is within the bounds of the specified view
* #param point - Point containing screen coordinates
* #param view - View to test
* #return true if the point is in the view, else false
*/
protected boolean isPointInView(Point point, View view) {
int[] viewPosition = new int[2];
view.getLocationOnScreen(viewPosition);
int left = viewPosition[0];
int right = left + view.getWidth();
int top = viewPosition[1];
int bottom = top + view.getHeight();
return point.x >= left && point.x <= right && point.y >= top && point.y <= bottom;
}
#SuppressLint("NewApi")
protected boolean isCollision(View view1, View view2) {
boolean collision = false;
do {
if(view1.getY() + view1.getHeight() < view2.getY()) {
break;
}
if(view1.getY() > view2.getY() + view2.getHeight()) {
break;
}
if(view1.getX() > view2.getX() + view2.getWidth()) {
break;
}
if(view1.getX() + view1.getWidth() < view2.getX()) {
break;
}
collision = true;
} while(false);
return collision;
}
protected void selectDropTarget(int index) {
if(index > -1) {
deselectDropTarget();
selectedDropTargetIndex = index;
dropTargets.get(selectedDropTargetIndex).setSelected(true);
}
}
protected void deselectDropTarget() {
if(selectedDropTargetIndex > -1) {
dropTargets.get(selectedDropTargetIndex).setSelected(false);
lastSelectedDropTargetIndex = selectedDropTargetIndex;
selectedDropTargetIndex = -1;
}
}
}

Categories

Resources