在Android界面特效中如何做出和墨迹天气及UC中左右拖动的效果

(国内知名Android开发论坛eoe开发者社区推荐:http://www.eoeandroid.com/

在Android界面特效中如何做出和墨迹天气及UC中左右拖动的效果

相信这么多手机APP中大家对墨迹天气和UC浏览器并不陌生,几乎很多人手机里都装有这两款应用,其中墨迹天气还出现在湖南卫视《天天向上》的节目中,受到大家的一度热捧!

那么,作为一名Android开发人员,在Android界面特效中如何做出和墨迹天气及UC中左右拖动的效果呢?

今天就来为大家分享相关的Android开发源代码:

1. [代码]FlingGalleryActivit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
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));
        }
    }
}

 

2. [代码]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;
        }
    }
}

 上述这些Android源代码分享仅供大家参考使用,如有不懂,可留言在下面!希望可以帮助大家在Android界面特效中实现和墨迹天气及UC一样的左右拖动效果!

    更多Android开发源码及Android开发交流 请关注eoe移动开发者社区:http://www.eoeandroid.com/

posted on   vus520  阅读(750)  评论(1编辑  收藏  举报

编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
历史上的今天:
2012-09-18 android 问题汇总系列之五
2012-09-18 Android Debug Bridge 技术实现原理

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示