Android 3d Tagcloud

目录

今天在讨论中大家想在我们的搜索页将搜索热词用wordpress中常见的tag云的形式来展示,功能不足噱头补嘛 XD
然后就在google上搜索了一番。在中文的开发论坛里找到了一个demo,类似星空图的样子,效果不错。不过惊喜在后台,google上又找到了一个开源的项目tagin!,它实现了一个真正的浑天仪tag云,而且效果很华丽哟。代码地址在这里,感兴趣的可以下载体验一下。不过现在它是通过在屏幕边缘长按来控制tag球转动,我想把代码修改一下,让他可以在滑动的时候也能很方便的让tag云跟随转动。如果修改成功,稍后奉上代码。

下午大概的看了一下cloudtag imp4的代码,很简洁,核心的功能实现在一个TagCloudView中。其中,响应用户操作的代码,放在了view的public boolean onTouchEvent(MotionEvent e)方法中。原来作者的代码如下:

	public boolean onTouchEvent(MotionEvent e) {
		float x = e.getX();
		float y = e.getY();
//		Log.d(TAG, "motion:x=["+x+"] y=["+y+"] action is ["+e.getAction()+"]");
		switch (e.getAction()) {
		case MotionEvent.ACTION_MOVE:	
			//rotate elements depending on how far the selection point is from center of cloud
			float dx = x - centerX;
			float dy = y - centerY;
			
			Log.d(TAG, "motion:dx=["+dx+"] dy=["+dy+"] action is ["+e.getAction()+"]");
			
			mAngleX = ( dy/radius) *tspeed * TOUCH_SCALE_FACTOR;
			mAngleY = (-dx/radius) *tspeed * TOUCH_SCALE_FACTOR;
	    	
			mTagCloud.setAngleX(mAngleX);
	    	mTagCloud.setAngleY(mAngleY);
	    	mTagCloud.update();
	    	
	    	Iterator it=mTagCloud.iterator();
	    	Tag tempTag;
	    	while (it.hasNext()){
	    		tempTag= (Tag) it.next();              
	    		mParams.get(tempTag.getParamNo()).setMargins(	
						(int) (centerX -shiftLeft + tempTag.getLoc2DX()), 
						(int) (centerY + tempTag.getLoc2DY()), 
						0, 
						0);
				mTextView.get(tempTag.getParamNo()).setTextSize((int)(tempTag.getTextSize() * tempTag.getScale()));
				int mergedColor = Color.argb( (int)	(tempTag.getAlpha() * 255), 
						  (int)	(tempTag.getColorR() * 255), 
						  (int)	(tempTag.getColorG() * 255), 
						  (int) (tempTag.getColorB() * 255));
				mTextView.get(tempTag.getParamNo()).setTextColor(mergedColor);
				mTextView.get(tempTag.getParamNo()).bringToFront();
	    	}
			break;
		/*case MotionEvent.ACTION_UP:  //now it is clicked!!!!		
			dx = x - centerX;
			dy = y - centerY;			
			break;*/
		}
		
		return true;
	}

我做了一些小的修改,让不再是依靠长按屏幕某个位置来触发球体滚动,因为我觉得在手机上通过滑动来控制屏幕的变化更加自然,就改成了下面这个样子:

@Override
	public boolean onTouchEvent(MotionEvent e) {
		float x = e.getX();
		float y = e.getY();
//		Log.d(TAG, "motion:x=["+x+"] y=["+y+"] action is ["+e.getAction()+"]");
		switch (e.getAction()) {
		case MotionEvent.ACTION_DOWN:
			oldX = x;
			oldY = y;
			Log.d(TAG, "motion:x=["+x+"] y=["+y+"] action is ["+e.getAction()+"]");
			break;
		case MotionEvent.ACTION_MOVE:	
			//rotate elements depending on how far the selection point is from center of cloud
			float dx = x - oldX;
			float dy = y - oldY;
			oldX = x;
			oldY = y;
			
			Log.d(TAG, "motion:dx=["+dx+"] dy=["+dy+"] action is ["+e.getAction()+"]");
			
			mAngleX = ( dy/radius) *tspeed * TOUCH_SCALE_FACTOR;
			mAngleY = (-dx/radius) *tspeed * TOUCH_SCALE_FACTOR;
	    	
			mTagCloud.setAngleX(mAngleX);
	    	mTagCloud.setAngleY(mAngleY);
	    	mTagCloud.update();
	    	
	    	Iterator it=mTagCloud.iterator();
	    	Tag tempTag;
	    	while (it.hasNext()){
	    		tempTag= (Tag) it.next();              
	    		mParams.get(tempTag.getParamNo()).setMargins(	
						(int) (centerX -shiftLeft + tempTag.getLoc2DX()), 
						(int) (centerY + tempTag.getLoc2DY()), 
						0, 
						0);
				mTextView.get(tempTag.getParamNo()).setTextSize((int)(tempTag.getTextSize() * tempTag.getScale()));
				int mergedColor = Color.argb( (int)	(tempTag.getAlpha() * 255), 
						  (int)	(tempTag.getColorR() * 255), 
						  (int)	(tempTag.getColorG() * 255), 
						  (int) (tempTag.getColorB() * 255));
				mTextView.get(tempTag.getParamNo()).setTextColor(mergedColor);
				mTextView.get(tempTag.getParamNo()).bringToFront();
	    	}
			
			break;
		/*case MotionEvent.ACTION_UP:  //now it is clicked!!!!		
			dx = x - centerX;
			dy = y - centerY;			
			break;*/
		}
		
		return true;
	}

但是在测试中还发现了一个问题,有时候手指在屏幕上滑动,但是view的ontouchevent事件并未响应。看来得明天去公司请教大牛了。

看了一些关于android的ontouch响应的资料,ontouch只是处理事件,在此之前如果dispatch方法未拦截到事件或者之前的view已经处理了事件的话,会导致ontouch方法根本就不会被调用。因此,我改写了layout默认的dispatch方法,代码如下:

	@Override
	public boolean dispatchTouchEvent(MotionEvent e) {
		float x = e.getX();
		float y = e.getY();
		boolean result = true;
		if (e.getAction() == MotionEvent.ACTION_MOVE) {
			return false;
		} else {
			oldX = x;
			oldY = y;
			result = super.dispatchTouchEvent(e);
		}
		
		Log.d(TAG, "action is :" + e.getAction());
		Log.d(TAG, "result is :" + result);
		return result;
	}