当前位置:  编程技术>移动开发
本页文章导读:
    ▪一个不那么完善的手势平滑拖动类FlingGallery        一个不那么完美的手势平滑拖动类FlingGallery 原帖看:http://www.eoeandroid.com/thread-70194-1-1.html或者看这个:android中的左右滑动http://www.iteye.com/topic/1102128之所以说其不完美是因为FlingGallery使用到.........
    ▪ 编纂和使用ContentProvicer的步骤        编写和使用ContentProvicer的步骤 编写:  1.编写一个类,继承android.content.ContentProvider 2.定义一个uri字符串,例如:   private static final String MY_URI = "com.test.dataContentProvider";   3.如果你的应用程序可以.........
    ▪ 编撰push notification之服务器端发送通知       编写push notification之服务器端发送通知 在编写push notification之获取device token中拿到device token以后,需要把token字符串发送给应用的服务器端,即provider。 provider将token号、通知内容、通知形式(.........

[1]一个不那么完善的手势平滑拖动类FlingGallery
    来源: 互联网  发布时间: 2014-02-18
一个不那么完美的手势平滑拖动类FlingGallery
原帖看:
http://www.eoeandroid.com/thread-70194-1-1.html
或者看这个:
android中的左右滑动
http://www.iteye.com/topic/1102128

之所以说其不完美是因为FlingGallery使用到了Adapter,这样会造成各界面的一致性,比较单一.如果能随便什么界面都能拖动就完美了.(什么?想要完美?我的博客里找!)
不过它的循环显示效果不错.
下面是它的源码:
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;
    	}
    }
}


测试代码:
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 String[] mLabelArray = { "View1", "View2", "View3", "View4",
			"View5" };
	private final int[] mColorArray = { Color.argb(100, 200, 0, 0),
			Color.argb(100, 0, 200, 0), Color.argb(100, 0, 0, 200),
			Color.argb(100, 200, 200, 0), Color.argb(100, 200, 0, 200) };

	private FlingGallery mGallery;
	private CheckBox mCheckBox;

	@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.setAnimationDuration(500);
		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);

				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.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));
		}
	}
}
1 楼 米其林的微笑 2011-09-03  
博主,你好,你所说的完美解决的是指你的哪篇文章呢,请指点一下。
还有一个问题想请教下,我用了FlingGallery 这个类,每个子View 都是一张图片,我用了回调先加载模糊图片然后再加载清晰图片,但是加载未完成发生滚动时,子View就无法更新了?项目卡在这里了,请博主指点一下!
2 楼 andsiban 2012-02-16  
各位开发者,这个类能滑动?难道你们的API比较特殊吗!滑动的关键方法onTouchEvent(MotionEvent event)都没有重写,用个onGalleryTouchEvent(MotionEvent event)方法,你们就能滑动了,真是牛人。  
3 楼 米其林的微笑 2012-02-22  
andsiban 写道
各位开发者,这个类能滑动?难道你们的API比较特殊吗!滑动的关键方法onTouchEvent(MotionEvent event)都没有重写,用个onGalleryTouchEvent(MotionEvent event)方法,你们就能滑动了,真是牛人。  

呵呵 你自己跑跑看不就知道了么 看起来是滑动的效果 就是真的滑动么 不能用动画么

    
[2] 编纂和使用ContentProvicer的步骤
    来源: 互联网  发布时间: 2014-02-18
编写和使用ContentProvicer的步骤

编写:

 1.编写一个类,继承android.content.ContentProvider
 2.定义一个uri字符串,例如:

 

private static final String MY_URI = "com.test.dataContentProvider";

 

3.如果你的应用程序可以提供多个ContentProvider,需要写几个path,例如

 

private static final String MY_PATH1 = "path1";
private static final String MY_PATH2 = "path1";

 

 

4.定义与你的path对应的代码,当匹配成功后,会返回这个代码,我们这里使用

 

public static final int SUCCESS1 = 1;
public static final int SUCCESS2 = 2;

  

 

 

 5.将uri添加到UriMatcher,例

 

static
{
	UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
	uriMatcher.addURI(MY_URI, MY_PATH1, SUCCESS1);
	uriMatcher.addURI(MY_URI, MY_PATH2, SUCCESS2);
}

 

如果你没用到path,则addURI的第二个参数设置为null 

 

 

 6.编写ContentProvider的方法,这里举例query方法

 

@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
	switch (uriMatcher.match(uri)) {
		case SUCCESS1: {//这个对应content://com.test.dataContentProvider/path1
			return null;
		 }
		case SUCCESS2:{//这个对应content://com.test.dataContentProvider/path2		{
			return null;
		}
	}
	return null;
}

 

 

 7.在AndroidManifest.xml中配置ContentProvider

 

<provider android:name="com.test.provider.DataContentProvider"
	android:authorities="com.test.dataContentProvider" />

com.test.provider.DataContentProvider是你的自定义的ContentProvider的路径,包括包名和类名

com.test.dataContentProvider是你在上面定义的MY_URI的值

 

使用:

 

 1.定义要使用的ContentProvider的URI字符串,注意:与编写ContentProvider时不同,这时定义的URI是完整的URI地址

 

private static final String MY_URI = "content://com.test.dataContentProvider";

  

如果你使用path了,则这么写

 

private static final String MY_URI1 = "content://com.test.dataContentProvider/path1";
private static final String MY_URI2 = "content://com.test.dataContentProvider/path2";

 

 

2.得到URI对象

 

Uri uri = Uri.parse(MY_URI);

 

 

 3.得到Cursor

 

Cursor cursor =  getContentResolver().query(uri, null, null, null, null);

 

 

 


    
[3] 编撰push notification之服务器端发送通知
    来源: 互联网  发布时间: 2014-02-18
编写push notification之服务器端发送通知

在编写push notification之获取device token中拿到device token以后,需要把token字符串发送给应用的服务器端,即provider。

provider将token号、通知内容、通知形式(比如是否弹出提示窗口、是否发声等)发送给苹果的服务器(apns)。

最简单的provider实现,其实就是通过证书,和苹果服务器建立安全连接(tsl或ssl),通过认证建立连接后,向苹果服务器发送符合苹果要求的数据流。

获得证书
苹果提供两种接入方式的证书:

developer,用于测试
production,用于产品

如果是内部测试,使用developer方式即可。

下载证书,通过ios provisioning portal:



这要求:

登录的apple developer program帐号必须是级别最高的agent(这是针对企业帐号来说的,如果是个人帐号就无所谓了),agent帐号即创始帐号,否则看不到configure链接;
必须经过configure操作,已经enable了developer和product。
然后进入configure链接,点击download按钮即可:






处理证书
如果是编写在mac下跑的objc程序,无需对证书做处理,可跳过这一步。

如果是在java下使用,需要把打证书用的私有专用密钥和上述的支持通知的证书(注意,不是iphone developer证书)合并导出。



生成证书:



点击存储的时候,会提示生成一个文件密码:



当然可以密码为空。

之后会提示:



这里需要输入mac登录用户的密码。

文件生成。

编写发送通知的实例


如果是编写mac代码,有一个现成的项目可用:http://stefan.hafeneger.name/download/PushMeBabySource.zip

导入到xcode中,只需将:



deviceToken填写成设备的token字符串,另外,pathForResource改为上面图中的:

aps_developer_identity

另外,要把刚才获得证书步骤中下载的证书复制到xcode项目Resources目录下:



可以看到文件名和上面的pathForResource的参数一致。

之后运行程序就可以在设备上收到推送通知。

如果是用java编写,可以用第三方库,见:

http://code.google.com/p/javapns/

编写简单的发送通知代码:

import org.json.JSONException;

import javapns.back.PushNotificationManager;
import javapns.back.SSLConnectionHelper;
import javapns.data.Device;
import javapns.data.PayLoad;

public class Main {

    /**
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
         PayLoad simplePayLoad = new PayLoad();
        // Get PushNotification Instance
         PushNotificationManager pushManager = PushNotificationManager.getInstance();
         // Link iPhone’s UDID (64-char device token) to a stringName
         pushManager.addDevice(&quot;iPhone&quot;, &quot;00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 &quot;);
         simplePayLoad.addAlert(&quot;My alert message测试&quot;);
         simplePayLoad.addBadge(1);
         simplePayLoad.addSound(&quot;default&quot;);
         Device client = PushNotificationManager.getInstance().getDevice(&quot;iPhone&quot;);
         PushNotificationManager.getInstance().initializeConnection(&quot;gateway.sandbox.push.apple.com&quot;, 2195, &quot;/home/ubuntu/mypush.p12&quot;, &quot;password&quot;, SSLConnectionHelper.KEYSTORE_TYPE_PKCS12);
         PushNotificationManager.getInstance().sendNotification(client, simplePayLoad);



测试中文没有乱码问题。

编写比较复杂的使用示例(可以控制通知是否有提示窗口、是否有提醒声音):

aPayload.addBadge( 2),显示在手机应用图标上的数字
aPayload.addAlert(&quot;软件版本有更新&quot;),显示提示窗口文字
aPayload.addSound(&quot;default.wav&quot;),指定提示声音
另外,也可以使用php的第三方实现,比如:

http://code.google.com/p/php-apns

基本原理是启动一个php服务,监控memcacheq队列,如果有消息就发送给苹果服务器

 


    
最新技术文章:
▪Android开发之登录验证实例教程
▪Android开发之注册登录方法示例
▪Android获取手机SIM卡运营商信息的方法
▪Android实现将已发送的短信写入短信数据库的...
▪Android发送短信功能代码
▪Android根据电话号码获得联系人头像实例代码
▪Android中GPS定位的用法实例
▪Android实现退出时关闭所有Activity的方法
▪Android实现文件的分割和组装
▪Android录音应用实例教程
▪Android双击返回键退出程序的实现方法
▪Android实现侦听电池状态显示、电量及充电动...
▪Android获取当前已连接的wifi信号强度的方法
▪Android实现动态显示或隐藏密码输入框的内容
▪根据USER-AGENT判断手机类型并跳转到相应的app...
▪Android Touch事件分发过程详解
▪Android中实现为TextView添加多个可点击的文本
▪Android程序设计之AIDL实例详解
▪Android显式启动与隐式启动Activity的区别介绍
▪Android按钮单击事件的四种常用写法总结
▪Android消息处理机制Looper和Handler详解
▪Android实现Back功能代码片段总结
▪Android实用的代码片段 常用代码总结
▪Android实现弹出键盘的方法
▪Android中通过view方式获取当前Activity的屏幕截...
▪Android提高之自定义Menu(TabMenu)实现方法
▪Android提高之多方向抽屉实现方法
▪Android提高之MediaPlayer播放网络音频的实现方法...
▪Android提高之MediaPlayer播放网络视频的实现方法...
▪Android提高之手游转电视游戏的模拟操控
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3