package reco.frame.tv.view;
import java.util.ArrayList;
import java.util.List;
import reco.frame.tv.R;
import reco.frame.tv.util.ViewUtil;
import reco.frame.tv.view.component.FragmentAdapter;
import reco.frame.tv.view.component.TvUtil;
import reco.frame.tv.view.component.TvSlowViewPager;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.Handler;
import android.os.Parcelable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
/**
* 通过对viewpager再加工而成,当前版本只适用多fragment布局
*
* @author keYence
*
*/
public class TvTabHost extends RelativeLayout {
private final String TAG = "TvTabHost";
/**
* 光标
*/
private View cursor;
/**
* 光标资源
*/
private int cursorRes;
/**
* 可否缩放
*/
private boolean scalable;
/**
* 放大比率
*/
private float scale;
/**
* 放大用时
*/
private int durationLarge = 100;
/**
* 缩小用时
*/
private int durationSmall = 100;
/**
* 翻页滚动时间
*/
private int durationScroll;
/**
* 触发延迟
*/
private int delay = 110;
/**
* 光标宽高 包括阴影
*/
private int cursorWidth, cursorHeight;
/**
* 光标相对位置
*/
private int cursorMarginLeft, cursorMarginTop, cursorMarginRight,
cursorMarginBottom;
private int paddingLeft, paddingTop;
public int curPage, initPage, savePage;
/**
* 页宽 页高
*/
private int pageWidth, pageHeight;
/**
* 页数 当前页
*/
private int pageCount, pageCurrent;
/**
* 顶部栏与页间隔高度
*/
private int dividerHeight;
/**
* 标题宽高 间隔及文字大小
*/
private int titleWidth, titleHeight, titleSpace, textSize;
/**
* 页面回收标记
*/
private boolean isRestore = false;
/**
* 顶部栏获得焦点
*/
private boolean isTopFocused = false;
private ScrollPageChangerListener scrollPageChangerListener;
private OnTopBarFocusChange onTopBarFocusChange;
private FragmentManager fragmentManager;
private List<Fragment> fragList = new ArrayList<Fragment>();
private List<View> titleList;
/**
* 键为ID 值为对应页面
*/
private SparseArray<Integer> idToPages;
private int titleMarginLeft;
private int textColorDefault, textColorSelected;
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
};
};
public TvTabHost(Context context) {
this(context, null);
}
public TvTabHost(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TvTabHost(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray custom = getContext().obtainStyledAttributes(attrs,
R.styleable.TvTabHost);
this.cursorRes = custom.getResourceId(R.styleable.TvTabHost_cursorRes,
0);
this.titleWidth = (int) custom.getDimension(
R.styleable.TvTabHost_titleWidth, 10);
this.titleHeight = (int) custom.getDimension(
R.styleable.TvTabHost_titleHeight, 10);
this.titleSpace = (int) custom.getDimension(
R.styleable.TvTabHost_titleSpace, 10);
this.textColorDefault = custom.getColor(
R.styleable.TvTabHost_textColorDefault, Color.BLACK);
this.textColorSelected = custom.getColor(
R.styleable.TvTabHost_textColorSelected, Color.WHITE);
this.textSize = (int) custom.getDimension(
R.styleable.TvTabHost_textSize, 10);
this.dividerHeight = (int) custom.getDimension(
R.styleable.TvTabHost_dividerHeight, 10);
this.cursorWidth = (int) custom.getDimension(
R.styleable.TvTabHost_cursorWidth, 0);
this.cursorHeight = (int) custom.getDimension(
R.styleable.TvTabHost_cursorHeight, 0);
this.cursorMarginTop = (int) custom.getDimension(
R.styleable.TvTabHost_cursorMarginTop, 0);
this.cursorMarginRight = (int) custom.getDimension(
R.styleable.TvTabHost_cursorMarginRight, 0);
this.cursorMarginRight = (int) custom.getDimension(
R.styleable.TvTabHost_cursorMarginRight, 0);
this.cursorMarginBottom = (int) custom.getDimension(
R.styleable.TvTabHost_cursorMarginBottom, 0);
this.scalable = custom.getBoolean(R.styleable.TvTabHost_scalable, true);
this.scale = custom.getFloat(R.styleable.TvTabHost_scale, 1.1f);
this.delay = custom.getInteger(R.styleable.TvTabHost_delay, 110);
this.durationLarge = custom.getInteger(
R.styleable.TvTabHost_durationLarge, 100);
this.durationSmall = custom.getInteger(
R.styleable.TvTabHost_durationSmall, 100);
this.durationScroll = custom.getInteger(
R.styleable.TvTabHost_durationScroll, 370);
custom.recycle();
paddingLeft = (int) (titleWidth * (scale - 1) / 2 + 3 + this
.getPaddingLeft());
paddingTop = (int) (titleHeight * (scale - 1) / 2 + 3 + this
.getPaddingTop());
init();
}
private void init() {
titleList = new ArrayList<View>();
idToPages = new SparseArray<Integer>();
}
/**
* 添加页
*
* @param frag
*/
public void addPage(FragmentManager fm, Fragment frag, String title) {
this.fragmentManager = fm;
this.fragList.add(frag);
TextView tv = new TextView(getContext());
tv.setFocusable(true);
tv.setTextColor(textColorDefault);
tv.setTextSize(ViewUtil.Px2Dp(getContext(), textSize));
tv.setText(title);
tv.setGravity(Gravity.CENTER);
int tempId = TvUtil.buildId();
tv.setId(tempId + titleList.size() + 1);
idToPages.put(tempId + titleList.size() + 1, titleList.size());
tv.setTag(titleList.size());
tv.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(final View item, boolean focus) {
if (focus) {
// 翻页
int targetPage = Integer.parseInt(item.getTag().toString());
// Log.e(TAG,
// "targetPage="+targetPage+"---"+pageCurrent+"---"+isTopFocused);
if (pageCurrent != targetPage && !isTopFocused) {
titleList.get(pageCurrent).requestFocus();
return;
}
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (item.isFocused()) {
moveCover(item);
}
}
}, delay);
if (isTopFocused) {
pageContainer.setCurrentItem(targetPage);
}
isTopFocused = true;
} else {
returnCover(item);
}
}
});
tv.setOnKeyListener(new OnKeyListener() {
@Override
public boolean onKey(View v, int id, KeyEvent key) {
if (key.getAction() == KeyEvent.ACTION_DOWN) {
if (key.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN) {
isTopFocused = false;
} else if (key.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT) {
if (pageCurrent == 0) {
isTopFocused = false;
}
} else if (key.getKeyCode() == KeyEvent.KEYCODE_DPAD_RIGHT) {
if (pageCurrent == pageCount - 1) {
isTopFocused = false;
}
}
if (onTopBarFocusChange != null) {
onTopBarFocusChange.onFocusChange(isTopFocused,
pageCurrent);
}
}
return false;
}
});
titleList.add(tv);
}
private void buildTitle() {
}
private void buildPage() {
}
/**
* 加载完毕后调用
*/
public void buildLayout() {
/**
* 修改frag添加方式使用adapter 然后 addView();
*/
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) getLayoutParams();
RelativeLayout.LayoutParams newParams = new RelativeLayout.LayoutParams(
params.width, params.height);
newParams.setMargins(params.leftMargin, params.topMargin,
params.rightMargin, params.bottomMargin);
this.setLayoutParams(newParams);
pageWidth = params.width;
pageHeight = params.height - titleHeight - dividerHeight;
if (pageWidth < 10) {
pageWidth = LayoutParams.MATCH_PARENT;
}
if (pageHeight < 10) {
pageHeight = LayoutParams.MATCH_PARENT;
}
pageContainer = new TvSlowViewPager(getContext(), durationScroll);
RelativeLayout.LayoutParams vpParams = new RelativeLayout.LayoutParams(
pageWidth, pageHeight);
vpParams.setMargins(0, (titleHeight + dividerHeight), 0, 0);
vpParams.addRule(RelativeLayout.ALIGN_LEFT, this.getId());
vpParams.addRule(RelativeLayout.ALIGN_TOP, this.getId());
RelativeLayout parent = (RelativeLayout) this.getParent();
parent.addView(pageContainer, vpParams);
pageContainer
.setAdapter(new FragmentAdapter(fragmentManager, fragList));
pageCount = fragList.size();
pageContainer.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int postion) {
pageCurrent = postion;
if (scrollPageChangerListener != null) {
scrollPageChangerListener.onPageSelected(postion);
}
flushTopBar(postion);
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageScrollStateChanged(int arg0) {
}
});
titleMarginLeft = (params.width - (titleList.size() * titleWidth + (titleList
.size() - 1) * titleSpace)) / 2;
// 加载标题
for (int i = 0; i < titleList.size(); i++) {
TextView title = (TextView) titleList.get(i);
RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(
titleWidth, titleHeight);
// 默认居中
rlp.setMargins((titleSpace + titleWidth) * i + titleMarginLeft, 0,
0, 0);
this.addView(title, rlp);
}
// 加载页
if (isRestore) {
this.curPage = savePage;
}
}
private void flushTopBar(int position) {
if (this.findFocus()!=null) {
titleList.get(position).requestFocus();
}
for (int i = 0; i < titleList.size(); i++) {
// 变色
TextView title = (TextView) titleList.get(i);
if (i == position) {
title.setTextColor(textColorSelected);
} else {
title.setTextColor(textColorDefault);
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
/**
* 获得此ViewGroup上级容器为其推荐的宽和高,以及计算模式
*/
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
// 计算出所有的childView的宽和高
measureChildren(widthMeasureSpec, heightMeasureSpec);
/**
* 记录如果是wrap_content是设置的宽和高
*/
int width = 0;
int height = 0;
int cCount = getChildCount();
int cWidth = 0;
int cHeight = 0;
/**
* 根据childView计算的出的宽和高,以及设置的margin计算容器的宽和高,主要用于容器是warp_content时
*/
for (int i = 0; i < cCount; i++) {
View childView = getChildAt(i);
if (childView instanceof ViewGroup) {
width = sizeWidth;
height = sizeHeight;
} else {
cWidth = childView.getMeasuredWidth();
cHeight = childView.getMeasuredHeight();
width += cWidth;
height += cHeight;
}
}
/**
* 如果是wrap_content设置为我们计算的值 否则:直接设置为父容器计算的值
*/
setMeasuredDimension(
(widthMode == MeasureSpec.EXACTLY || width == 0) ? sizeWidth
: width,
(heightMode == MeasureSpec.EXACTLY || height == 0) ? sizeHeight
: height);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed) {
pageHeight = b;
int cCount = getChildCount();
int cWidth = 0;
int cHeight = 0;
int titleIndex = 0;
/**
* 遍历所有childView根据其宽和高,以及margin进行布局
*/
for (int i = 0; i < cCount; i++) {
View childView = getChildAt(i);
if (childView instanceof ViewGroup) {
// 页布局
childView.layout(0, t + titleHeight, pageWidth, b
+ titleHeight);
} else {
cWidth = childView.getMeasuredWidth();
cHeight = childView.getMeasuredHeight();
int cl = 0, ct = 0, cr = 0, cb = 0;
cl = titleIndex * (titleWidth + titleSpace)
+ titleMarginLeft + paddingLeft;
ct = 0;
cr = cl + cWidth;
cb = cHeight + ct;
childView.layout(cl, ct + paddingTop, cr, cb + paddingTop);
titleIndex++;
}
}
}
}
/**
* 滑至指定页面
*
* @param position
*/
public void setCurrentPage(int position) {
pageCurrent = position;
pageContainer.setCurrentItem(position);
flushTopBar(position);
}
@Override
protected Parcelable onSaveInstanceState() {
// 保存当前状态
return super.onSaveInstanceState();
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
// 读取保存状态
isRestore = true;
super.onRestoreInstanceState(state);
}
/**
* 光标移动 到达后 与控件同时放大
*/
private void moveCover(View item) {
if (cursor == null) {
cursor = new ImageView(getContext());
cursor.setBackgroundResource(cursorRes);
this.addView(cursor);
}
setBorderParams(item);
item.bringToFront();
cursor.bringToFront();
if (scalable) {
scaleToLarge(item);
}
}
/**
* 还原控件状态
*/
public void returnCover(View item) {
if (cursor != null) {
cursor.setVisibility(View.INVISIBLE);
}
if (scalable) {
scaleToNormal(item);
}
}
private AnimatorSet animatorSet;
private ObjectAnimator largeX;
private TvSlowViewPager pageContainer;
private void scaleToLarge(View item) {
if (!item.isFocused()) {
return;
}
animatorSet = new AnimatorSet();
largeX = ObjectAnimator.ofFloat(item, "ScaleX", 1f, scale);
ObjectAnimator largeY = ObjectAnimator.ofFloat(item, "ScaleY", 1f,
scale);
ObjectAnimator cursorX = ObjectAnimator.ofFloat(cursor, "ScaleX", 1f,
scale);
ObjectAnimator cursorY = ObjectAnimator.ofFloat(cursor, "ScaleY", 1f,
scale);
animatorSet.setDuration(durationLarge);
animatorSet.play(largeX).with(largeY).with(cursorX).with(cursorY);
animatorSet.start();
}
public void scaleToNormal(View item) {
if (animatorSet == null) {
return;
}
if (animatorSet.isRunning()) {
animatorSet.cancel();
}
ObjectAnimator oa = ObjectAnimator.ofFloat(item, "ScaleX", 1f);
oa.setDuration(durationSmall);
oa.start();
ObjectAnimator oa2 = ObjectAnimator.ofFloat(item, "ScaleY", 1f);
oa2.setDuration(durationSmall);
oa2.start();
}
/**
* 指定光标相对位置
*/
private void setBorderParams(View item) {
cursor.clearAnimation();
cursor.setVisibility(View.VISIBLE);
// 判断类型
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) item
.getLayoutParams();
int l, t, r, b;
l = params.leftMargin + paddingLeft + cursorMarginLeft;
t = params.topMargin + paddingTop + cursorMarginTop;
r = l + cursorWidth;
b = t + cursorHeight;
cursor.layout(l, t, r, b);
// Log.e(VIEW_LOG_TAG, l + "---" + t+ "---" + r + "---" + b);
}
public void setOnPageChangeListener(ScrollPageChangerListener listener) {
this.scrollPageChangerListener = listener;
}
public void setOnTopBarFocusChangeListener(OnTopBarFocusChange listener) {
this.onTopBarFocusChange = listener;
}
public interface ScrollPageChangerListener {
public void onPageSelected(int pageCurrent);
}
public interface OnTopBarFocusChange {
public void onFocusChange(boolean hasFocus, int postion);
}
}