android tv gridview焦点放大效果

在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画上去,而dispat


chDraw通常是用在容器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 rig


ht, 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);来允许子类排序

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值