Android 利用 HorizontalScrollView

作者: d74f37143a31 | 来源:发表于2018-10-31 22:55 被阅读57次

    最近在实现一个标签云效果,参考的是这个兄弟的博文
    Android自定义控件之自定义ViewGroup实现标签云

    在上面的博文中博主已经写的很详细了 来不急作图,先用上面兄弟博文图片

    我这边实现的效果是能实现左右水平滑动的标签云效果。在刚开始想着用 HorizontalScrollView做父布局,然后子布局就用上文博主的自定义的标签云控件

     <HorizontalScrollView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scrollbars="none">
            <com.xxxx.xxx.TagsLayout
                    android:id="@+id/tagsLayout"
                    style="@style/AppWrapContent"
                    android:layout_gravity="center_vertical"
                    android:layout_marginStart="18dp"
                    android:layout_marginEnd="10dp"
                    app:tagHorizontalSpace="12dp"
                    app:tagVerticalSpace="12dp" />
        </HorizontalScrollView>
    

    但是这样做的效果是 标签云控件的宽度只显示子布局中最大的宽度。后来想着是不是在外头加上 LinearLayout来实现父布局填满,最后是这样:

     <HorizontalScrollView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scrollbars="none">
            <LinearLayout
                android:id="@+id/layout_tag"
                style="@style/AppWrapContent"
                android:orientation="horizontal">
                <com.XXX.XXX.TagsLayout
                    android:id="@+id/tagsLayout"
                    style="@style/AppWrapContent"
                    android:layout_gravity="center_vertical"
                    android:layout_marginStart="18dp"
                    android:layout_marginEnd="10dp"
                    app:tagHorizontalSpace="12dp"
                    app:tagVerticalSpace="12dp" />
            </LinearLayout>
        </HorizontalScrollView>
    

    但是这样还是不能实现水平滑动,因为TagsLayout的宽度还是和父布局一样,所以在TagsLayout中再需要改改,需要改动的地方是

     @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            // 获得它的父容器为它设置的测量模式和大小
            int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
            int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
            int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
            int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
          
    // 需要修改的地方
    sizeWidth = 屏幕宽度+屏幕宽度的一半
    
        }
    

    最后附上上文兄弟的源码: 我的改动还未添加到源码中,明天补上。

    public class TagsLayout extends ViewGroup {
        private int childHorizontalSpace;
        private int childVerticalSpace;
    
        public TagsLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
            TypedArray attrArray = context.obtainStyledAttributes(attrs, R.styleable.TagsLayout);
            if (attrArray != null) {
                childHorizontalSpace = attrArray.getDimensionPixelSize(R.styleable.TagsLayout_tagHorizontalSpace, 0);
                childVerticalSpace = attrArray.getDimensionPixelSize(R.styleable.TagsLayout_tagVerticalSpace, 0);
                attrArray.recycle();
            }
        }
    
        /**
         * 负责设置子控件的测量模式和大小 根据所有子控件设置自己的宽和高
         */
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            // 获得它的父容器为它设置的测量模式和大小
            int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
            int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
            int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
            int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
            // 如果是warp_content情况下,记录宽和高
            int width = 0;
            int height = 0;
            /**
             * 记录每一行的宽度,width不断取最大宽度
             */
            int lineWidth = 0;
            /**
             * 每一行的高度,累加至height
             */
            int lineHeight = 0;
    
            int count = getChildCount();
            int left = getPaddingLeft();
            int top = getPaddingTop();
            // 遍历每个子元素
            for (int i = 0; i < count; i++) {
                View child = getChildAt(i);
                if (child.getVisibility() == GONE)
                    continue;
                // 测量每一个child的宽和高
                measureChild(child, widthMeasureSpec, heightMeasureSpec);
                // 得到child的lp
                MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
                // 当前子空间实际占据的宽度
                int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin + childHorizontalSpace;
                // 当前子空间实际占据的高度
                int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin + childVerticalSpace;
                /**
                 * 如果加入当前child,则超出最大宽度,则的到目前最大宽度给width,类加height 然后开启新行
                 */
                if (lineWidth + childWidth > sizeWidth - getPaddingLeft() - getPaddingRight()) {
                    width = Math.max(lineWidth, childWidth);// 取最大的
                    lineWidth = childWidth; // 重新开启新行,开始记录
                    // 叠加当前高度,
                    height += lineHeight;
                    // 开启记录下一行的高度
                    lineHeight = childHeight;
                    child.setTag(new Location(left, top + height, childWidth + left - childHorizontalSpace, height + child.getMeasuredHeight() + top));
                } else {// 否则累加值lineWidth,lineHeight取最大高度
                    child.setTag(new Location(lineWidth + left, top + height, lineWidth + childWidth - childHorizontalSpace + left, height + child.getMeasuredHeight() + top));
                    lineWidth += childWidth;
                    lineHeight = Math.max(lineHeight, childHeight);
                }
            }
            width = Math.max(width, lineWidth) + getPaddingLeft() + getPaddingRight();
            height += lineHeight;
            sizeHeight += getPaddingTop() + getPaddingBottom();
            height += getPaddingTop() + getPaddingBottom();
            setMeasuredDimension((modeWidth == MeasureSpec.EXACTLY) ? sizeWidth : width, (modeHeight == MeasureSpec.EXACTLY) ? sizeHeight : height);
        }
    
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            int count = getChildCount();
            for (int i = 0; i < count; i++) {
                View child = getChildAt(i);
                if (child.getVisibility() == GONE)
                    continue;
                Location location = (Location) child.getTag();
                child.layout(location.left, location.top, location.right, location.bottom);
            }
        }
    
        /**
         * 记录子控件的坐标
         */
        public class Location {
            public Location(int left, int top, int right, int bottom) {
                this.left = left;
                this.top = top;
                this.right = right;
                this.bottom = bottom;
            }
    
            public int left;
            public int top;
            public int right;
            public int bottom;
    
        }
    }
    

    文末~

    相关文章

      网友评论

        本文标题:Android 利用 HorizontalScrollView

        本文链接:https://www.haomeiwen.com/subject/mcwztqtx.html