自定义View(java,kotlin) - 仿京东流式布局 2.26

效果图:
在这里插入图片描述
细节方面没有考虑
java:

public class FlowLayout extends ViewGroup {

    private static final String TAG = "FlowLayout";

    private int mHorizontalSpacing = dq2px(16);
    private int mVerticlaSpacing = dq2px(8);

    private List<List<View>> allLines; //记录所有行的View
    private List<Integer> lineHeights = new ArrayList();//记录每一行的行高

    public FlowLayout(Context context) {
        super(context);
    }

    public FlowLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        initMeasureParams();
        //测量所有子View的大小
        int childCount = getChildCount();
        int paddingLeft = getPaddingLeft();
        int paddingRigth = getPaddingRight();
        int paddingTop = getPaddingTop();
        int paddingBottom = getPaddingBottom();

        int selfWidth = MeasureSpec.getSize(widthMeasureSpec);
        int selfHeight = MeasureSpec.getSize(heightMeasureSpec);

        List<View> lineViews = new ArrayList<>();
        //保存一行中所有的View

        int lineWidthUsed = 0;
        //记录每一行已经使用的宽度

        int lineHeight = 0;
        //一行的高度

        int parentNeededWidth = 0;
        int parentNeededHeight = 0;
        //meauser过程中,子View要求的父ViewGroup的宽高

        //遍历所有的子View
        for(int i=0;i<childCount;i++){
            View childView = getChildAt(i);

            LayoutParams childLP = childView.getLayoutParams();

           int childWidthMeasureSpec =  getChildMeasureSpec(widthMeasureSpec,paddingLeft+paddingRigth,childLP.width);
           int childHeightMeasureSpec =  getChildMeasureSpec(heightMeasureSpec,paddingTop+paddingBottom,childLP.height);

           childView.measure(childWidthMeasureSpec,childHeightMeasureSpec);

           //获取view的宽高
            int childMeausreWidth = childView.getMeasuredWidth();
            int childMeasureHeight = childView.getMeasuredHeight();

            if(childMeausreWidth + lineWidthUsed + mHorizontalSpacing > selfWidth){
                allLines.add(lineViews);
                lineHeights.add(lineHeight);

                parentNeededHeight = parentNeededHeight + lineHeight +mVerticlaSpacing;
                parentNeededWidth = Math.max(parentNeededWidth,lineWidthUsed+mHorizontalSpacing);

                //集合重置
                lineViews = new ArrayList<>();
                lineWidthUsed = 0;
                lineHeight = 0;
            }
            lineViews.add(childView);

            lineWidthUsed = lineWidthUsed + childMeausreWidth + mHorizontalSpacing;
            lineHeight = Math.max(lineHeight,childMeasureHeight);


            //判断尾行
            if(i == childCount -1){
                lineHeights.add(lineHeight);
                allLines.add(lineViews);
                parentNeededWidth = Math.max(parentNeededWidth,lineWidthUsed);
                parentNeededHeight += lineHeight;
            }

        }

        //根据子View的度量结果 来重新度量自己
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        int realWidth = (widthMode == MeasureSpec.EXACTLY) ? selfWidth:parentNeededWidth;
        int realHeight = (heightMode == MeasureSpec.EXACTLY) ? selfHeight:parentNeededHeight;

        setMeasuredDimension(realWidth,realHeight);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        int lineCount = allLines.size();

        int curL = 0;
        int curT = 0;

        for(int i=0;i<lineCount;i++){
            List<View> lineViews = allLines.get(i);
            int lineHeight = lineHeights.get(i);
            for(int j=0;j<lineViews.size();j++){
                View view = lineViews.get(j);
                int left1 = curL;
                int top1 = curT;

                int bottom1 = top1 +view.getMeasuredHeight();
                int right1 = left1 +view.getMeasuredWidth();

                view.layout(left1,top1,right1,bottom1);
                curL = right1 + mHorizontalSpacing;
            }
            curL=0;
            curT = curT + lineHeight + mVerticlaSpacing;
        }
    }

    private void initMeasureParams(){
        allLines = new ArrayList<>();
        lineHeights = new ArrayList<>();
    }

    public static int dq2px(int dp){
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp, Resources.getSystem().getDisplayMetrics());
    }
}

kotiln:

class FlowLayout : ViewGroup {

    var views:ArrayList<ArrayList<View>>?=null//记录子View
    var lineHeights :ArrayList<Int>?=null //记录行高
    var mHorizontalSpacing = dq2px(0)//子view横向间距
    var mVerticalSapcing = dq2px(8)//子view行间距


    //父类有参构造
    constructor(context: Context):super(context){}
    constructor(context: Context,attributeSet: AttributeSet):super(context,attributeSet){}

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {

        initMeasureParams()

        var mPaddingLeft = getPaddingLeft()
        var mPaddingTop = paddingTop
        var mPaddingRight = paddingRight
        var mPaddingBottom = paddingBottom

        var lineViews:ArrayList<View> = arrayListOf()
        var lineWidthUsed = 0
        var lineHeight = 0

        var parentNeededWidth=0
        var parentNeededHeight=0

        var selfWidth = MeasureSpec.getSize(widthMeasureSpec)
        var selfHeight = MeasureSpec.getSize(heightMeasureSpec)

        for(i in 0 until childCount){
            println("childCount :$childCount")
            val mChildView:View = getChildAt(i)
            var mChildViewLP = mChildView?.layoutParams


            //根据父容器的MeasureSpec 自身宽高 以及布局参数 得到 childView的MeasureSpec
            val childWidthMS = getChildMeasureSpec(
                widthMeasureSpec,
                mPaddingLeft + mPaddingRight,
                mChildViewLP.width
            )
            val childHeightMS = getChildMeasureSpec(
                heightMeasureSpec,
                mPaddingTop + mPaddingBottom,
                mChildViewLP.height
            )

            mChildView.measure(childWidthMS,childHeightMS)

            val childMeasuredWidth = mChildView.measuredWidth
            val childMeasuredHeight = mChildView.measuredHeight

            if(childMeasuredWidth+lineWidthUsed+mHorizontalSpacing>selfWidth){
                views?.add(lineViews)
                lineHeights?.add(lineHeight)

                //一行布局结束
                //判断当前行需要的宽和高
                parentNeededHeight = parentNeededHeight+lineHeight+mVerticalSapcing
                parentNeededWidth = Math.max(parentNeededHeight,lineWidthUsed+mHorizontalSpacing)

                lineViews = arrayListOf()
                lineWidthUsed = 0
                lineHeight = 0
            }
            lineViews.add(mChildView)
            lineWidthUsed = lineWidthUsed+childMeasuredWidth+mHorizontalSpacing
            lineHeight = Math.max(lineHeight,childMeasuredHeight)


            //如果当前子view 是最后一行的最后一个
            if(i == childCount-1){
                lineHeights?.add(lineHeight)
                views?.add(lineViews)
                println("views :${views?.size}")
                parentNeededWidth = Math.max(parentNeededWidth,lineWidthUsed)
                parentNeededHeight+=lineHeight
            }

        }


        //根据子view的度量结果来度量自己

        var widthMode = MeasureSpec.getMode(widthMeasureSpec)
        var heightMode = MeasureSpec.getMode(heightMeasureSpec)

        var realWidth = when(widthMode){
            MeasureSpec.EXACTLY -> selfWidth
            else -> parentNeededWidth
        }

        var realHeight = when(heightMode){
            MeasureSpec.EXACTLY -> selfHeight
            else -> parentNeededHeight
        }

        setMeasuredDimension(realWidth,realHeight)

    }






    override fun onLayout(p0: Boolean, p1: Int, p2: Int, p3: Int, p4: Int) {
       var lineCount = views?.size
        println("lineCount:$lineCount---lineHeights;${lineHeights?.size}")
        var curLeft = 0
        var curTop = 0

        for(i in 0 until lineCount!!){
            var lineViews = views?.get(i)
            val lineHeight = lineHeights?.get(i)
            for (j in 0 until lineViews?.size!!){
                val view = lineViews.get(j)
                var left = curLeft
                var top = curTop

                var bottom = top+view.measuredHeight
                var right = left+view.measuredWidth
                view.layout(left,top,right,bottom)
                curLeft = right+mHorizontalSpacing
            }
            curLeft = 0
            curTop = curTop+lineHeight!!+mVerticalSapcing
        }
    }

    fun initMeasureParams(){
        views = arrayListOf(arrayListOf())
        lineHeights = arrayListOf()
    }

    fun dq2px(dp:Int):Int{
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp.toFloat(),Resources.getSystem().displayMetrics)?.toInt()
    }

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
最近在学习kotlin,项目中正好用到了图片浏览,就用kotlin放照微信的做了一个,效果如下:大概就是这么个效果,图片从小到大的一个效果,然后滑动切换图片,点击后会返回对应图片的位置,其实比较容易,用到的是ActivityOptions,一个activity的转场动画,下面说一下怎么实现。github地址点这里关于kotlin的配置就不过多说了,网上好多教程(最近kotlin好火)布局就是一个recyclerviewmainactivity代码:可以看到就一个初始化布局管理器和设置适配器的代码没什么了(你说没看到初始化控件?看看这篇文章)到这里之前都很好理解,关键就是adapter和点击图片跳转的代码在API 21以后,我们可以使用内置的Activity切换动画。但是这样也就意味着只能兼容5.0之后的系统,ActivityOptions是一个静态类,它提供了为数不多的几种方法,我们正是用其中的makeSceneTransitionAnimation(Activity activity,Pair… sharedElements)来完成了这个效果,有兴趣的小伙伴移步至这里,先来说下传递的两个参数,第一个activity不用说,第二个pair,View是你开始动画的view对象,string是他的动画名要和结束动画的view名一致才可以,到这里应该可以理解,我们在创建适配器的时候给每个imageview起了一个transitionname当我们跳转至查看大图界面给当前的viewpage赋值相同的名称便能完成动画,然后在我们滑动时更改viewpage的transitionname为对应图片的transitionname这样在点击图片的时候就会显示对应图片的下标。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值