android tv gridview焦点放大效果

来源:互联网 发布:Java开发工程师 招聘 编辑:程序博客网 时间:2024/05/22 12:36

在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}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawBitmap(bitmap, 100, 100, mPaint);}}
但是其实还有一个方法也可以实现这个:

@Overrideprotected 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}@Overrideprotected 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() {@Overridepublic 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{@Overridepublic int getCount() {// TODO Auto-generated method stubreturn datas.size();}@Overridepublic Object getItem(int position) {return null;}@Overridepublic long getItemId(int position) {return 0;}@Overridepublic 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);}@Overridepublic 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;}@Overrideprotected int getChildDrawingOrder(int childCount, int i) {if (position != -1) {if (i == childCount - 1)return position;if (i == position)return childCount - 1;}return i;}@Overridepublic 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">@Overrideprotected int getChildDrawingOrder(int childCount, int i) {if (position != -1) {if (i == childCount - 1)return position;if (i == position)return childCount - 1;}return i;}@Overridepublic void bringChildToFront(View child) {position = indexOfChild(child);postInvalidate();}
这个是为了解决焦点框被上层item挡住
getChildDrawingOrder 是改变子view的绘制顺序,如果要重写这个必须先 setChildrenDrawingOrderEnabled(true);来允许子类排序




2 1