欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

在android中实现类似uc和墨迹天气的左右拖动效果

程序员文章站 2023-11-25 10:21:16
复制代码 代码如下: import android.app.activity; import android.os.bundle; import android.conte...
复制代码 代码如下:

import android.app.activity;
import android.os.bundle;
import android.content.context;
import android.graphics.color;
import android.util.log;
import android.view.gravity;
import android.view.motionevent;
import android.view.view;
import android.view.viewgroup;
import android.view.view.onclicklistener;
import android.widget.arrayadapter;
import android.widget.button;
import android.widget.checkbox;
import android.widget.edittext;
import android.widget.linearlayout;
import android.widget.tablelayout;
import android.widget.textview;
public class flinggalleryactivity extends activity
{
private final int color_red = color.argb(100, 200, 0, 0);
private final int color_green = color.argb(100, 0, 200, 0);
private final int color_blue = color.argb(100, 0, 0, 200);
private final int color_yellow = color.argb(100, 200, 200, 0);
private final int color_purple = color.argb(100, 200, 0, 200);
private final string[] mlabelarray = {"view1", "view2", "view3", "view4", "view5"};
private final int[] mcolorarray = {color_red, color_green, color_blue, color_yellow, color_purple};
private flinggallery mgallery;
private checkbox mcheckbox;
// note: the following handler is critical to correct function of
// the flinggallery class. this enables the flinggallery class to
// detect when the motion event has ended by finger being lifted
@override
public boolean ontouchevent(motionevent event)
{
return mgallery.ongallerytouchevent(event);
}
public void oncreate(bundle savedinstancestate)
{
super.oncreate(savedinstancestate);
mgallery = new flinggallery(this);
mgallery.setpaddingwidth(5);
mgallery.setadapter(new arrayadapter<string>(getapplicationcontext(), android.r.layout.simple_list_item_1, mlabelarray)
{
@override
public view getview(int position, view convertview, viewgroup parent)
{
log.d("111", "count="+position);
// if (convertview != null && convertview instanceof galleryviewitem)
// {
// galleryviewitem galleryview = (galleryviewitem) convertview;
//
// galleryview.medit1.settext("");
// galleryview.mtext1.settext(mlabelarray[position]);
// galleryview.mtext1.setbackgroundcolor(mcolorarray[position]);
// galleryview.mtext2.settext(mlabelarray[position]);
// galleryview.mtext2.setbackgroundcolor(mcolorarray[position]);
//
// log.d("111", "count="+position);
//
// return galleryview;
//
// }

return new galleryviewitem(getapplicationcontext(), position);
}
});
linearlayout layout = new linearlayout(getapplicationcontext());
layout.setorientation(linearlayout.vertical);
linearlayout.layoutparams layoutparams = new linearlayout.layoutparams(
linearlayout.layoutparams.match_parent,
linearlayout.layoutparams.match_parent);
layoutparams.setmargins(10, 10, 10, 10);
layoutparams.weight = 1.0f;
layout.addview(mgallery, layoutparams);

mcheckbox = new checkbox(getapplicationcontext());
mcheckbox.settext("gallery is circular");
mcheckbox.settext("gallery is circular");
mcheckbox.setpadding(50, 10, 0, 10);
mcheckbox.settextsize(30);
mcheckbox.setchecked(true);
mcheckbox.setonclicklistener(new onclicklistener()
{
@override
public void onclick(view view)
{
mgallery.setisgallerycircular(mcheckbox.ischecked());
}
});
layout.addview(mcheckbox, new linearlayout.layoutparams(
linearlayout.layoutparams.match_parent,
linearlayout.layoutparams.wrap_content));

setcontentview(layout);
}
private class galleryviewitem extends tablelayout
{
private edittext medit1;
private textview mtext1;
private textview mtext2;
private button mbutton1;
private button mbutton2;
public galleryviewitem(context context, int position)
{
super(context);
this.setorientation(linearlayout.vertical);
this.setlayoutparams(new linearlayout.layoutparams(
linearlayout.layoutparams.match_parent,
linearlayout.layoutparams.match_parent));

medit1 = new edittext(context);
this.addview(medit1, new linearlayout.layoutparams(
linearlayout.layoutparams.match_parent,
linearlayout.layoutparams.wrap_content));
mtext1 = new textview(context);
mtext1.settext(mlabelarray[position]);
mtext1.settextsize(30);
mtext1.setgravity(gravity.left);
mtext1.setbackgroundcolor(mcolorarray[position]);
this.addview(mtext1, new linearlayout.layoutparams(
linearlayout.layoutparams.match_parent,
linearlayout.layoutparams.wrap_content));
mbutton1 = new button(context);
mbutton1.settext("<<");
mbutton1.setgravity(gravity.left);
mbutton1.setonclicklistener(new onclicklistener()
{
@override
public void onclick(view view)
{
mgallery.moveprevious();
}
});
this.addview(mbutton1, new linearlayout.layoutparams(
linearlayout.layoutparams.match_parent,
linearlayout.layoutparams.wrap_content));
mbutton2 = new button(context);
mbutton2.settext(">>");
mbutton2.setgravity(gravity.right);
mbutton2.setonclicklistener(new onclicklistener()
{
@override
public void onclick(view view)
{
mgallery.movenext();
}
});
this.addview(mbutton2, new linearlayout.layoutparams(
linearlayout.layoutparams.match_parent,
linearlayout.layoutparams.wrap_content));
mtext2 = new textview(context);
mtext2.settext(mlabelarray[position]);
mtext2.settextsize(30);
mtext2.setgravity(gravity.right);
mtext2.setbackgroundcolor(mcolorarray[position]);
this.addview(mtext2, new linearlayout.layoutparams(
linearlayout.layoutparams.match_parent,
linearlayout.layoutparams.match_parent, 1));
}
}
}

[代码]flinggallery
复制代码 代码如下:

import android.content.context;
import android.view.gesturedetector;
import android.view.keyevent;
import android.view.motionevent;
import android.view.view;
import android.view.animation.animation;
import android.view.animation.animationutils;
import android.view.animation.interpolator;
import android.view.animation.transformation;
import android.widget.adapter;
import android.widget.framelayout;
import android.widget.linearlayout;
// todo:
// 1. in order to improve performance cache screen bitmap and use for animation
// 2. establish superfluous memory allocations and delay or replace with reused objects
// probably need to make sure we are not allocating objects (strings, etc.) in loops
public class flinggallery extends framelayout
{
// constants

private final int swipe_min_distance = 120;
private final int swipe_max_off_path = 250;
private final int swipe_threshold_veloicty = 400;
// properties
private int mviewpaddingwidth = 0;
private int manimationduration = 250;
private float msnapborderratio = 0.5f;
private boolean misgallerycircular = true;
// members
private int mgallerywidth = 0;
private boolean mistouched = false;
private boolean misdragging = false;
private float mcurrentoffset = 0.0f;
private long mscrolltimestamp = 0;
private int mflingdirection = 0;
private int mcurrentposition = 0;
private int mcurrentviewnumber = 0;
private context mcontext;
private adapter madapter;
private flinggalleryview[] mviews;
private flinggalleryanimation manimation;
private gesturedetector mgesturedetector;
private interpolator mdecelerateinterpolater;
public flinggallery(context context)
{
super(context);
mcontext = context;
madapter = null;

mviews = new flinggalleryview[3];
mviews[0] = new flinggalleryview(0, this);
mviews[1] = new flinggalleryview(1, this);
mviews[2] = new flinggalleryview(2, this);
manimation = new flinggalleryanimation();
mgesturedetector = new gesturedetector(new flinggesturedetector());
mdecelerateinterpolater = animationutils.loadinterpolator(mcontext, android.r.anim.decelerate_interpolator);
}
public void setpaddingwidth(int viewpaddingwidth)
{
mviewpaddingwidth = viewpaddingwidth;
}
public void setanimationduration(int animationduration)
{
manimationduration = animationduration;
}

public void setsnapborderratio(float snapborderratio)
{
msnapborderratio = snapborderratio;
}
public void setisgallerycircular(boolean isgallerycircular)
{
if (misgallerycircular != isgallerycircular)
{
misgallerycircular = isgallerycircular;

if (mcurrentposition == getfirstposition())
{
// we need to reload the view immediately to the left to change it to circular view or blank
mviews[getprevviewnumber(mcurrentviewnumber)].recycleview(getprevposition(mcurrentposition));
}

if (mcurrentposition == getlastposition())
{
// we need to reload the view immediately to the right to change it to circular view or blank
mviews[getnextviewnumber(mcurrentviewnumber)].recycleview(getnextposition(mcurrentposition));
}
}
}
public int getgallerycount()
{
return (madapter == null) ? 0 : madapter.getcount();
}
public int getfirstposition()
{
return 0;
}
public int getlastposition()
{
return (getgallerycount() == 0) ? 0 : getgallerycount() - 1;
}
private int getprevposition(int relativeposition)
{
int prevposition = relativeposition - 1;
if (prevposition < getfirstposition())
{
prevposition = getfirstposition() - 1;
if (misgallerycircular == true)
{
prevposition = getlastposition();
}
}
return prevposition;
}
private int getnextposition(int relativeposition)
{
int nextposition = relativeposition + 1;
if (nextposition > getlastposition())
{
nextposition = getlastposition() + 1;
if (misgallerycircular == true)
{
nextposition = getfirstposition();
}
}
return nextposition;
}
private int getprevviewnumber(int relativeviewnumber)
{
return (relativeviewnumber == 0) ? 2 : relativeviewnumber - 1;
}
private int getnextviewnumber(int relativeviewnumber)
{
return (relativeviewnumber == 2) ? 0 : relativeviewnumber + 1;
}

@override
protected void onlayout(boolean changed, int left, int top, int right, int bottom)
{
super.onlayout(changed, left, top, right, bottom);
// calculate our view width
mgallerywidth = right - left;
if (changed == true)
{
// position views at correct starting offsets
mviews[0].setoffset(0, 0, mcurrentviewnumber);
mviews[1].setoffset(0, 0, mcurrentviewnumber);
mviews[2].setoffset(0, 0, mcurrentviewnumber);
}
}
public void setadapter(adapter adapter)
{
madapter = adapter;
mcurrentposition = 0;
mcurrentviewnumber = 0;
// load the initial views from adapter
mviews[0].recycleview(mcurrentposition);
mviews[1].recycleview(getnextposition(mcurrentposition));
mviews[2].recycleview(getprevposition(mcurrentposition));
// position views at correct starting offsets
mviews[0].setoffset(0, 0, mcurrentviewnumber);
mviews[1].setoffset(0, 0, mcurrentviewnumber);
mviews[2].setoffset(0, 0, mcurrentviewnumber);
}
private int getviewoffset(int viewnumber, int relativeviewnumber)
{
// determine width including configured padding width
int offsetwidth = mgallerywidth + mviewpaddingwidth;
// position the previous view one measured width to left
if (viewnumber == getprevviewnumber(relativeviewnumber))
{
return offsetwidth;
}
// position the next view one measured width to the right
if (viewnumber == getnextviewnumber(relativeviewnumber))
{
return offsetwidth * -1;
}
return 0;
}
void moveprevious()
{
// slide to previous view
mflingdirection = 1;
processgesture();
}
void movenext()
{
// slide to next view
mflingdirection = -1;
processgesture();
}
@override
public boolean onkeydown(int keycode, keyevent event)
{
switch (keycode)
{
case keyevent.keycode_dpad_left:
moveprevious();
return true;

case keyevent.keycode_dpad_right:
movenext();
return true;

case keyevent.keycode_dpad_center:
case keyevent.keycode_enter:
}
return super.onkeydown(keycode, event);
}
public boolean ongallerytouchevent(motionevent event)
{
boolean consumed = mgesturedetector.ontouchevent(event);

if (event.getaction() == motionevent.action_up)
{
if (mistouched || misdragging)
{
processscrollsnap();
processgesture();
}
}

return consumed;
}
void processgesture()
{
int newviewnumber = mcurrentviewnumber;
int reloadviewnumber = 0;
int reloadposition = 0;
mistouched = false;
misdragging = false;
if (mflingdirection > 0)
{
if (mcurrentposition > getfirstposition() || misgallerycircular == true)
{
// determine previous view and outgoing view to recycle
newviewnumber = getprevviewnumber(mcurrentviewnumber);
mcurrentposition = getprevposition(mcurrentposition);
reloadviewnumber = getnextviewnumber(mcurrentviewnumber);
reloadposition = getprevposition(mcurrentposition);
}
}
if (mflingdirection < 0)
{
if (mcurrentposition < getlastposition() || misgallerycircular == true)
{
// determine the next view and outgoing view to recycle
newviewnumber = getnextviewnumber(mcurrentviewnumber);
mcurrentposition = getnextposition(mcurrentposition);
reloadviewnumber = getprevviewnumber(mcurrentviewnumber);
reloadposition = getnextposition(mcurrentposition);
}
}
if (newviewnumber != mcurrentviewnumber)
{
mcurrentviewnumber = newviewnumber;
// reload outgoing view from adapter in new position
mviews[reloadviewnumber].recycleview(reloadposition);
}
// ensure input focus on the current view
mviews[mcurrentviewnumber].requestfocus();
// run the slide animations for view transitions
manimation.prepareanimation(mcurrentviewnumber);
this.startanimation(manimation);
// reset fling state
mflingdirection = 0;
}
void processscrollsnap()
{
// snap to next view if scrolled passed snap position
float rolledgewidth = mgallerywidth * msnapborderratio;
int rolloffset = mgallerywidth - (int) rolledgewidth;
int currentoffset = mviews[mcurrentviewnumber].getcurrentoffset();
if (currentoffset <= rolloffset * -1)
{
// snap to previous view
mflingdirection = 1;
}
if (currentoffset >= rolloffset)
{
// snap to next view
mflingdirection = -1;
}
}
private class flinggalleryview
{
private int mviewnumber;
private framelayout mparentlayout;

private framelayout minvalidlayout = null;
private linearlayout minternallayout = null;
private view mexternalview = null;
public flinggalleryview(int viewnumber, framelayout parentlayout)
{
mviewnumber = viewnumber;
mparentlayout = parentlayout;
// invalid layout is used when outside gallery
minvalidlayout = new framelayout(mcontext);
minvalidlayout.setlayoutparams(new linearlayout.layoutparams(
layoutparams.match_parent, layoutparams.match_parent));
// internal layout is permanent for duration
minternallayout = new linearlayout(mcontext);
minternallayout.setlayoutparams(new linearlayout.layoutparams(
layoutparams.match_parent, layoutparams.match_parent));
mparentlayout.addview(minternallayout);
}
public void recycleview(int newposition)
{
if (mexternalview != null)
{
minternallayout.removeview(mexternalview);
}
if (madapter != null)
{
if (newposition >= getfirstposition() && newposition <= getlastposition())
{
mexternalview = madapter.getview(newposition, mexternalview, minternallayout);
}
else
{
mexternalview = minvalidlayout;
}
}
if (mexternalview != null)
{
minternallayout.addview(mexternalview, new linearlayout.layoutparams(
layoutparams.match_parent, layoutparams.match_parent));
}
}
public void setoffset(int xoffset, int yoffset, int relativeviewnumber)
{
// scroll the target view relative to its own position relative to currently displayed view
minternallayout.scrollto(getviewoffset(mviewnumber, relativeviewnumber) + xoffset, yoffset);
}

public int getcurrentoffset()
{
// return the current scroll position
return minternallayout.getscrollx();
}
public void requestfocus()
{
minternallayout.requestfocus();
}
}
private class flinggalleryanimation extends animation
{
private boolean misanimationinprogres;
private int mrelativeviewnumber;
private int minitialoffset;
private int mtargetoffset;
private int mtargetdistance;
public flinggalleryanimation()
{
misanimationinprogres = false;
mrelativeviewnumber = 0;
minitialoffset = 0;
mtargetoffset = 0;
mtargetdistance = 0;
}
public void prepareanimation(int relativeviewnumber)
{
// if we are animating relative to a new view
if (mrelativeviewnumber != relativeviewnumber)
{
if (misanimationinprogres == true)
{
// we only have three views so if requested again to animate in same direction we must snap
int newdirection = (relativeviewnumber == getprevviewnumber(mrelativeviewnumber)) ? 1 : -1;
int animdirection = (mtargetdistance < 0) ? 1 : -1;
// if animation in same direction
if (animdirection == newdirection)
{
// ran out of time to animate so snap to the target offset
mviews[0].setoffset(mtargetoffset, 0, mrelativeviewnumber);
mviews[1].setoffset(mtargetoffset, 0, mrelativeviewnumber);
mviews[2].setoffset(mtargetoffset, 0, mrelativeviewnumber);
}
}

// set relative view number for animation
mrelativeviewnumber = relativeviewnumber;
}
// note: in this implementation the targetoffset will always be zero
// as we are centering the view; but we include the calculations of
// targetoffset and targetdistance for use in future implementations
minitialoffset = mviews[mrelativeviewnumber].getcurrentoffset();
mtargetoffset = getviewoffset(mrelativeviewnumber, mrelativeviewnumber);
mtargetdistance = mtargetoffset - minitialoffset;
// configure base animation properties
this.setduration(manimationduration);
this.setinterpolator(mdecelerateinterpolater);
// start/continued animation
misanimationinprogres = true;
}
@override
protected void applytransformation(float interpolatedtime, transformation transformation)
{
// ensure interpolatedtime does not over-shoot then calculate new offset
interpolatedtime = (interpolatedtime > 1.0f) ? 1.0f : interpolatedtime;
int offset = minitialoffset + (int) (mtargetdistance * interpolatedtime);
for (int viewnumber = 0; viewnumber < 3; viewnumber++)
{
// only need to animate the visible views as the other view will always be off-screen
if ((mtargetdistance > 0 && viewnumber != getnextviewnumber(mrelativeviewnumber)) ||
(mtargetdistance < 0 && viewnumber != getprevviewnumber(mrelativeviewnumber)))
{
mviews[viewnumber].setoffset(offset, 0, mrelativeviewnumber);
}
}
}
@override
public boolean gettransformation(long currenttime, transformation outtransformation)
{
if (super.gettransformation(currenttime, outtransformation) == false)
{
// perform final adjustment to offsets to cleanup animation
mviews[0].setoffset(mtargetoffset, 0, mrelativeviewnumber);
mviews[1].setoffset(mtargetoffset, 0, mrelativeviewnumber);
mviews[2].setoffset(mtargetoffset, 0, mrelativeviewnumber);
// reached the animation target
misanimationinprogres = false;
return false;
}
// cancel if the screen touched
if (mistouched || misdragging)
{
// note that at this point we still consider ourselves to be animating
// because we have not yet reached the target offset; its just that the
// user has temporarily interrupted the animation with a touch gesture
return false;
}
return true;
}
}
private class flinggesturedetector extends gesturedetector.simpleongesturelistener
{
@override
public boolean ondown(motionevent e)
{
// stop animation
mistouched = true;
// reset fling state
mflingdirection = 0;
return true;
}
@override
public boolean onscroll(motionevent e1, motionevent e2, float distancex, float distancey)
{
if (e2.getaction() == motionevent.action_move)
{
if (misdragging == false)
{
// stop animation
mistouched = true;

// reconfigure scroll
misdragging = true;
mflingdirection = 0;
mscrolltimestamp = system.currenttimemillis();
mcurrentoffset = mviews[mcurrentviewnumber].getcurrentoffset();
}
float maxvelocity = mgallerywidth / (manimationduration / 1000.0f);
long timestampdelta = system.currenttimemillis() - mscrolltimestamp;
float maxscrolldelta = maxvelocity * (timestampdelta / 1000.0f);
float currentscrolldelta = e1.getx() - e2.getx();
if (currentscrolldelta < maxscrolldelta * -1) currentscrolldelta = maxscrolldelta * -1;
if (currentscrolldelta > maxscrolldelta) currentscrolldelta = maxscrolldelta;
int scrolloffset = math.round(mcurrentoffset + currentscrolldelta);
// we can't scroll more than the width of our own frame layout
if (scrolloffset >= mgallerywidth) scrolloffset = mgallerywidth;
if (scrolloffset <= mgallerywidth * -1) scrolloffset = mgallerywidth * -1;

mviews[0].setoffset(scrolloffset, 0, mcurrentviewnumber);
mviews[1].setoffset(scrolloffset, 0, mcurrentviewnumber);
mviews[2].setoffset(scrolloffset, 0, mcurrentviewnumber);
}
return false;
}
@override
public boolean onfling(motionevent e1, motionevent e2, float velocityx, float velocityy)
{
if (math.abs(e1.gety() - e2.gety()) <= swipe_max_off_path)
{
if (e2.getx() - e1.getx() > swipe_min_distance && math.abs(velocityx) > swipe_threshold_veloicty)
{
moveprevious();
}
if(e1.getx() - e2.getx() > swipe_min_distance && math.abs(velocityx) > swipe_threshold_veloicty)
{
movenext();
}
}
return false;
}
@override
public void onlongpress(motionevent e)
{
// finalise scrolling
mflingdirection = 0;
processgesture();
}
@override
public void onshowpress(motionevent e)
{
}
@override
public boolean onsingletapup(motionevent e)
{
// reset fling state
mflingdirection = 0;
return false;
}
}
}