当前位置: 首页>>代码示例>>C#>>正文


C# android.getPointerId方法代码示例

本文整理汇总了C#中android.getPointerId方法的典型用法代码示例。如果您正苦于以下问题:C# android.getPointerId方法的具体用法?C# android.getPointerId怎么用?C# android.getPointerId使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在android的用法示例。


在下文中一共展示了android.getPointerId方法的9个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C#代码示例。

示例1: onTouchEvent

		/// <summary>Checks a touch event.</summary>
		/// <remarks>Checks a touch event.</remarks>
		/// <param name="event">The event.</param>
		/// <param name="nestingLevel">
		/// The nesting level: 0 if called from the base class,
		/// or 1 from a subclass.  If the event was already checked by this consistency verifier
		/// at a higher nesting level, it will not be checked again.  Used to handle the situation
		/// where a subclass dispatching method delegates to its superclass's dispatching method
		/// and both dispatching methods call into the consistency verifier.
		/// </param>
		public void onTouchEvent(android.view.MotionEvent @event, int nestingLevel)
		{
			if (!startEvent(@event, nestingLevel, EVENT_TYPE_TOUCH))
			{
				return;
			}
			int action = @event.getAction();
			bool newStream = action == android.view.MotionEvent.ACTION_DOWN || action == android.view.MotionEvent
				.ACTION_CANCEL;
			if (newStream && (mTouchEventStreamIsTainted || mTouchEventStreamUnhandled))
			{
				mTouchEventStreamIsTainted = false;
				mTouchEventStreamUnhandled = false;
				mTouchEventStreamPointers = 0;
			}
			if (mTouchEventStreamIsTainted)
			{
				@event.setTainted(true);
			}
			try
			{
				ensureMetaStateIsNormalized(@event.getMetaState());
				int deviceId = @event.getDeviceId();
				int source = @event.getSource();
				if (!newStream && mTouchEventStreamDeviceId != -1 && (mTouchEventStreamDeviceId !=
					 deviceId || mTouchEventStreamSource != source))
				{
					problem("Touch event stream contains events from multiple sources: " + "previous device id "
						 + mTouchEventStreamDeviceId + ", previous source " + Sharpen.Util.IntToHexString
						(mTouchEventStreamSource) + ", new device id " + deviceId + ", new source " + Sharpen.Util.IntToHexString
						(source));
				}
				mTouchEventStreamDeviceId = deviceId;
				mTouchEventStreamSource = source;
				int pointerCount = @event.getPointerCount();
				if ((source & android.view.InputDevice.SOURCE_CLASS_POINTER) != 0)
				{
					switch (action)
					{
						case android.view.MotionEvent.ACTION_DOWN:
						{
							if (mTouchEventStreamPointers != 0)
							{
								problem("ACTION_DOWN but pointers are already down.  " + "Probably missing ACTION_UP from previous gesture."
									);
							}
							ensureHistorySizeIsZeroForThisAction(@event);
							ensurePointerCountIsOneForThisAction(@event);
							mTouchEventStreamPointers = 1 << @event.getPointerId(0);
							break;
						}

						case android.view.MotionEvent.ACTION_UP:
						{
							ensureHistorySizeIsZeroForThisAction(@event);
							ensurePointerCountIsOneForThisAction(@event);
							mTouchEventStreamPointers = 0;
							mTouchEventStreamIsTainted = false;
							break;
						}

						case android.view.MotionEvent.ACTION_MOVE:
						{
							int expectedPointerCount = Sharpen.Util.IntGetBitCount(mTouchEventStreamPointers);
							if (pointerCount != expectedPointerCount)
							{
								problem("ACTION_MOVE contained " + pointerCount + " pointers but there are currently "
									 + expectedPointerCount + " pointers down.");
								mTouchEventStreamIsTainted = true;
							}
							break;
						}

						case android.view.MotionEvent.ACTION_CANCEL:
						{
							mTouchEventStreamPointers = 0;
							mTouchEventStreamIsTainted = false;
							break;
						}

						case android.view.MotionEvent.ACTION_OUTSIDE:
						{
							if (mTouchEventStreamPointers != 0)
							{
								problem("ACTION_OUTSIDE but pointers are still down.");
							}
							ensureHistorySizeIsZeroForThisAction(@event);
							ensurePointerCountIsOneForThisAction(@event);
							mTouchEventStreamIsTainted = false;
							break;
//.........这里部分代码省略.........
开发者ID:hakeemsm,项目名称:XobotOS,代码行数:101,代码来源:InputEventConsistencyVerifier.cs

示例2: dispatchTouchEvent

		public override bool dispatchTouchEvent(android.view.MotionEvent ev)
		{
			if (mInputEventConsistencyVerifier != null)
			{
				mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
			}
			bool handled = false;
			if (onFilterTouchEventForSecurity(ev))
			{
				int action = ev.getAction();
				int actionMasked = action & android.view.MotionEvent.ACTION_MASK;
				// Handle an initial down.
				if (actionMasked == android.view.MotionEvent.ACTION_DOWN)
				{
					// Throw away all previous state when starting a new touch gesture.
					// The framework may have dropped the up or cancel event for the previous gesture
					// due to an app switch, ANR, or some other state change.
					cancelAndClearTouchTargets(ev);
					resetTouchState();
				}
				// Check for interception.
				bool intercepted;
				if (actionMasked == android.view.MotionEvent.ACTION_DOWN || mFirstTouchTarget != 
					null)
				{
					bool disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
					if (!disallowIntercept)
					{
						intercepted = onInterceptTouchEvent(ev);
						ev.setAction(action);
					}
					else
					{
						// restore action in case it was changed
						intercepted = false;
					}
				}
				else
				{
					// There are no touch targets and this action is not an initial down
					// so this view group continues to intercept touches.
					intercepted = true;
				}
				// Check for cancelation.
				bool canceled = resetCancelNextUpFlag(this) || actionMasked == android.view.MotionEvent
					.ACTION_CANCEL;
				// Update list of touch targets for pointer down, if needed.
				bool split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
				android.view.ViewGroup.TouchTarget newTouchTarget = null;
				bool alreadyDispatchedToNewTouchTarget = false;
				if (!canceled && !intercepted)
				{
					if (actionMasked == android.view.MotionEvent.ACTION_DOWN || (split && actionMasked
						 == android.view.MotionEvent.ACTION_POINTER_DOWN) || actionMasked == android.view.MotionEvent
						.ACTION_HOVER_MOVE)
					{
						int actionIndex = ev.getActionIndex();
						// always 0 for down
						int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex) : android.view.ViewGroup
							.TouchTarget.ALL_POINTER_IDS;
						// Clean up earlier touch targets for this pointer id in case they
						// have become out of sync.
						removePointersFromTouchTargets(idBitsToAssign);
						int childrenCount = mChildrenCount;
						if (childrenCount != 0)
						{
							// Find a child that can receive the event.
							// Scan children from front to back.
							android.view.View[] children = mChildren;
							float x = ev.getX(actionIndex);
							float y = ev.getY(actionIndex);
							{
								for (int i = childrenCount - 1; i >= 0; i--)
								{
									android.view.View child = children[i];
									if (!canViewReceivePointerEvents(child) || !isTransformedTouchPointInView(x, y, child
										, null))
									{
										continue;
									}
									newTouchTarget = getTouchTarget(child);
									if (newTouchTarget != null)
									{
										// Child is already receiving touch within its bounds.
										// Give it the new pointer in addition to the ones it is handling.
										newTouchTarget.pointerIdBits |= idBitsToAssign;
										break;
									}
									resetCancelNextUpFlag(child);
									if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign))
									{
										// Child wants to receive touch within its bounds.
										mLastTouchDownTime = ev.getDownTime();
										mLastTouchDownIndex = i;
										mLastTouchDownX = ev.getX();
										mLastTouchDownY = ev.getY();
										newTouchTarget = addTouchTarget(child, idBitsToAssign);
										alreadyDispatchedToNewTouchTarget = true;
										break;
									}
//.........这里部分代码省略.........
开发者ID:hakeemsm,项目名称:XobotOS,代码行数:101,代码来源:ViewGroup.cs

示例3: onSecondaryPointerUp

		private void onSecondaryPointerUp(android.view.MotionEvent ev)
		{
			int pointerIndex = (ev.getAction() & android.view.MotionEvent.ACTION_POINTER_INDEX_MASK
				) >> android.view.MotionEvent.ACTION_POINTER_INDEX_SHIFT;
			int pointerId = ev.getPointerId(pointerIndex);
			if (pointerId == mActivePointerId)
			{
				// This was our active pointer going up. Choose a new
				// active pointer and adjust accordingly.
				// TODO: Make this decision more intelligent.
				int newPointerIndex = pointerIndex == 0 ? 1 : 0;
				mLastMotionX = ev.getX(newPointerIndex);
				mActivePointerId = ev.getPointerId(newPointerIndex);
				if (mVelocityTracker != null)
				{
					mVelocityTracker.clear();
				}
			}
		}
开发者ID:hakeemsm,项目名称:XobotOS,代码行数:19,代码来源:HorizontalScrollView.cs

示例4: onTouchEvent

		public virtual bool onTouchEvent(android.view.MotionEvent @event)
		{
			if (mInputEventConsistencyVerifier != null)
			{
				mInputEventConsistencyVerifier.onTouchEvent(@event, 0);
			}
			int action = @event.getActionMasked();
			if (action == android.view.MotionEvent.ACTION_DOWN)
			{
				reset();
			}
			// Start fresh
			bool handled = true;
			if (mInvalidGesture)
			{
				handled = false;
			}
			else
			{
				if (!mGestureInProgress)
				{
					switch (action)
					{
						case android.view.MotionEvent.ACTION_DOWN:
						{
							mActiveId0 = @event.getPointerId(0);
							mActive0MostRecent = true;
							break;
						}

						case android.view.MotionEvent.ACTION_UP:
						{
							reset();
							break;
						}

						case android.view.MotionEvent.ACTION_POINTER_DOWN:
						{
							// We have a new multi-finger gesture
							// as orientation can change, query the metrics in touch down
							android.util.DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
							mRightSlopEdge = metrics.widthPixels - mEdgeSlop;
							mBottomSlopEdge = metrics.heightPixels - mEdgeSlop;
							if (mPrevEvent != null)
							{
								mPrevEvent.recycle();
							}
							mPrevEvent = android.view.MotionEvent.obtain(@event);
							mTimeDelta = 0;
							int index1 = @event.getActionIndex();
							int index0 = @event.findPointerIndex(mActiveId0);
							mActiveId1 = @event.getPointerId(index1);
							if (index0 < 0 || index0 == index1)
							{
								// Probably someone sending us a broken event stream.
								index0 = findNewActiveIndex(@event, index0 == index1 ? -1 : mActiveId1, index0);
								mActiveId0 = @event.getPointerId(index0);
							}
							mActive0MostRecent = false;
							setContext(@event);
							// Check if we have a sloppy gesture. If so, delay
							// the beginning of the gesture until we're sure that's
							// what the user wanted. Sloppy gestures can happen if the
							// edge of the user's hand is touching the screen, for example.
							float edgeSlop = mEdgeSlop;
							float rightSlop = mRightSlopEdge;
							float bottomSlop = mBottomSlopEdge;
							float x0 = getRawX(@event, index0);
							float y0 = getRawY(@event, index0);
							float x1 = getRawX(@event, index1);
							float y1 = getRawY(@event, index1);
							bool p0sloppy = x0 < edgeSlop || y0 < edgeSlop || x0 > rightSlop || y0 > bottomSlop;
							bool p1sloppy = x1 < edgeSlop || y1 < edgeSlop || x1 > rightSlop || y1 > bottomSlop;
							if (p0sloppy && p1sloppy)
							{
								mFocusX = -1;
								mFocusY = -1;
								mSloppyGesture = true;
							}
							else
							{
								if (p0sloppy)
								{
									mFocusX = @event.getX(index1);
									mFocusY = @event.getY(index1);
									mSloppyGesture = true;
								}
								else
								{
									if (p1sloppy)
									{
										mFocusX = @event.getX(index0);
										mFocusY = @event.getY(index0);
										mSloppyGesture = true;
									}
									else
									{
										mSloppyGesture = false;
										mGestureInProgress = mListener.onScaleBegin(this);
									}
//.........这里部分代码省略.........
开发者ID:hakeemsm,项目名称:XobotOS,代码行数:101,代码来源:ScaleGestureDetector.cs

示例5: onTouchEvent

		public override bool onTouchEvent(android.view.MotionEvent ev)
		{
			initVelocityTrackerIfNotExists();
			mVelocityTracker.addMovement(ev);
			int action = ev.getAction();
			switch (action & android.view.MotionEvent.ACTION_MASK)
			{
				case android.view.MotionEvent.ACTION_DOWN:
				{
					mIsBeingDragged = getChildCount() != 0;
					if (!mIsBeingDragged)
					{
						return false;
					}
					if (!mScroller.isFinished())
					{
						mScroller.abortAnimation();
					}
					// Remember where the motion event started
					mLastMotionX = ev.getX();
					mActivePointerId = ev.getPointerId(0);
					break;
				}

				case android.view.MotionEvent.ACTION_MOVE:
				{
					if (mIsBeingDragged)
					{
						// Scroll to follow the motion event
						int activePointerIndex = ev.findPointerIndex(mActivePointerId);
						float x = ev.getX(activePointerIndex);
						int deltaX = (int)(mLastMotionX - x);
						mLastMotionX = x;
						int oldX = mScrollX;
						int oldY = mScrollY;
						int range = getScrollRange();
						int overscrollMode = getOverScrollMode();
						bool canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS || (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS
							 && range > 0);
						if (overScrollBy(deltaX, 0, mScrollX, 0, range, 0, mOverscrollDistance, 0, true))
						{
							// Break our velocity if we hit a scroll barrier.
							mVelocityTracker.clear();
						}
						onScrollChanged(mScrollX, mScrollY, oldX, oldY);
						if (canOverscroll)
						{
							int pulledToX = oldX + deltaX;
							if (pulledToX < 0)
							{
								mEdgeGlowLeft.onPull((float)deltaX / getWidth());
								if (!mEdgeGlowRight.isFinished())
								{
									mEdgeGlowRight.onRelease();
								}
							}
							else
							{
								if (pulledToX > range)
								{
									mEdgeGlowRight.onPull((float)deltaX / getWidth());
									if (!mEdgeGlowLeft.isFinished())
									{
										mEdgeGlowLeft.onRelease();
									}
								}
							}
							if (mEdgeGlowLeft != null && (!mEdgeGlowLeft.isFinished() || !mEdgeGlowRight.isFinished
								()))
							{
								invalidate();
							}
						}
					}
					break;
				}

				case android.view.MotionEvent.ACTION_UP:
				{
					if (mIsBeingDragged)
					{
						android.view.VelocityTracker velocityTracker = mVelocityTracker;
						velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
						int initialVelocity = (int)velocityTracker.getXVelocity(mActivePointerId);
						if (getChildCount() > 0)
						{
							if ((System.Math.Abs(initialVelocity) > mMinimumVelocity))
							{
								fling(-initialVelocity);
							}
							else
							{
								if (mScroller.springBack(mScrollX, mScrollY, 0, getScrollRange(), 0, 0))
								{
									invalidate();
								}
							}
						}
						mActivePointerId = INVALID_POINTER;
						mIsBeingDragged = false;
//.........这里部分代码省略.........
开发者ID:hakeemsm,项目名称:XobotOS,代码行数:101,代码来源:HorizontalScrollView.cs

示例6: onInterceptTouchEvent

		public override bool onInterceptTouchEvent(android.view.MotionEvent ev)
		{
			int action = ev.getAction();
			if ((action == android.view.MotionEvent.ACTION_MOVE) && (mIsBeingDragged))
			{
				return true;
			}
			switch (action & android.view.MotionEvent.ACTION_MASK)
			{
				case android.view.MotionEvent.ACTION_MOVE:
				{
					int activePointerId = mActivePointerId;
					if (activePointerId == INVALID_POINTER)
					{
						// If we don't have a valid id, the touch down wasn't on content.
						break;
					}
					int pointerIndex = ev.findPointerIndex(activePointerId);
					float x = ev.getX(pointerIndex);
					int xDiff = (int)System.Math.Abs(x - mLastMotionX);
					if (xDiff > mTouchSlop)
					{
						mIsBeingDragged = true;
						mLastMotionX = x;
						initVelocityTrackerIfNotExists();
						mVelocityTracker.addMovement(ev);
						if (mParent != null)
						{
							mParent.requestDisallowInterceptTouchEvent(true);
						}
					}
					break;
				}

				case android.view.MotionEvent.ACTION_DOWN:
				{
					float x = ev.getX();
					if (!inChild((int)x, (int)ev.getY()))
					{
						mIsBeingDragged = false;
						recycleVelocityTracker();
						break;
					}
					mLastMotionX = x;
					mActivePointerId = ev.getPointerId(0);
					initOrResetVelocityTracker();
					mVelocityTracker.addMovement(ev);
					mIsBeingDragged = !mScroller.isFinished();
					break;
				}

				case android.view.MotionEvent.ACTION_CANCEL:
				case android.view.MotionEvent.ACTION_UP:
				{
					mIsBeingDragged = false;
					mActivePointerId = INVALID_POINTER;
					if (mScroller.springBack(mScrollX, mScrollY, 0, getScrollRange(), 0, 0))
					{
						invalidate();
					}
					break;
				}

				case android.view.MotionEvent.ACTION_POINTER_DOWN:
				{
					int index = ev.getActionIndex();
					mLastMotionX = ev.getX(index);
					mActivePointerId = ev.getPointerId(index);
					break;
				}

				case android.view.MotionEvent.ACTION_POINTER_UP:
				{
					onSecondaryPointerUp(ev);
					mLastMotionX = ev.getX(ev.findPointerIndex(mActivePointerId));
					break;
				}
			}
			return mIsBeingDragged;
		}
开发者ID:hakeemsm,项目名称:XobotOS,代码行数:80,代码来源:HorizontalScrollView.cs

示例7: onSecondaryPointerUp

		private void onSecondaryPointerUp(android.view.MotionEvent ev)
		{
			int activePointerIndex = ev.getActionIndex();
			int pointerId = ev.getPointerId(activePointerIndex);
			if (pointerId == mActivePointerId)
			{
				int activeViewIndex = (mSwipeGestureType == GESTURE_SLIDE_DOWN) ? 0 : 1;
				android.view.View v = getViewAtRelativeIndex(activeViewIndex);
				if (v == null)
				{
					return;
				}
				{
					// Our primary pointer has gone up -- let's see if we can find
					// another pointer on the view. If so, then we should replace
					// our primary pointer with this new pointer and adjust things
					// so that the view doesn't jump
					for (int index = 0; index < ev.getPointerCount(); index++)
					{
						if (index != activePointerIndex)
						{
							float x = ev.getX(index);
							float y = ev.getY(index);
							mTouchRect.set(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
							if (mTouchRect.contains(Sharpen.Util.Round(x), Sharpen.Util.Round(y)))
							{
								float oldX = ev.getX(activePointerIndex);
								float oldY = ev.getY(activePointerIndex);
								// adjust our frame of reference to avoid a jump
								mInitialY += (y - oldY);
								mInitialX += (x - oldX);
								mActivePointerId = ev.getPointerId(index);
								if (mVelocityTracker != null)
								{
									mVelocityTracker.clear();
								}
								// ok, we're good, we found a new pointer which is touching the active view
								return;
							}
						}
					}
				}
				// if we made it this far, it means we didn't find a satisfactory new pointer :(,
				// so end the gesture
				handlePointerUp(ev);
			}
		}
开发者ID:hakeemsm,项目名称:XobotOS,代码行数:47,代码来源:StackView.cs

示例8: onInterceptTouchEvent

		public override bool onInterceptTouchEvent(android.view.MotionEvent ev)
		{
			int action = ev.getAction();
			switch (action & android.view.MotionEvent.ACTION_MASK)
			{
				case android.view.MotionEvent.ACTION_DOWN:
				{
					if (mActivePointerId == INVALID_POINTER)
					{
						mInitialX = ev.getX();
						mInitialY = ev.getY();
						mActivePointerId = ev.getPointerId(0);
					}
					break;
				}

				case android.view.MotionEvent.ACTION_MOVE:
				{
					int pointerIndex = ev.findPointerIndex(mActivePointerId);
					if (pointerIndex == INVALID_POINTER)
					{
						// no data for our primary pointer, this shouldn't happen, log it
						android.util.Log.d(TAG, "Error: No data for our primary pointer.");
						return false;
					}
					float newY = ev.getY(pointerIndex);
					float deltaY = newY - mInitialY;
					beginGestureIfNeeded(deltaY);
					break;
				}

				case android.view.MotionEvent.ACTION_POINTER_UP:
				{
					onSecondaryPointerUp(ev);
					break;
				}

				case android.view.MotionEvent.ACTION_UP:
				case android.view.MotionEvent.ACTION_CANCEL:
				{
					mActivePointerId = INVALID_POINTER;
					mSwipeGestureType = GESTURE_NONE;
					break;
				}
			}
			return mSwipeGestureType != GESTURE_NONE;
		}
开发者ID:hakeemsm,项目名称:XobotOS,代码行数:47,代码来源:StackView.cs

示例9: onInterceptTouchEvent

		public override bool onInterceptTouchEvent(android.view.MotionEvent ev)
		{
			int action = ev.getAction();
			if ((action == android.view.MotionEvent.ACTION_MOVE) && (mIsBeingDragged))
			{
				return true;
			}
			switch (action & android.view.MotionEvent.ACTION_MASK)
			{
				case android.view.MotionEvent.ACTION_MOVE:
				{
					int activePointerId = mActivePointerId;
					if (activePointerId == INVALID_POINTER)
					{
						// If we don't have a valid id, the touch down wasn't on content.
						break;
					}
					int pointerIndex = ev.findPointerIndex(activePointerId);
					float y = ev.getY(pointerIndex);
					int yDiff = (int)System.Math.Abs(y - mLastMotionY);
					if (yDiff > mTouchSlop)
					{
						mIsBeingDragged = true;
						mLastMotionY = y;
						initVelocityTrackerIfNotExists();
						mVelocityTracker.addMovement(ev);
						if (mScrollStrictSpan == null)
						{
							mScrollStrictSpan = android.os.StrictMode.enterCriticalSpan("ScrollView-scroll");
						}
					}
					break;
				}

				case android.view.MotionEvent.ACTION_DOWN:
				{
					float y = ev.getY();
					if (!inChild((int)ev.getX(), (int)y))
					{
						mIsBeingDragged = false;
						recycleVelocityTracker();
						break;
					}
					mLastMotionY = y;
					mActivePointerId = ev.getPointerId(0);
					initOrResetVelocityTracker();
					mVelocityTracker.addMovement(ev);
					mIsBeingDragged = !mScroller.isFinished();
					if (mIsBeingDragged && mScrollStrictSpan == null)
					{
						mScrollStrictSpan = android.os.StrictMode.enterCriticalSpan("ScrollView-scroll");
					}
					break;
				}

				case android.view.MotionEvent.ACTION_CANCEL:
				case android.view.MotionEvent.ACTION_UP:
				{
					mIsBeingDragged = false;
					mActivePointerId = INVALID_POINTER;
					recycleVelocityTracker();
					if (mScroller.springBack(mScrollX, mScrollY, 0, 0, 0, getScrollRange()))
					{
						invalidate();
					}
					break;
				}

				case android.view.MotionEvent.ACTION_POINTER_UP:
				{
					onSecondaryPointerUp(ev);
					break;
				}
			}
			return mIsBeingDragged;
		}
开发者ID:hakeemsm,项目名称:XobotOS,代码行数:76,代码来源:ScrollView.cs


注:本文中的android.getPointerId方法示例由纯净天空整理自Github/MSDocs等开源代码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。