package com.tv.ui.metro.view;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
import android.widget.FrameLayout;
import com.tv.ui.metro.R;
import com.tv.ui.metro.Utils;
import android.util.Log;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class MetroLayout extends FrameLayout implements View.OnFocusChangeListener{
public static final int Vertical = 0; //occupy two vertical cells
public static final int Horizontal = 1; //occupy two horizontal cells
public static final int Normal = 2; //square rectangle
Context mContext;
int[] rowOffset = new int[2];
static int DIVIDE_SIZE = 6;
boolean mMirror = true;
AnimatorSet mScaleAnimator;
List<WeakReference<View>> mViewList = new ArrayList<WeakReference<View>>();
HashMap<View, WeakReference<MirrorItemView>> mViewMirrorMap = new HashMap<View, WeakReference<MirrorItemView>>();
MetroCursorView mMetroCursorView;
View mLeftView;
View mRightView;
float mDensityScale = 1.0f;
private static int ITEM_V_WIDTH = -1;
private static int ITEM_V_HEIGHT = -1;
private static int ITEM_H_WIDTH = -1;
private static int ITEM_H_HEIGHT = -1;
private static int ITEM_NORMAL_SIZE = -1;
private static int mirror_ref_height= -1;
public class Item{
public Item( int type, int row){
mType = type;
mRow = row;
}
public int mType;
public int mRow;
}
public MetroLayout(Context context) {
super(context);
mContext = context;
init();
}
public MetroLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
init();
}
private void init(){
if(ITEM_V_WIDTH == -1){
DIVIDE_SIZE = getResources().getDimensionPixelSize(R.dimen.ITEM_DIVIDE_SIZE);
ITEM_V_WIDTH = getResources().getDimensionPixelSize(R.dimen.ITEM_V_WIDTH);
ITEM_V_HEIGHT = getResources().getDimensionPixelSize(R.dimen.ITEM_V_HEIGHT);
ITEM_H_WIDTH = getResources().getDimensionPixelSize(R.dimen.ITEM_H_WIDTH);
ITEM_H_HEIGHT = getResources().getDimensionPixelSize(R.dimen.ITEM_H_HEIGHT);
ITEM_NORMAL_SIZE = getResources().getDimensionPixelSize(R.dimen.ITEM_NORMAL_SIZE);
mirror_ref_height = getResources().getDimensionPixelSize(R.dimen.mirror_ref_height);
}
mDensityScale = 1;//mContext.getResources().getDisplayMetrics().densityDpi/320.0f;
setClipChildren(false);
setClipToPadding(false);
}
public View getItemView(int index){
if(index>=mViewList.size()) return null;
return mViewList.get(index).get();
}
public View addItemView(View child, int celltype , int row){
return addItemView(child, celltype , row, DIVIDE_SIZE);
}
public void clearItems(){
removeAllViews();
rowOffset[1]=rowOffset[0]=0;
mViewList.clear();
mViewMirrorMap.clear();
mLeftView = null;
mRightView = null;
}
public View addItemView(View child, int celltype , int row, int padding){
if(mLeftView==null){
mLeftView = child;
}
if(row==0) {
mRightView = child;
}
child.setFocusable(true);
child.setOnFocusChangeListener(this);
LayoutParams flp;
mViewList.add(new WeakReference<View>(child));
View result = child;
switch(celltype){
case Vertical:
flp = new LayoutParams(
(int)(ITEM_V_WIDTH*mDensityScale),
(int)(ITEM_V_HEIGHT*mDensityScale));
if(mMirror){
MirrorItemView mirror = new MirrorItemView(mContext);
mirror.setContentView(child, flp);
flp.bottomMargin = mirror_ref_height;
flp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
flp.leftMargin = rowOffset[0];
flp.topMargin = getPaddingTop();
flp.rightMargin = getPaddingRight();
mirror.setOnFocusChangeListener(this);
child.setTag(R.integer.tag_view_postion, 0);
addView(mirror,flp);
result = mirror;
mViewMirrorMap.put(child, new WeakReference<MirrorItemView>(mirror));
}else{
child.setFocusable(true);
child.setOnFocusChangeListener(this);
child.setTag(R.integer.tag_view_postion, 0);
flp.leftMargin = rowOffset[0];
flp.topMargin = getPaddingTop();
flp.rightMargin = getPaddingRight();
addView(child, flp);
}
rowOffset[0]+=ITEM_V_WIDTH*mDensityScale+padding;
rowOffset[1]=rowOffset[0];
break;
case Horizontal:
flp = new LayoutParams((int)(ITEM_H_WIDTH*mDensityScale), (int)(ITEM_H_HEIGHT*mDensityScale));
switch(row){
case 0:
flp.leftMargin = rowOffset[0];
flp.topMargin = getPaddingTop();
flp.rightMargin = getPaddingRight();
child.setFocusable(true);
child.setOnFocusChangeListener(this);
child.setTag(R.integer.tag_view_postion, 0);
addView(child,flp);
rowOffset[0]+=ITEM_H_WIDTH*mDensityScale+padding;
break;
case 1:
if(mMirror){
MirrorItemView mirror = new MirrorItemView(mContext);
mirror.setContentView(child, flp);
flp.bottomMargin = mirror_ref_height;
flp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
flp.leftMargin = rowOffset[1];
flp.topMargin = getPaddingTop();
flp.rightMargin = getPaddingRight();
flp.topMargin += ITEM_NORMAL_SIZE*mDensityScale+padding;
child.setTag(R.integer.tag_view_postion, 1);
addView(mirror,flp);
mirror.setOnFocusChangeListener(this);
result = mirror;
mViewMirrorMap.put(child, new WeakReference<MirrorItemView>(mirror));
}else{
child.setFocusable(true);
child.setOnFocusChangeListener(this);
child.setTag(R.integer.tag_view_postion, 1);
flp.leftMargin = rowOffset[1];
flp.topMargin = getPaddingTop();
flp.rightMargin = getPaddingRight();
flp.topMargin += ITEM_NORMAL_SIZE*mDensityScale+padding;
addView(child,flp);
}
rowOffset[1]+=ITEM_H_WIDTH*mDensityScale+padding;
break;
}
break;
case Normal:
flp = new LayoutParams(
(int)(ITEM_NORMAL_SIZE*mDensityScale),
(int)(ITEM_NORMAL_SIZE*mDensityScale));
switch(row){
case 0:
flp.leftMargin = rowOffset[0];
child.setFocusable(true);
child.setOnFocusChangeListener(this);
child.setTag(R.integer.tag_view_postion, 0);
flp.topMargin = getPaddingTop();
flp.rightMargin = getPaddingRight();
addView(child,flp);
rowOffset[0]+=ITEM_NORMAL_SIZE*mDensityScale+padding;
break;
case 1:
if(mMirror){
MirrorItemView mirror = new MirrorItemView(mContext);
mirror.setContentView(child, flp);
flp.bottomMargin = mirror_ref_height;
flp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
flp.leftMargin = rowOffset[1];
flp.topMargin = getPaddingTop();
flp.rightMargin = getPaddingRight();
flp.topMargin += ITEM_NORMAL_SIZE*mDensityScale+padding;
addView(mirror,flp);
child.setTag(R.integer.tag_view_postion, 1);
mirror.setOnFocusChangeListener(this);
result = mirror;
mViewMirrorMap.put(child, new WeakReference<MirrorItemView>(mirror));
}else{
child.setFocusable(true);
child.setTag(R.integer.tag_view_postion, 1);
child.setOnFocusChangeListener(this);
flp.leftMargin = rowOffset[1];
flp.topMargin = getPaddingTop();
flp.rightMargin = getPaddingRight();
flp.topMargin += ITEM_NORMAL_SIZE*mDensityScale+padding;
addView(child,flp);
}
rowOffset[1]+=ITEM_NORMAL_SIZE*mDensityScale+padding;
break;
}
break;
}
return result;
}
private View lastFocusedView;
@Override
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
if (lastFocusedView!=null&&lastFocusedView.requestFocus(direction, previouslyFocusedRect)) {
return true;
}
int index;
int increment;
int end;
int count = this.getChildCount();
if ((direction & FOCUS_FORWARD) != 0) {
index = 0;
increment = 1;
end = count;
} else {
index = count - 1;
increment = -1;
end = -1;
}
for (int i = index; i != end; i += increment) {
View child = this.getChildAt(i);
{
if (child.requestFocus(direction, previouslyFocusedRect)) {
return true;
}
}
}
return false;
}
public void requestChildFocus(View child, View focused) {
super.requestChildFocus(child,focused);
}
public void onFocusChange(final View v, boolean hasFocus){
if(mScaleAnimator!=null) mScaleAnimator.end();
if(mMetroCursorView!=null){
if(hasFocus){
if(mViewMirrorMap.get(v)!=null){
mMetroCursorView.setFocusView(mViewMirrorMap.get(v).get());
}else{
mMetroCursorView.setFocusView(v);
}
v.setTag(R.integer.tag_view_focused_host_view, mMetroCursorView);
lastFocusedView = v;
}else{
if(mViewMirrorMap.get(v)!=null){
mMetroCursorView.setUnFocusView(mViewMirrorMap.get(v).get());
}else{
mMetroCursorView.setUnFocusView(v);
}
}
}else{
if(hasFocus){
lastFocusedView = v;
bringChildToFront(v);
invalidate();
ObjectAnimator animX = ObjectAnimator.ofFloat(v, "ScaleX",
new float[] { 1.0F, 1.1F }).setDuration(200);
ObjectAnimator animY = ObjectAnimator.ofFloat(v, "ScaleY",
new float[] { 1.0F, 1.1F }).setDuration(200);
mScaleAnimator = new AnimatorSet();
mScaleAnimator.playTogether(new Animator[] { animX, animY });
mScaleAnimator.start();
//v.setScaleX(1.1f);
//v.setScaleY(1.1f);
}else{
v.setScaleX(1.0f);
v.setScaleY(1.0f);
}
}
}
public void setMetroCursorView(MetroCursorView v){
mMetroCursorView = v;
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
// Handle automatic focus changes.
if (event.getAction() == KeyEvent.ACTION_DOWN) {
int direction = 0;
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_DPAD_LEFT:
if (event.hasNoModifiers()) {
direction = View.FOCUS_LEFT;
}
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
if (event.hasNoModifiers()) {
direction = View.FOCUS_RIGHT;
}
break;
case KeyEvent.KEYCODE_DPAD_UP:
if (event.hasNoModifiers()) {
direction = View.FOCUS_UP;
}
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
if (event.hasNoModifiers()) {
direction = View.FOCUS_DOWN;
}
break;
case KeyEvent.KEYCODE_TAB:
if (event.hasNoModifiers()) {
direction = View.FOCUS_FORWARD;
} else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
direction = View.FOCUS_BACKWARD;
}
break;
}
if (direction == View.FOCUS_DOWN || direction == View.FOCUS_UP) {
View focused = findFocus();
if (focused != null) {
View v = focused.focusSearch(direction);
if (v == null) {
Utils.playKeySound(this, Utils.SOUND_ERROR_KEY);
mMetroCursorView.showIndicator();
}
}
}
}
boolean ret = super.dispatchKeyEvent(event);
return ret;
}
public void focusMoveToLeft(){
mLeftView.requestFocus();
}
public void focusMoveToRight(){
mRightView.requestFocus();
}
public void focusMoveToPreFocused(){
if(lastFocusedView!=null){
lastFocusedView.requestFocus();
}else {
mLeftView.requestFocus();
}
}
}