最近开始接触TV端开发,初转入TV端,有好多不适应。尤其是对焦点的处理,上篇文章对leanback的使用做了简单的介绍,并对Item获取焦点后的高亮显示进行了处理。但是,如果按照同样的方法在非列表页实现时,效果并不理想,并会出现难以控制等问题。于是,开始寻找新的实现方式。在网上找了好多实现方式,均不是特别理想。最终找到了一篇比较满意的文章,自己在此基础上进行了优化改进。Demo的截图如下:
下面就详细介绍一下实现流程吧。
(1)自定义View,实现获取焦点时放大,失去焦点时缩小,详细代码如下:
[java]view plaincopy
packagecn.chinaiptv.newaikan.view;
importandroid.content.Context;
importandroid.graphics.Canvas;
importandroid.graphics.Rect;
importandroid.graphics.drawable.Drawable;
importandroid.util.AttributeSet;
importandroid.view.animation.Animation;
importandroid.view.animation.AnimationUtils;
importandroid.widget.RelativeLayout;
importcn.chinaiptv.newaikan.R;
publicclassFocusRelativeLayoutextendsRelativeLayout {
privateRect mBound;
privateDrawable mDrawable;
privateRect mRect;
privateAnimation scaleSmallAnimation;
privateAnimation scaleBigAnimation;
publicFocusRelativeLayout(Context context) {
super(context);
init();
}
publicFocusRelativeLayout(Context context, AttributeSet attrs,intdefStyle) {
super(context, attrs, defStyle);
init();
}
publicFocusRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
protectedvoidinit() {
setWillNotDraw(false);
mRect =newRect();
mBound =newRect();
//获取焦点后,外侧的阴影图片
mDrawable = getResources().getDrawable(R.drawable.poster_shadow_4);
setChildrenDrawingOrderEnabled(true);
}
@Override
protectedvoidonAttachedToWindow() {
super.onAttachedToWindow();
}
@Override
publicvoiddraw(Canvas canvas) {
super.draw(canvas);
}
@Override
protectedvoidonDraw(Canvas canvas) {
if(hasFocus()) {
super.getDrawingRect(mRect);
mBound.set(-5+mRect.left, -5+mRect.top,5+mRect.right,5+mRect.bottom);
mDrawable.setBounds(mBound);
canvas.save();
mDrawable.draw(canvas);
canvas.restore();
}
super.onDraw(canvas);
}
@Override
protectedvoidonFocusChanged(booleangainFocus,intdirection, Rect previouslyFocusedRect) {
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
if(gainFocus) {
bringToFront();
getRootView().requestLayout();
getRootView().invalidate();
zoomOut();
}else{
zoomIn();
}
}
/**
* 缩小动画
*/
privatevoidzoomIn() {
if(scaleSmallAnimation ==null) {
scaleSmallAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.anim_scale_small);
}
startAnimation(scaleSmallAnimation);
}
/**
* 放倒动画
*/
privatevoidzoomOut() {
if(scaleBigAnimation ==null) {
scaleBigAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.anim_scale_big);
}
startAnimation(scaleBigAnimation);
}
}
(2)定义两个放大和缩小的动画文件
放大的动画文件:anim_scale_big.xml
[java]view plaincopy
android:fillAfter="true"
android:fillBefore="false"
android:shareInterpolator="false">
android:duration="500"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:pivotX="50.0%"
android:pivotY="50.0%"
android:repeatCount="0"
android:toXScale="1.1"
android:toYScale="1.1"
android:fillAfter="true"/>
缩小的动画文件:anim_scale_small.xml
[java]view plaincopy
android:fillAfter="false"
android:fillBefore="true"
android:shareInterpolator="false">
android:duration="500"
android:fromXScale="1.1"
android:fromYScale="1.1"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:pivotX="50.0%"
android:pivotY="50.0%"
android:repeatCount="0"
android:toXScale="1.0"
android:toYScale="1.0"
android:fillAfter="true"/>
(3)准备工作就结束下,下面开始些布局文件。由于本例子中的图片布局基本类似,所以就单独给出一个item文件(例子中使用了圆角图片,在此不再贴出代码):
[java]view plaincopy
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/item"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true">
android:id="@+id/img"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/mid_bottom"
android:duplicateParentState="true"
android:scaleType="fitXY"
app:roundHeight="@dimen/w_10"
app:roundWidth="@dimen/w_10"/>
android:id="@+id/hover"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/sl_image_home_navigator"
android:duplicateParentState="true"
android:scaleType="fitXY"
app:roundHeight="@dimen/w_10"
app:roundWidth="@dimen/w_10"/>
(4)引用定义好的子布局:
[java]view plaincopy
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
android:id="@+id/fragment_two"
android:clipChildren="false"
android:clipToPadding="false">
android:id="@+id/channel_0"
android:layout_width="@dimen/w_320"
android:layout_height="@dimen/h_240"
layout="@layout/home_page_channel_item"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginRight="@dimen/h_15"/>
android:id="@+id/channel_1"
android:layout_width="@dimen/w_320"
android:layout_height="@dimen/h_240"
android:layout_marginTop="@dimen/h_15"
layout="@layout/home_page_channel_item"
android:layout_below="@id/channel_0"
android:layout_marginRight="@dimen/h_15"
android:layout_alignLeft="@id/channel_0"/>
android:id="@+id/channel_2"
android:layout_width="@dimen/w_320"
android:layout_height="@dimen/h_240"
layout="@layout/home_page_channel_item"
android:layout_toRightOf="@id/channel_0"
android:layout_alignTop="@id/channel_0"
android:layout_marginRight="@dimen/h_15"/>
android:id="@+id/channel_3"
android:layout_width="@dimen/w_320"
android:layout_height="@dimen/h_240"
layout="@layout/home_page_channel_item"
android:layout_alignLeft="@id/channel_2"
android:layout_marginTop="@dimen/h_15"
android:layout_marginRight="@dimen/h_15"
android:layout_below="@id/channel_2"/>
android:id="@+id/channel_4"
android:layout_width="@dimen/w_320"
android:layout_height="@dimen/h_240"
layout="@layout/home_page_channel_item"
android:layout_toRightOf="@id/channel_2"
android:layout_alignTop="@id/channel_2"
android:layout_marginRight="@dimen/h_15"/>
android:id="@+id/channel_5"
android:layout_width="@dimen/w_320"
android:layout_height="@dimen/h_240"
layout="@layout/home_page_channel_item"
android:layout_alignLeft="@id/channel_4"
android:layout_marginTop="@dimen/h_15"
android:layout_marginRight="@dimen/h_15"
android:layout_below="@id/channel_4"/>
android:id="@+id/channel_6"
android:layout_width="@dimen/w_320"
android:layout_height="@dimen/h_240"
layout="@layout/home_page_channel_item"
android:layout_toRightOf="@id/channel_4"
android:layout_alignTop="@id/channel_4"
android:layout_marginRight="@dimen/h_15"/>
android:id="@+id/channel_7"
android:layout_width="@dimen/w_320"
android:layout_height="@dimen/h_240"
android:layout_marginTop="@dimen/h_15"
layout="@layout/home_page_channel_item"
android:layout_alignLeft="@id/channel_6"
android:layout_marginRight="@dimen/h_15"
android:layout_below="@id/channel_6"/>
android:id="@+id/channel_8"
android:layout_width="@dimen/w_320"
android:layout_height="@dimen/h_240"
layout="@layout/home_page_channel_item"
android:layout_toRightOf="@id/channel_6"
android:layout_alignTop="@id/channel_6"
android:layout_marginRight="@dimen/h_15"/>
android:id="@+id/channel_9"
android:layout_width="@dimen/w_320"
android:layout_marginTop="@dimen/h_15"
android:layout_height="@dimen/h_240"
layout="@layout/home_page_channel_item"
android:layout_alignLeft="@id/channel_8"
android:layout_marginRight="@dimen/h_15"
android:layout_below="@id/channel_8"/>
最后,在JAVA代码处理滑动到最左侧,最右侧,最下方时。进行模块切换,具体代码如下:
[java]view plaincopy
packagecn.chinaiptv.newaikan.fragment;
importandroid.os.Bundle;
importandroid.support.annotation.Nullable;
importandroid.support.v4.app.Fragment;
importandroid.view.LayoutInflater;
importandroid.view.View;
importandroid.view.ViewGroup;
importandroid.view.ViewTreeObserver;
importandroid.widget.RelativeLayout;
importcn.chinaiptv.newaikan.R;
importcn.chinaiptv.newaikan.view.FocusRelativeLayout;
/**
* Created by ddklsy163com on 16/12/19.
*/
publicclassFragmentTwoextendsFragmentimplementsViewTreeObserver.OnGlobalFocusChangeListener {
privateView view;
privateFocusRelativeLayout channel_0;
privateFocusRelativeLayout channel_1;
privateFocusRelativeLayout channel_2;
privateFocusRelativeLayout channel_3;
privateFocusRelativeLayout channel_4;
privateFocusRelativeLayout channel_5;
privateFocusRelativeLayout channel_6;
privateFocusRelativeLayout channel_7;
privateFocusRelativeLayout channel_8;
privateFocusRelativeLayout channel_9;
privateRelativeLayout fragment_two;
@Nullable
@Override
publicView onCreateView(LayoutInflater inflater,@NullableViewGroup container,@NullableBundle savedInstanceState) {
if(view !=null) {
ViewGroup parent = (ViewGroup) view.getParent();
if(parent !=null) {
parent.removeView(view);
}
returnview;
}
view = inflater.inflate(R.layout.fragment_two,null);
initView(view);
fragment_two.getViewTreeObserver().addOnGlobalFocusChangeListener(this);
returnview;
}
privatevoidinitView(View view) {
fragment_two = (RelativeLayout) view.findViewById(R.id.fragment_two);
channel_0 = (FocusRelativeLayout) view.findViewById(R.id.channel_0);
channel_1 = (FocusRelativeLayout) view.findViewById(R.id.channel_1);
channel_2 = (FocusRelativeLayout) view.findViewById(R.id.channel_2);
channel_3 = (FocusRelativeLayout) view.findViewById(R.id.channel_3);
channel_4 = (FocusRelativeLayout) view.findViewById(R.id.channel_4);
channel_5 = (FocusRelativeLayout) view.findViewById(R.id.channel_5);
channel_6 = (FocusRelativeLayout) view.findViewById(R.id.channel_6);
channel_7 = (FocusRelativeLayout) view.findViewById(R.id.channel_7);
channel_8 = (FocusRelativeLayout) view.findViewById(R.id.channel_8);
channel_9 = (FocusRelativeLayout) view.findViewById(R.id.channel_9);
}
@Override
publicvoidonGlobalFocusChanged(View oldFocus, View newFocus) {
switch(newFocus.getId()) {
caseR.id.channel_0:
caseR.id.channel_1:
channel_0.setNextFocusLeftId(R.id.tv_one);
channel_1.setNextFocusLeftId(R.id.tv_one);
channel_1.setNextFocusDownId(R.id.tv_two);
caseR.id.channel_8:
caseR.id.channel_9:
channel_8.setNextFocusRightId(R.id.tv_three);
channel_9.setNextFocusRightId(R.id.tv_three);
channel_9.setNextFocusDownId(R.id.tv_two);
break;
caseR.id.channel_2:
caseR.id.channel_3:
caseR.id.channel_4:
caseR.id.channel_5:
caseR.id.channel_6:
caseR.id.channel_7:
channel_3.setNextFocusDownId(R.id.tv_two);
channel_5.setNextFocusDownId(R.id.tv_two);
channel_7.setNextFocusDownId(R.id.tv_two);
break;
}
}
}
到此,就完美实现了获取焦点的高亮显示。
网友评论