您的位置:首页 > 移动开发 > Android开发

android tv gridview焦点放大效果

2016-05-08 22:40 337 查看
在tv上开发gridview有焦点放大这个效果还是很普遍的做法,今天就讲下这个实现方案,当然要实现这个效果有很多种,我这里只是讲其中的一种实现方案,也是比较简单而且容易看懂的一个,首先看下效果图是怎么样的?



这个肯定也许会这么想我选中了那个item就设置一张焦点框图片就可以实现,告诉你没这么简单,这个框是根据你选中了那个item而动态画上去的,而画的位置是要获取item view的坐标的,我准备把这个用到的知识点分开一点点讲,然后再合拼起来,首先说下怎么把一个背景图画上去,我们知道自定义一个view在onDraw()方法中画

public class CutomView extends View {
private Paint mPaint;
private Bitmap bitmap;
public CutomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

public CutomView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
}

public CutomView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bitmap, 100, 100, mPaint);
}
}
但是其实还有一个方法也可以实现这个:

@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
canvas.drawBitmap(bitmap, 400, 400, mPaint);
}
看下效果:



前面一个是坐标点(100,100)后一个坐标点是(400,400) 说明这二个方法都可以把一个资源通过canvas画上去,而dispatchDraw通常是用在容器view中的,所谓的容器view就是能有addView()方法,比如RelativeLayout,LinearLayout,ListView,GridView等,但是像上面的焦点框是咋么画上去的呢?是一个view还是一个其他的东西呢?如果是view的画就要再自定义一个view,当然也可以不用view,用Drawable也行,看下view的继承或者实现关系:



从图可以看出来view实现了Drawable.Callback还有KeyEvent.Callback,前者是关于Drawable一些方法比如如何把一张图片绘制到view上,后者是一些关于一些遥控器事件,关于Drawable一些方法大概如下:



这些方法我我们不可能全部搞懂或者用到,在这里就讲2到3个方法,

draw(Canvas canvas)是用于把drawable绘制到view上的

setBounds(Rect bounds)和setBounds(int left, int top, int right, int bottom)这二个方法其实是一个意思,当你要把一个drawable绘制到屏幕上.你肯定要知道要绘制在那个位置,而我们知道其实每个view都是一个Rect也就是一个矩形,我们知道这个矩形也就意味着把这个view的2个点确定下来,那么现在就自定义一个RelativeLayout,然后通过上面讲的方法如何把一个图片绘制到view上,代码如下:

public class CutomView extends RelativeLayout {
private Paint mPaint;
private Bitmap bitmap;
private Drawable drawable;
public CutomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

public CutomView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
drawable = getResources().getDrawable(R.drawable.topic_focus);//这是焦点框
}
public CutomView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
drawable.setBounds(100, 100, 500, 500);
drawable.draw(canvas);
}
}
效果图:



如果要达到gridview焦点放大的效果是不是要知道每个item view的坐标点,知道了这个如何动态绘制这个焦点框是不是就可以了,通常获取一个view的坐标有如下四种做法

1:getLocationInWindow

这个获取坐标是相当于当前的activity,我现在做一个实验,如何获取这个坐标点,

button = (Button) findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
int[] position = new int[2];
button.getLocationInWindow(position);
Log.e(TAG,"getLocationInWindow:" + position[0] + "," + position[1]);
}
});



结果是:

x=0y=228但是我button的位置是这样的:



我这button离父view左边是0上边也是0也就是y轴的高度也是0,而这打印出来是228,就说明这个是相对于屏幕的,屏幕就有状态栏和标题栏,获取状态栏高度

Rect frame = new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
int statusBarHeight = frame.top;
获取标题栏高度
//statusBarHeight是上面所求的状态栏的高度
int titleBarHeight = contentTop - statusBarHeight ;
结果是statusBarHeight 是60  titleBarHeight是168 加起来就是228了,这就验证了getLocationInWindow()是相对屏幕而已不是相对父view而言,
int[] position = new int[2];
button.getLocationOnScreen(position);
System.out.println("getLocationOnScreen:" + position[0] + "," + position[1]);
这个获取x,y轴坐标是一样的,
getGlobalVisibleRec
这个是通过view围城的矩形来获取它的坐标:
<pre name="code" class="java">Rect viewRect = new Rect();
button.getGlobalVisibleRect(viewRect);
Log.e(TAG,"left="+viewRect.left+"top="+viewRect.top+"right="+viewRect.right+"bottom"+viewRect.bottom)


结果:<span style="font-family: Arial, Helvetica, sans-serif;">left=0top=228right=353bottom372</span>


这个也是相对它屏幕而言的,

getLocalVisibleRect

Rect globeRect = new Rect();
button.getLocalVisibleRect(globeRect);
Log.e(TAG,"left="+globeRect.left+"top="+globeRect.top+"right="+globeRect.right+"bottom"+globeRect.bottom);


结果:
这个结果说明这个是相对于父view而言的 子view的坐标<span style="line-height: 25.2px;">好了分析就到这里了,现在把好的效果代码贴上来</span>
<span style="line-height: 25.2px;">example.demo;</span>
import java.util.ArrayList;
import java.util.List;
import com.commons.CustomImageView;
import com.commons.ZoneGridView;
import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class MainActivity extends Activity {
private ZoneGridView gridview;
private List<String> datas;
private MyAdapter adapter;
private CustomImageView iv;
private int[] ids={R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w,R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w,R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w,R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w,R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w,R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w,R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w,R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w,R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w,R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w,R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w,R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w,R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w,R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w,R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w,R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w,R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w,R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w,R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w,R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w,R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w,R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w,R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w,R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e,R.drawable.f,R.drawable.g,R.drawable.h
,R.drawable.i,R.drawable.j,R.drawable.x,R.drawable.y,R.drawable.r,R.drawable.w};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gridview = (ZoneGridView) findViewById(R.id.gridview);
iv = (CustomImageView) findViewById(R.id.iv);
initData();
adapter = new MyAdapter();
gridview.setAdapter(adapter);
gridview.setClipToPadding(false);
gridview.setSelected(true);
gridview.setSelection(0);
gridview.setSelector(android.R.color.transparent);
gridview.setMySelector(R.drawable.topic_focus);
gridview.setMyScaleValues(1.2f, 1.2f);
}
private void initData() {
datas = new ArrayList<String>();
for(int i=0;i<ids.length;i++){
datas.add("专辑列表---"+i);
}
}
class MyAdapter extends BaseAdapter{

@Override
public int getCount() {
// TODO Auto-generated method stub
return datas.size();
}

@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if(convertView==null){
viewHolder = new ViewHolder();
convertView = LayoutInflater.from(getApplicationContext()).inflate(R.layout.item, null);
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.iv = (ImageView) convertView.findViewById(R.id.iv);
viewHolder.tv_name = (TextView) convertView.findViewById(R.id.tv_name);
viewHolder.tv_name.setText(datas.get(position));
viewHolder.iv.setImageResource(ids[position]);
return convertView;
}
}
class ViewHolder{
ImageView iv;
TextView tv_name;
}
}


xml文件

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.commons.ZoneGridView
android:id="@+id/gridview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="6"
android:horizontalSpacing="8dp"
android:verticalSpacing="30dp"
android:layout_marginTop="20dp"
android:gravity="center_horizontal"
android:drawSelectorOnTop="true"
android:scrollbars="none"
android:padding="30dp"
android:background="#ff0000"
>
</com.commons.ZoneGridView>
</RelativeLayout>



自定义的GridView

package com.commons;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class ZoneGridView extends GridView {
float mMyScaleX = 1.0f;
float mMyScaleY = 1.0f;
protected Rect mMySelectedPaddingRect = new Rect();
int mPlayIconMargin;
private int position = 0;

public ZoneGridView(Context contxt) {
super(contxt);
setChildrenDrawingOrderEnabled(true);
setClipChildren(false);
setClipToPadding(false);
}

public ZoneGridView(Context contxt, AttributeSet attrs) {
super(contxt, attrs);
setChildrenDrawingOrderEnabled(true);
setClipChildren(false);
setClipToPadding(false);
}

public ZoneGridView(Context contxt, AttributeSet attrs, int defStyle) {
super(contxt, attrs, defStyle);
setChildrenDrawingOrderEnabled(true);
setClipChildren(false);
setClipToPadding(false);
}

@Override
public void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (mMySelectedDrawable == null)
return;
drawSelector(canvas);
}
/**
* 设置焦点框的图片
* @param resId
*/
public void setMySelector(int resId) {
mMySelectedDrawable = getResources().getDrawable(resId);
mMySelectedPaddingRect = new Rect();
mMySelectedDrawable.getPadding(mMySelectedPaddingRect);//获取drawable所画区域的内边框
}
protected Drawable mMySelectedDrawable = null;
protected View mMySelectedView = null;
protected Rect mTmpSelectedRect = new Rect();
protected Rect mTmpGridViewRect = new Rect();
/**
* 这是关键点
* @param canvas
*/
protected void drawSelector(Canvas canvas) {
View v = getSelectedView();
bringChildToFront(v);
if (isFocused() && v != null) {
scaleCurrentView();
if(v instanceof RelativeLayout){
RelativeLayout rl = (RelativeLayout) v;
ImageView tmepView = (ImageView) rl.getChildAt(0);
TextView tv = (TextView) rl.getChildAt(1);
tv.setTextColor(Color.WHITE);
Rect r = mTmpSelectedRect;
tmepView.getGlobalVisibleRect(r);//Rect(62, 152 - 398, 512) 计算出imageview在屏幕的坐标点
getGlobalVisibleRect(mTmpGridViewRect);//计算出屏幕的坐标点 Rect(45, 141 - 1875, 1035)

r.offset(-mTmpGridViewRect.left, -mTmpGridViewRect.top);//向左移动--mTmpGridViewRect.left就是向右滑动-mTmpGridViewRect.left

r.top -= mMySelectedPaddingRect.top+DensityUtil.dip2px(getContext(), 6);
r.left -= mMySelectedPaddingRect.left+DensityUtil.dip2px(getContext(), 6);
r.right += mMySelectedPaddingRect.right+DensityUtil.dip2px(getContext(), 6);
r.bottom += mMySelectedPaddingRect.bottom+DensityUtil.dip2px(getContext(), 6);
mMySelectedDrawable.setBounds(r);
mMySelectedDrawable.draw(canvas);
}
}
}
public void setMyScaleValues(float scaleX, float scaleY) {
mMyScaleX = scaleX;
mMyScaleY = scaleY;
}
void scaleCurrentView(){
View v = getSelectedView();
unScalePrevView();
if(v != null){
mMySelectedView = v;
mMySelectedView.setScaleX(mMyScaleX);
mMySelectedView.setScaleY(mMyScaleY);
}
}
/**
* 把上一次获取焦点 还原
*/
void unScalePrevView(){
if(mMySelectedView != null){
if(mMySelectedView instanceof RelativeLayout){
RelativeLayout rl = (RelativeLayout) mMySelectedView;
TextView tv = (TextView) rl.getChildAt(1);
tv.setTextColor(Color.RED);
}
mMySelectedView.setScaleX(1);
mMySelectedView.setScaleY(1);
mMySelectedView = null;
}
}
protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
if(!gainFocus){
unScalePrevView();
requestLayout();
}
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
}
protected int mMyVerticalSpacing = 0;
public void setMyVerticalSpacing(int verticalSpacing) {
mMyVerticalSpacing = verticalSpacing;
}
public int getMyVerticalSpacing() {
return mMyVerticalSpacing;
}
@Override
protected int getChildDrawingOrder(int childCount, int i) {
if (position != -1) {
if (i == childCount - 1)
return position;
if (i == position)
return childCount - 1;
}
return i;
}
@Override
public void bringChildToFront(View child) {
position = indexOfChild(child);
postInvalidate();
}
}

item布局:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ImageView
android:id="@+id/iv"
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@drawable/w"
android:scaleType="fitXY"
/>
<TextView
android:id="@+id/tv_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#ff0000"
android:text="江湖论剑"
android:layout_below="@id/iv"
android:layout_marginTop="5dp"
/>
</RelativeLayout>


其中自定义gridview有一段关键的代码:

<pre code_snippet_id="1675432" snippet_file_name="blog_20160508_28_338885" name="code" class="java">@Override
protected int getChildDrawingOrder(int childCount, int i) {
if (position != -1) {
if (i == childCount - 1)
return position;
if (i == position)
return childCount - 1;
}
return i;
}
@Override
public void bringChildToFront(View child) {
position = indexOfChild(child);
postInvalidate();
}



这个是为了解决焦点框被上层item挡住
getChildDrawingOrder 是改变子view的绘制顺序,如果要重写这个必须先 setChildrenDrawingOrderEnabled(true);来允许子类排序
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: