Android TV Menu 3D星体旋转效果

在Android中,如果想要实现3D动画效果一般有两种选择:一是使用Open GL ES,二是使用Camera。Open GL ES使用起来太过复杂,一般是用于比较高级的3D特效或游戏,并且这个也不是开源的,像比较简单的一些3D效果,使用Camera就足够了。

 一些熟知的Android 3D动画如对某个View进行旋转或翻转的 Rotate3dAnimation类,还有使用Gallery( Gallery目前已过时,现在都推荐使用 HorizontalScrollView或 RecyclerView替代其实现相应功能) 实现的3D画廊效果等,当然有一些特效要通过伪3D变换来实现,比如CoverFlow效果,它使用标准Android 2D库,还是继承的Gallery类并自定义一些方法,具体实现和使用请参照http://www.cnblogs.com/zealotrouge/p/3380682.html。

本文要实现的3D星体旋转效果也是从这个CoverFlow演绎而来,不过CoverFlow只是对图像进行转动,我这里要实现的效果是要对所有的View进行类似旋转木马的转动,并且CoverFlow还存在很多已知bug,所以我这里需要重写一些类,并且将Scroller类用Rotator类替代,使界面看起来具有滚动效果,实际上是在转动一组图像。

 

1. 首先我们需要自定义控件的一些属性,我们将控件取名Carousel,需要设置子项的最小个数和最大个数、当前选中项以及定义旋转角度等

attrs.xml




    
        
        
        
        
        
        
        
        
        
    

 

2. 控件的绘制实现参考:https://github.com/hammykhan/android-carousel-demo,使用的时候只是对其中的细节进行了一些修改,这里不多叙述,大家也可以根据自己的需求作定制化修改

 

3. 3D星体旋转效果核心的内容在主界面,主要做两件事情:

  • 菜单布局使用上面自定义的Carousel控件
  • UI交互主要是焦点处理和按键控制
package com.john.carousel.test;

import com.john.carousel.lib.Carousel;
import com.john.carousel.lib.Carousel.CarouselItemClickListener;
import com.john.carousel.lib.CarouselAdapter;
import com.john.carousel.lib.CarouselAdapter.OnItemClickListener;
import com.john.carousel.lib.Constants;
import com.john.carousel.lib.R;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnKeyListener;
import android.widget.LinearLayout;

public class AndroidActivity extends Activity implements CarouselItemClickListener, Constants
{
	private Carousel carousel;
	private final String TAG = AndroidActivity.class.getSimpleName();
	private LinearLayout layoutMain = null;
	private final int NETWORK = 0;
	private final int UPDATE = 1;
	private final int APK = 2;
	private final int STB = 3;
	private final int OTHER = 4;
	private final int WALLPAPER = 5;
	private final int MEDIA = 6;

	private int initSelection = 2;
	
	private long lastClickTime, currClickTime;

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		View mainView = LayoutInflater.from(this).inflate(R.layout.activity_android, null);
		setContentView(mainView);
           if (getIntent() != null) {
             initSelection = getIntent().getExtras().getInt("selection", 2);  
         }

		if (initSelection >= 6 || initSelection <= 0)
		{
			initSelection = initSelection % 7;
		}

		buildView();

	}

	private void buildView()
	{
		carousel = (Carousel) findViewById(R.id.carousel);
		layoutMain = (LinearLayout) findViewById(R.id.layoutMain);
		layoutMain.setBackground(getResources().getDrawable(R.drawable.main_back00));
		carousel.setDrawingCacheEnabled(true);
		carousel.setGravity(Gravity.TOP);
		carousel.setFocusFlag(true);
		carouselGetFocus();
		carousel.setSelected(initSelection);
		carousel.setCarouselItemClickCallBack(this);

		carousel.setOnItemClickListener(new cOnItemClickListener()
		{

			@Override
			public void onItemClick(CarouselAdapter parent, View view, int position, long id)
			{
				onItemClickOrCallback(position);
			}
		});
		carousel.setOnKeyListener(new OnKeyListener()
		{

			@Override
			public boolean onKey(View v, int keyCode, KeyEvent event)
			{
				if (event.equals(KeyEvent.ACTION_DOWN))
				{
					switch (keyCode)
					{
					case KEY_LEFT:
						carousel.toNextLeftItem();
						break;

					case KEY_RIGHT:
						carousel.toNextRightItem();
						break;

					case KEY_OK:
					case KEY_CENTER:
						onItemClickOrCallback(carousel.getIndex());
						break;

					}
				}

				carouselGetFocus();
				return true;
			}
		});

	}

	private void onItemClickOrCallback(int position)
	{

		switch (position)
		{
		case NETWORK:

			break;

		case UPDATE:

			break;

		case APK:

			break;

		case STB:

			break;

		case OTHER:

			break;

		case WALLPAPER:

			break;

		case MEDIA:

			break;

		default:
			break;
		}
	}

	@Override
	public void CarouselClickCallBack(int itemPosition)
	{
		onItemClickOrCallback(itemPosition);
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event)
	{
		switch (keyCode)
		{
		case KEY_OK:
		case KEY_CENTER:
			onItemClickOrCallback(carousel.getIndex());
			return true;

		case KEY_LEFT:
			if (carousel.getFocusFlag())
			{
				currClickTime = System.currentTimeMillis();
				if (currClickTime - lastClickTime > 200)
				{
					lastClickTime = currClickTime;

					carousel.toNextLeftItem();
					Log.d("selectedItemIndex", carousel.getIndex() + "");
					return true;
				}
				else
				{
					return true;
				}
			}
			break;

		case KEY_RIGHT:
			if (carousel.getFocusFlag())
			{
				currClickTime = System.currentTimeMillis();
				if (currClickTime - lastClickTime > 200)
				{
					lastClickTime = currClickTime;
					carousel.toNextRightItem();
					Log.d("selectedItemIndex", carousel.getIndex() + "");
					return true;
				}
				else
				{
					return true;
				}
			}
			break;

		case KEY_UP:
			carousel.setFocusFlag(false);
			carousel.clearFocus();
			carousel.setFocusable(false);
			carousel.setSelected(false);

			return true;

		case KEY_DOWN:
			if (!carousel.getFocusFlag())
			{
				Log.e(TAG, "KEY_DOWN");
				carouselGetFocus();
			}
			return true;

		case KEY_EXIT:
			return true;

		case KEY_VOLDOWN:
		case KEY_VOLUP:
		case KEY_MUTE:
		case KEY_VOLUME_MUTE:
			return true;

		}
		return super.onKeyDown(keyCode, event);
	}

	private void carouselGetFocus()
	{
		carousel.setFocusFlag(true);
		carousel.requestFocus();
		carousel.setFocusable(true);
	}

}


效果展示
http://v.youku.com/v_show/id_XMTcyMDY3ODUxMg==.html

你可能感兴趣的:(Android,TV)