使用 ViewPager 实现 iOS 应用程序关闭垂直滑动关闭功能
Implement feature like iOS app closing vertical Swipe-to-Dismiss with ViewPager
我目前在 ViewPager 中水平排列了多个视图,并且可以使用 PagerAdapter 循环浏览它们。目前,要执行我想在滑动时执行的操作,我必须在视图页面上双击。我可以 post 编码,但是提取必要的部分有点困难...
我想要的是能够在这些视图上垂直滑动,让它们通过滑动和淡出垂直平移,然后在它们到达距设备边缘一定距离时执行操作。
为了了解我在想什么,在图库应用中,您可以捏合打开的照片以缩小并打开水平胶片视图。从那里你可以向上(或向下)滑动 photo/video 来删除它。对于那些没有相同 Gallery 应用程序的人来说,这就像在 iOS 上关闭应用程序一样。
我尝试扫描图库应用程序的源代码,但没能找到正确的 Activity。
view.setOnTouchListener(new View.OnTouchListener(){
public boolean onTouch(View v, MotionEvent motion) {
float y = motion.getY();
/* NOTE: the following line might need to be in runOnUiThread() */
view.animate().alpha(1-Math.abs(y-height/2)/(height/2)).setDuration(50).start();
return true; //false if you want to pass this event on to other listeners
}
});
使用1-Math.abs(y-height/2)/(height/2)
的解释是我想让alpha在中心的时候为1,在顶部或者底部的时候alpha为0。您必须自己确定如何获得 height
值,或者是否要使用不同的方法来计算 alpha。如果你想获得触摸相对于屏幕的位置而不是相对于视图的位置,使用getRawY()
。
此外,了解 MotionEvent 是按下、拖动还是释放事件可能对您有用,请使用
motion.getAction() ==
分别为 MotionEvent.ACTION_UP、MotionEvent.ACTION_MOVE 和 MotionEvent.ACTION_DOWN。
检查下面的代码,这可能对你有帮助:
public class MainActivity extends Activity implements View.OnTouchListener{
private RelativeLayout baseLayout;
private int previousFingerPosition = 0;
private int baseLayoutPosition = 0;
private int defaultViewHeight;
private boolean isClosing = false;
private boolean isScrollingUp = false;
private boolean isScrollingDown = false;
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_popup);
baseLayout = (RelativeLayout) findViewById(R.id.base_popup_layout);//this is the main layout
baseLayout.setOnTouchListener(this);
}
public boolean onTouch(View view, MotionEvent event) {
// Get finger position on screen
final int Y = (int) event.getRawY();
// Switch on motion event type
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
// save default base layout height
defaultViewHeight = baseLayout.getHeight();
// Init finger and view position
previousFingerPosition = Y;
baseLayoutPosition = (int) baseLayout.getY();
break;
case MotionEvent.ACTION_UP:
// If user was doing a scroll up
if(isScrollingUp){
// Reset baselayout position
baseLayout.setY(0);
// We are not in scrolling up mode anymore
isScrollingUp = false;
}
// If user was doing a scroll down
if(isScrollingDown){
// Reset baselayout position
baseLayout.setY(0);
// Reset base layout size
baseLayout.getLayoutParams().height = defaultViewHeight;
baseLayout.requestLayout();
// We are not in scrolling down mode anymore
isScrollingDown = false;
}
break;
case MotionEvent.ACTION_MOVE:
if(!isClosing){
int currentYPosition = (int) baseLayout.getY();
// If we scroll up
if(previousFingerPosition >Y){
// First time android rise an event for "up" move
if(!isScrollingUp){
isScrollingUp = true;
}
// Has user scroll down before -> view is smaller than it's default size -> resize it instead of change it position
if(baseLayout.getHeight()<defaultViewHeight){
baseLayout.getLayoutParams().height = baseLayout.getHeight() - (Y - previousFingerPosition);
baseLayout.requestLayout();
}
else {
// Has user scroll enough to "auto close" popup ?
if ((baseLayoutPosition - currentYPosition) > defaultViewHeight / 4) {
closeUpAndDismissDialog(currentYPosition);
return true;
}
//
}
baseLayout.setY(baseLayout.getY() + (Y - previousFingerPosition));
}
// If we scroll down
else{
// First time android rise an event for "down" move
if(!isScrollingDown){
isScrollingDown = true;
}
// Has user scroll enough to "auto close" popup ?
if (Math.abs(baseLayoutPosition - currentYPosition) > defaultViewHeight / 2)
{
closeDownAndDismissDialog(currentYPosition);
return true;
}
// Change base layout size and position (must change position because view anchor is top left corner)
baseLayout.setY(baseLayout.getY() + (Y - previousFingerPosition));
baseLayout.getLayoutParams().height = baseLayout.getHeight() - (Y - previousFingerPosition);
baseLayout.requestLayout();
}
// Update position
previousFingerPosition = Y;
}
break;
}
return true;
}
}
动画使用以下方法:
public void closeUpAndDismissDialog(int currentPosition){
isClosing = true;
ObjectAnimator positionAnimator = ObjectAnimator.ofFloat(baseLayout, "y", currentPosition, -baseLayout.getHeight());
positionAnimator.setDuration(300);
positionAnimator.addListener(new Animator.AnimatorListener()
{
. . .
@Override
public void onAnimationEnd(Animator animator)
{
finish();
}
. . .
});
positionAnimator.start();
}
public void closeDownAndDismissDialog(int currentPosition){
isClosing = true;
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int screenHeight = size.y;
ObjectAnimator positionAnimator = ObjectAnimator.ofFloat(baseLayout, "y", currentPosition, screenHeight+baseLayout.getHeight());
positionAnimator.setDuration(300);
positionAnimator.addListener(new Animator.AnimatorListener()
{
. . .
@Override
public void onAnimationEnd(Animator animator)
{
finish();
}
. . .
});
positionAnimator.start();
}
我最终通过克隆编写良好的 Android-SwipeToDismiss 库并将 ListView 代码替换为 ViewPager 来或多或少地使它工作。
成品是这样的。
我目前在 ViewPager 中水平排列了多个视图,并且可以使用 PagerAdapter 循环浏览它们。目前,要执行我想在滑动时执行的操作,我必须在视图页面上双击。我可以 post 编码,但是提取必要的部分有点困难...
我想要的是能够在这些视图上垂直滑动,让它们通过滑动和淡出垂直平移,然后在它们到达距设备边缘一定距离时执行操作。
为了了解我在想什么,在图库应用中,您可以捏合打开的照片以缩小并打开水平胶片视图。从那里你可以向上(或向下)滑动 photo/video 来删除它。对于那些没有相同 Gallery 应用程序的人来说,这就像在 iOS 上关闭应用程序一样。
我尝试扫描图库应用程序的源代码,但没能找到正确的 Activity。
view.setOnTouchListener(new View.OnTouchListener(){
public boolean onTouch(View v, MotionEvent motion) {
float y = motion.getY();
/* NOTE: the following line might need to be in runOnUiThread() */
view.animate().alpha(1-Math.abs(y-height/2)/(height/2)).setDuration(50).start();
return true; //false if you want to pass this event on to other listeners
}
});
使用1-Math.abs(y-height/2)/(height/2)
的解释是我想让alpha在中心的时候为1,在顶部或者底部的时候alpha为0。您必须自己确定如何获得 height
值,或者是否要使用不同的方法来计算 alpha。如果你想获得触摸相对于屏幕的位置而不是相对于视图的位置,使用getRawY()
。
此外,了解 MotionEvent 是按下、拖动还是释放事件可能对您有用,请使用
motion.getAction() ==
分别为 MotionEvent.ACTION_UP、MotionEvent.ACTION_MOVE 和 MotionEvent.ACTION_DOWN。
检查下面的代码,这可能对你有帮助:
public class MainActivity extends Activity implements View.OnTouchListener{
private RelativeLayout baseLayout;
private int previousFingerPosition = 0;
private int baseLayoutPosition = 0;
private int defaultViewHeight;
private boolean isClosing = false;
private boolean isScrollingUp = false;
private boolean isScrollingDown = false;
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_popup);
baseLayout = (RelativeLayout) findViewById(R.id.base_popup_layout);//this is the main layout
baseLayout.setOnTouchListener(this);
}
public boolean onTouch(View view, MotionEvent event) {
// Get finger position on screen
final int Y = (int) event.getRawY();
// Switch on motion event type
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
// save default base layout height
defaultViewHeight = baseLayout.getHeight();
// Init finger and view position
previousFingerPosition = Y;
baseLayoutPosition = (int) baseLayout.getY();
break;
case MotionEvent.ACTION_UP:
// If user was doing a scroll up
if(isScrollingUp){
// Reset baselayout position
baseLayout.setY(0);
// We are not in scrolling up mode anymore
isScrollingUp = false;
}
// If user was doing a scroll down
if(isScrollingDown){
// Reset baselayout position
baseLayout.setY(0);
// Reset base layout size
baseLayout.getLayoutParams().height = defaultViewHeight;
baseLayout.requestLayout();
// We are not in scrolling down mode anymore
isScrollingDown = false;
}
break;
case MotionEvent.ACTION_MOVE:
if(!isClosing){
int currentYPosition = (int) baseLayout.getY();
// If we scroll up
if(previousFingerPosition >Y){
// First time android rise an event for "up" move
if(!isScrollingUp){
isScrollingUp = true;
}
// Has user scroll down before -> view is smaller than it's default size -> resize it instead of change it position
if(baseLayout.getHeight()<defaultViewHeight){
baseLayout.getLayoutParams().height = baseLayout.getHeight() - (Y - previousFingerPosition);
baseLayout.requestLayout();
}
else {
// Has user scroll enough to "auto close" popup ?
if ((baseLayoutPosition - currentYPosition) > defaultViewHeight / 4) {
closeUpAndDismissDialog(currentYPosition);
return true;
}
//
}
baseLayout.setY(baseLayout.getY() + (Y - previousFingerPosition));
}
// If we scroll down
else{
// First time android rise an event for "down" move
if(!isScrollingDown){
isScrollingDown = true;
}
// Has user scroll enough to "auto close" popup ?
if (Math.abs(baseLayoutPosition - currentYPosition) > defaultViewHeight / 2)
{
closeDownAndDismissDialog(currentYPosition);
return true;
}
// Change base layout size and position (must change position because view anchor is top left corner)
baseLayout.setY(baseLayout.getY() + (Y - previousFingerPosition));
baseLayout.getLayoutParams().height = baseLayout.getHeight() - (Y - previousFingerPosition);
baseLayout.requestLayout();
}
// Update position
previousFingerPosition = Y;
}
break;
}
return true;
}
}
动画使用以下方法:
public void closeUpAndDismissDialog(int currentPosition){
isClosing = true;
ObjectAnimator positionAnimator = ObjectAnimator.ofFloat(baseLayout, "y", currentPosition, -baseLayout.getHeight());
positionAnimator.setDuration(300);
positionAnimator.addListener(new Animator.AnimatorListener()
{
. . .
@Override
public void onAnimationEnd(Animator animator)
{
finish();
}
. . .
});
positionAnimator.start();
}
public void closeDownAndDismissDialog(int currentPosition){
isClosing = true;
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int screenHeight = size.y;
ObjectAnimator positionAnimator = ObjectAnimator.ofFloat(baseLayout, "y", currentPosition, screenHeight+baseLayout.getHeight());
positionAnimator.setDuration(300);
positionAnimator.addListener(new Animator.AnimatorListener()
{
. . .
@Override
public void onAnimationEnd(Animator animator)
{
finish();
}
. . .
});
positionAnimator.start();
}
我最终通过克隆编写良好的 Android-SwipeToDismiss 库并将 ListView 代码替换为 ViewPager 来或多或少地使它工作。
成品是这样的。