仿支付宝钱包:带分割线的GridView

需求:


本文记录了我尝试实现支付宝钱包样式带分割线GridView的过程。首先看一下高大上的支付宝钱包首页:

                                                                                    仿支付宝钱包:带分割线的GridView_第1张图片

这里画红框的部分,给人的直观感觉就是一个GridView 。当然,这里很可能是支付宝同学自定义了一个GridView的子类 。相对于ListView的单列列表,GridView则是一种支持多行多列的网格形式。 当我们想要实现例如九宫格的效果时,GridView即是首选。

然而,与ListView可以方便的设置和自定义分割线不同不同,GridView貌似并不提供分割线属性。这样,只能开动劳动人民的智慧来尝试解决了。(今天进行了三次尝试,成功的方式在第三次尝试中。 欢迎大家提供更好的实现方法)

第一次尝试:item的背景图


这个方法实际上是从网上看到的,使用最多的解决方案。 简而言之,就是对GridView的每个单元做背景图。代码说话:



    

        

        
    

  

 

在item_gridview中,已矩形框为背景:


        
            

            
        
        
            

            
        
        
            

            
        

 
在Activity中对GridView设置Adapter,充入对象,效果如下图所示。(目前仅探究gridview,其他部分还比较丑)
                                                                               仿支付宝钱包:带分割线的GridView_第2张图片

感觉哪里不对。。 通过比较中间的列和最右边的列可以发现,分割线太粗了!
虽然在xml中设置的是最小值 1px , 然而看起来还是比支付宝钱包的效果粗很多。 因为后者才是 真·1px ,前者的分割线实际上是相邻单元的边框合并在了一起,所以看起来要粗很多。

第二次尝试:相邻单元只有一个背景


上面的问题已经可以看出,是相邻的单元格背景框相邻使分割线变粗。 那么可以提出相应的解决办法:相邻单元格只有一个有背景。
    
以当前4列的情况为例,实际上,可以去掉:
     第一行的第二,第四个单元
     第二行的第一,第三个单元
     第三行的第二,第四个单元
     。。。

可以总结出规律,通过去掉行列数奇偶性不同的单元,可以使相邻的单元(包括上下相邻和左右相邻)不同时具有边框。在adapter的getView方法中加入如下代码:
if(position/4%2!=position%2){
				RelativeLayout layout=(RelativeLayout)convertView.findViewById(R.id.layout_gridview);
				layout.setBackgroundResource(R.drawable.item_gridview2);
}

 


其中item_gridview2是边框为空白的背景
效果图:
                                                                                  仿支付宝钱包:带分割线的GridView_第3张图片
这是才发现,我犯了一个很2的错误:小看了1px的误差
当相邻单元的边框去除后,成对角方向的单元框对不齐了。。 

第三次尝试:暴力加框


这一次比较直接和暴力,最终达到了预想的效果。但是显得不是那么聪明和巧妙,这里抛砖引玉,希望路过的大牛能给出更好的实现方法。

这一次,通过在单元格xml中插入两个宽度为1px的ImageView做边框,来实现gridview的伪分割线:




    


    

        

        

        


    

        

    

 最终效果。。
                                                                                 仿支付宝钱包:带分割线的GridView_第4张图片

第四次尝试:重写dispatchDraw 方法


这里我们可以对gridview进行重绘, 重写父类的dispatchDraw方法。
思路基本跟方法三一致,对每个子item画两条框。不同之处在于,当我们采用动态绘制(而不是写死在xml)时,可以针对不同的情况进行判断和定制,使最后的效果更完美。 在这里,可以考虑到左右上下的对称性和gridview的item数不是列数的整数倍时的情况。 重写代码如下:
@Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        View localView1 = getChildAt(0);
        int column = getWidth() / localView1.getWidth();
        int childCount = getChildCount();
        Paint localPaint= new Paint();
        localPaint.setStyle(Paint.Style.STROKE);
        localPaint.setColor(getContext().getResources().getColor(R.color.lightgray));
        for(int i = 0;i < childCount;i++){
            View cellView = getChildAt(i);
            if((i + 1) % column == 0){ //最右侧只画底部边框
                canvas.drawLine(cellView.getLeft(), cellView.getBottom(), cellView.getRight(), cellView.getBottom(), localPaint);
            }else if((i + 1) > (childCount - (childCount % column))){//最下部只画右侧边框
                canvas.drawLine(cellView.getRight(), cellView.getTop(), cellView.getRight(), cellView.getBottom(), localPaint);
            }else{//画底部和右侧边框
                canvas.drawLine(cellView.getRight(), cellView.getTop(), cellView.getRight(), cellView.getBottom(), localPaint);
                canvas.drawLine(cellView.getLeft(), cellView.getBottom(), cellView.getRight(), cellView.getBottom(), localPaint);
            }
        }
        //如果最后一行不足,则补全缺省item的右侧竖线。
        if(childCount % column != 0){
            for(int j = 0 ;j < (column-childCount % column) ; j++){
                View lastView = getChildAt(childCount - 1);
                canvas.drawLine(lastView.getRight() + lastView.getWidth() * j, lastView.getTop(), lastView.getRight() + lastView.getWidth()* j, lastView.getBottom(), localPaint);
            }
        }
    }

 
效果与第三种方法相同。




你可能感兴趣的:(android,学习笔记)