自定义GridView实现放大功能

来源:互联网 发布:南宁广电网络 编辑:程序博客网 时间:2024/04/28 17:19

         随着盒子的广泛使用,以及 智能电视的普及,大屏的android设备进入到各家各户,由于观看电视据电视较远,我们希望焦点在跳变的时候,能有一种放大作用,能让人眼清晰的识别焦点在哪位置上,一些放大效果就出现了,GridView作为一种常见的控件,经常用到,但是要在原生的GridView中实现放大,总是有这样那样的问题,根据本人的经验,讲下GridView 如何实现放大效果。

    首先我们看一看一般的gridview放大,我们都是在getView中通过监听focus事件实现放大效果,当获得焦点时,加载放大动画,失去焦点时,加载缩小动画,愿望是美好的,那么这种放大效果如何

private GridView mGridView;private List<Integer> mList=new ArrayList<Integer>();private MyAdapter adapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_common);mList=initList();mGridView=(GridView) findViewById(R.id.common_gridview);adapter=new MyAdapter();mGridView.setAdapter(adapter);}private List<Integer> initList() {List<Integer> list=new ArrayList<Integer>();list.add(R.drawable.bailain);list.add(R.drawable.baimei);list.add(R.drawable.fenlinghua);list.add(R.drawable.fusanghua);list.add(R.drawable.haitanghua);list.add(R.drawable.hongmei);list.add(R.drawable.hehuanhua);list.add(R.drawable.lianhua);list.add(R.drawable.lanhua);return list;}class MyAdapter extends BaseAdapter {@Overridepublic int getCount() {return mList.size();}@Overridepublic Object getItem(int position) {return mList.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewHolder holder;if(convertView==null){holder=new ViewHolder();convertView=LayoutInflater.from(getApplicationContext()).inflate(R.layout.item_common, null);holder.image=(ImageView) convertView.findViewById(R.id.image_common);holder.text=(TextView) convertView.findViewById(R.id.name_common);convertView.setTag(holder);}else {holder=(ViewHolder) convertView.getTag();}holder.image.setImageBitmap(getBitmapFromId(mList.get(position)));holder.text.setText(getTextFromId(mList.get(position)));convertView.setOnFocusChangeListener(new OnFocusChangeListener() {@Overridepublic void onFocusChange(View v, boolean hasFocus) {if (hasFocus) {Animation animation=AnimationUtils.loadAnimation(getApplicationContext(), R.anim.enlarg);v.startAnimation(animation);}else {Animation animation=AnimationUtils.loadAnimation(getApplicationContext(), R.anim.shrink);v.startAnimation(animation);}}});return convertView;}class ViewHolder{ImageView image;TextView text;}private CharSequence getTextFromId(Integer integer) {String string = null;switch (integer) {case R.drawable.bailain:string="bailain";break;case R.drawable.baimei:string="baimei";break;case R.drawable.fenlinghua:string="fenlinghua";break;case R.drawable.fusanghua:string="fusanghua";break;case R.drawable.guihua:string="guihua";break;case R.drawable.hehuanhua:string="hehuanhua";break;case R.drawable.hongmei:string="hongmei";break;case R.drawable.lanhua:string="lanhua";break;case R.drawable.lianhua:string="lianhua";break;case R.drawable.haitanghua:string="haitanghua";break;default:break;}return string;}private Bitmap getBitmapFromId(Integer integer) {Bitmap bitmap = null;switch (integer) {case R.drawable.bailain:bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.bailain);break;case R.drawable.baimei:bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.baimei);break;case R.drawable.fenlinghua:bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.fenlinghua);break;case R.drawable.fusanghua:bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.fusanghua);break;case R.drawable.guihua:bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.guihua);break;case R.drawable.hehuanhua:bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.hehuanhua);break;case R.drawable.hongmei:bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.hongmei);break;case R.drawable.lanhua:bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.lanhua);break;case R.drawable.lianhua:bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.lianhua);break;case R.drawable.haitanghua:bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.haitanghua);break;default:break;}return bitmap;}}

Activity和item的布局文件

<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" >    <GridView        android:id="@+id/common_gridview"        android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:layout_gravity="center"        android:layout_marginLeft="300dp"        android:layout_marginRight="300dp"        android:descendantFocusability="afterDescendants"        android:fadeScrollbars="true"        android:focusable="true"        android:gravity="center"        android:horizontalSpacing="30dp"        android:numColumns="4"        android:verticalSpacing="30dp" >    </GridView></RelativeLayout>

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    style="@android:style/Widget.Button"    android:layout_width="150dp"    android:layout_height="150dp"    android:layout_gravity="center"    android:clickable="true"    android:descendantFocusability="afterDescendants"    android:focusable="true"    android:gravity="center" >    <ImageView        android:id="@+id/image_common"        android:layout_width="150dp"        android:layout_height="150dp"        android:scaleType="fitXY" />    <TextView        android:id="@+id/name_common"        android:layout_width="150dp"        android:layout_height="wrap_content"        android:layout_alignBottom="@+id/image_common" /></RelativeLayout>

看一把运行效果



这是啥情况,左边和上边的边缘竟然被切割了,如果我们调小item之间的距离,即属性android:horizontalSpacing和android:verticalSpacing,再运行一把 


我们发现放大选项被边缘被右侧和下方的遮蔽了,该怎么办呢,我在一次使用gallery的时候发现他们的item居然是可以叠在一起的,由此启发,我认为gridview的背景如果使用合理的点九图,就可以向四周要的额外的空间,他的实际空间是大于我们人眼所能看到的。

我使用了一张给四周留有较多空隙,只有中间可编辑的点九图

如图所示


啥也看不到,没关系,在点九工具中打开



呵呵,运行一把


啊,我们发现四周边缘现在出来了,不会被边界覆盖,那么下一个问题就是解决,被右边和下边选项遮蔽的问题。

通过查阅资料,发现View的绘制机制是从左到右,从上到下,所以放大后才会被右侧和下侧的选项遮蔽,那有没有一种方法能够改变绘制顺序呢,让当前获得焦点的item最后一个绘制,就能把其他的选项压在下面。

先在GridView中寻找,找了半天,没有,继续往上,AbsListView也没有,继续找,终于在ViewGroup中找到了这个方法。

看源码 

   /**     * Tells the ViewGroup whether to draw its children in the order defined by the method     * {@link #getChildDrawingOrder(int, int)}.     *     * @param enabled true if the order of the children when drawing is determined by     *        {@link #getChildDrawingOrder(int, int)}, false otherwise     *     * @see #isChildrenDrawingOrderEnabled()     * @see #getChildDrawingOrder(int, int)     */    protected void setChildrenDrawingOrderEnabled(boolean enabled) {        setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);    }

setChildrenDrawingOrderEnabled(boolean enabled)这个方法把标志设为 true能够让ViewGroup通过设定的方式来改变View的绘制方式,具体的实现是哪个方法呢,也在ViewGroup中

 /**     * Returns the index of the child to draw for this iteration. Override this     * if you want to change the drawing order of children. By default, it     * returns i.     * <p>     * NOTE: In order for this method to be called, you must enable child ordering     * first by calling {@link #setChildrenDrawingOrderEnabled(boolean)}.     *     * @param i The current iteration.     * @return The index of the child to draw this iteration.     *     * @see #setChildrenDrawingOrderEnabled(boolean)     * @see #isChildrenDrawingOrderEnabled()     */    protected int getChildDrawingOrder(int childCount, int i) {        return i;    }

先看下这个方法的注释
返回容器中子view的索引,如果你想改变子控件的绘制顺序,要覆写这个方法,默认的返回i,注意:为了让这个方法被调用,你必须首先让子控件可变的属性变为可用,即调用
setChildrenDrawingOrderEnabled(boolean)

属性 i 是当前的迭代,对这个迭代,我的理解为当前子控件在ViewGroup中的原始顺序。返回的为当前控件在整个容器中的绘制顺序。

好了知道了这些方法后,我们自定义一个MyGridView实现具体的放大

public class MyGridView extends GridView{private int position=0;public MyGridView(Context context, AttributeSet attrs) {super(context, attrs);setChildrenDrawingOrderEnabled(true);}@Overrideprotected void setChildrenDrawingOrderEnabled(boolean enabled) {super.setChildrenDrawingOrderEnabled(enabled);}@Overrideprotected int getChildDrawingOrder(int childCount, int i) {position = getSelectedItemPosition()- getFirstVisiblePosition();if(position<0){return i;}else{if(i == childCount - 1){//这是最后一个需要刷新的itemif(position>i){position=i;}            return position;        }if(i == position){//这是原本要在最后一个刷新的itemreturn childCount - 1;}}return i;}}



好了,逻辑有点乱,慢慢理解,首先我们获取被选择的子控件在当前GridView中的绘制顺序。如果为负值(可能出现的异常情况)就按照默认返回。如果大于零,正常情况如果当前子控件已经是最后一个了,就按照正常返回,如果不是最后一个,返回最大值,最后一个绘制。

看一下效果

第一项完美的解决了四周被遮蔽,右边下边被遮挡的问题,这只是假象,焦点放在第二个,还是没有解决


原因是啥呢,在我自定义的GridView中改变绘制顺序我使用了这一句 position = getSelectedItemPosition()- getFirstVisiblePosition(),getSelectedItemPosition()只有在被选择的时候,也就是触发onitemselect的时候才会得到正确的效果,我的放大是在focus中调用的,不会触发到select事件,后面的绘制顺序也就错了,所以要实现放大,需要在onitemselect中实现

public class MainActivity extends Activity implements OnItemSelectedListener,OnFocusChangeListener{private MyGridView mGridView;private List<Integer> mList=new ArrayList<Integer>();private MyAdapter adapter;private View mPreView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mList=initList();mGridView=(MyGridView) findViewById(R.id.browse_gridview);adapter=new MyAdapter();mGridView.setAdapter(adapter);mGridView.setOnItemSelectedListener(this);mGridView.setOnFocusChangeListener(this);}private List<Integer> initList() {List<Integer> list=new ArrayList<Integer>();list.add(R.drawable.bailain);list.add(R.drawable.baimei);list.add(R.drawable.fenlinghua);list.add(R.drawable.fusanghua);list.add(R.drawable.haitanghua);list.add(R.drawable.hongmei);list.add(R.drawable.hehuanhua);list.add(R.drawable.lianhua);list.add(R.drawable.lanhua);return list;}@Overridepublic void onItemSelected(AdapterView<?> parent, View view, int position,long id) {if(parent.hasFocus()){if(mPreView!=null){Animation   animation=AnimationUtils.loadAnimation(getApplicationContext(), R.anim.shrink);mPreView.startAnimation(animation);}Animation animation=AnimationUtils.loadAnimation(getApplicationContext(), R.anim.enlarg);view.startAnimation(animation);mPreView=view;}else{if(mPreView!=null){Animation   animation=AnimationUtils.loadAnimation(getApplicationContext(), R.anim.shrink);mPreView.startAnimation(animation);mPreView=null;}}}@Overridepublic void onNothingSelected(AdapterView<?> parent) {if(mPreView!=null){Animation   animation=AnimationUtils.loadAnimation(getApplicationContext(), R.anim.shrink);mPreView.startAnimation(animation);mPreView=null;}}class MyAdapter extends BaseAdapter{@Overridepublic int getCount() {return mList.size();}@Overridepublic Object getItem(int position) {return mList.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewHolder holder;if(convertView==null){holder=new ViewHolder();convertView=LayoutInflater.from(getApplicationContext()).inflate(R.layout.item, null);holder.image=(ImageView) convertView.findViewById(R.id.image);holder.text=(TextView) convertView.findViewById(R.id.name);convertView.setTag(holder);}else {holder=(ViewHolder) convertView.getTag();}holder.image.setImageBitmap(getBitmapFromId(mList.get(position)));holder.text.setText(getTextFromId(mList.get(position)));return convertView;}private CharSequence getTextFromId(Integer integer) {String string = null;switch (integer) {case R.drawable.bailain:string="bailain";break;case R.drawable.baimei:string="baimei";break;case R.drawable.fenlinghua:string="fenlinghua";break;case R.drawable.fusanghua:string="fusanghua";break;case R.drawable.guihua:string="guihua";break;case R.drawable.hehuanhua:string="hehuanhua";break;case R.drawable.hongmei:string="hongmei";break;case R.drawable.lanhua:string="lanhua";break;case R.drawable.lianhua:string="lianhua";break;case R.drawable.haitanghua:string="haitanghua";break;default:break;}return string;}private Bitmap getBitmapFromId(Integer integer) {Bitmap bitmap = null;switch (integer) {case R.drawable.bailain:bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.bailain);break;case R.drawable.baimei:bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.baimei);break;case R.drawable.fenlinghua:bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.fenlinghua);break;case R.drawable.fusanghua:bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.fusanghua);break;case R.drawable.guihua:bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.guihua);break;case R.drawable.hehuanhua:bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.hehuanhua);break;case R.drawable.hongmei:bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.hongmei);break;case R.drawable.lanhua:bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.lanhua);break;case R.drawable.lianhua:bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.lianhua);break;case R.drawable.haitanghua:bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.haitanghua);break;default:break;}return bitmap;}class ViewHolder{ImageView image;TextView text;}}@Overridepublic void onFocusChange(View v, boolean hasFocus) {if(hasFocus){View view=mGridView.getSelectedView();if(view!=null){Animation animation=AnimationUtils.loadAnimation(getApplicationContext(), R.anim.enlarg);view.startAnimation(animation);mPreView=view;}else{if(mPreView!=null){Animation animation=AnimationUtils.loadAnimation(getApplicationContext(), R.anim.shrink);mPreView.startAnimation(animation);mPreView=null;}}}}}


最终效果图,在大屏电视上显示,还是比较完美的,也比较简单。



好了,至此,完整的流程实现了,放大效果普遍用于TV 开发,在手机中因为事件拦截,或者某些事件触发后一瞬即逝,放大效果不一定实现或者看的见,在手机上要看到放大效果,需要在onitemclick中添加动画事件,才能完成。


下面附上demo下载地址,那个是在电视上做的,不适配手机,手机需要改改

点击这里下载

好了,这是第一篇本人有图有真相的博客,比较乱,如有错误,忘批评指出。

文明发言,礼貌做人!





















1 0
原创粉丝点击