美文网首页
HeightListView - 自适应TextView高度

HeightListView - 自适应TextView高度

作者: phantomvk | 来源:发表于2018-02-06 13:42 被阅读0次

    使用Adapter可能需要在一个item里包含ListView控件动态展示多个TextView。普通的ListView会出现所有的TextView只显示第一行而不是多行内容的问题。

    问题的根源是ListView没有正确计算出每个TextView文字需要的高度,仅显示一行文字的高度。

    重写的的类中,把计算高度的onItemsChanged()通过DataSetObserver绑定到数据对应的adapter,且重写onMeasure(int, int)。数据改变时回调DataSetObserver,新数据对应的TextView高度得到计算。

    DataSetObserver在初始化ListView的时候已经创建完成,在setAdapter(ListAdapter adapter)中绑定到adapter

    经过上面的处理,令HeightListViewListView用法无异。

    /**
     * Auto height calculating ListView.
     * Calculates items' total height which includes some TextViews.
     * Use it just like a common ListView.
     * Author: PhantomVK
     */
    public final class HeightListView extends ListView {
    
        private DataSetObserver mDataSetObserver; // The custom data set observer.
    
        public HeightListView(Context context) {
            this(context, null);
        }
    
        public HeightListView(Context context, AttributeSet attrs) {
            super(context, attrs);
            createObserver();
        }
    
        public HeightListView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            createObserver();
        }
    
        /**
         * Overrides to set a suitable measure spec.
         *
         * @param widthMeasureSpec  widthMeasureSpec, not changed.
         * @param heightMeasureSpec heightMeasureSpec replaced with a custom one.
         */
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int spec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
            super.onMeasure(widthMeasureSpec, spec);
        }
    
        /**
         * Sets the data behind this ListView.
         * <p>
         * Unregisters the observer of the pre adapter before which will be replaced.
         * After the new adapter is setted, registers a observer.
         *
         * @param adapter Set the new listView adapter
         */
        @Override
        public void setAdapter(ListAdapter adapter) {
            if (adapter == null) throw new NullPointerException();
    
            if (getAdapter() != null) {
                getAdapter().unregisterDataSetObserver(mDataSetObserver);
            }
    
            adapter.registerDataSetObserver(mDataSetObserver);
            super.setAdapter(adapter);
        }
    
        /**
         * Creates a custom data set change observer.
         */
        private void createObserver() {
            if (mDataSetObserver != null) return;
            mDataSetObserver = new DataSetObserver() {
                @Override
                public void onChanged() {
                    super.onChanged();
                    onItemsChanged();
                }
            };
        }
    
        /**
         * Calculates the height of all sub items, includes divider height of each item.
         */
        private void onItemsChanged() {
            int count = getAdapter().getCount();
            if (count == 0) return;
    
            int height = 0;
            for (int i = 0; i < count; i++) {
                View v = getAdapter().getView(i, null, this);
                v.measure(0, 0);
                height += v.getMeasuredHeight();
            }
    
            ViewGroup.LayoutParams params = getLayoutParams();
            params.height = height + getDividerHeight() * (count - 1);
            setLayoutParams(params);
        }
    
        @Override
        public boolean isClickable() {
            return super.isClickable();
        }
    
        @Override
        public boolean isEnabled() {
            return super.isEnabled();
        }
    }
    

    最后还把isClickable()isEnabled()显式调用父类方法:itemListView展示的所有subitem都是可以点击的。要subitem把点击事件传递给item处理,则需要重写或设置上述两个方法的值为false

    相关文章

      网友评论

          本文标题:HeightListView - 自适应TextView高度

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