需求是这样的:
在应用程序的详情介绍时,有评论的版块,该页评论最多显示5条,而每条最大字数是140个字符,每条评论可能根据字数不同,所占据的高度也不一样,如有的是1行,有的是2、3行,且评论可以翻页。
图片效果如下:
如何解决这样的问题呢?
首先必须知道的是评论控件不要固定不变,而是需要动态计算并动态添加到显示面板中的。
下面通过实例来说一下。
1.定义布局
定义布局的时候,可以用AbsoluteLayout,因为高度是动态量取的,所以具体坐标是可以求得的。参考如下:
<AbsoluteLayout android:layout_width="1386px" android:layout_height="wrap_content" android:layout_marginTop="60px" android:id="@+id/comment_content"> </AbsoluteLayout>
该布局文件宽度设置不变,高度根据内容填充。只需将这个布局方在需要显示评论内容的地方。
2.显示数据
显示数据,需要根据数据来计算高度,首先把数据设置到控件中,然后通过View.measure(int
widthMeasureSpec, int heightMeasureSpec)量取高度,并为该View设置坐标。参考代码:
<span style="font-size:14px;">/** * 初始化、动态计算高度 */ public void initCommentView() { record_temp = new CommentRecord(); mPositionRecord = new ArrayList<Integer>(); mHeightRecord = new ArrayList<Integer>(); int currentHeight = 0; int maxNum = cachedComments.size(); int sum = 0; for (int i = comment_begin_index; i < maxNum; i++) { if (null != mCommentCache && !mCommentCache.empty()) { comment_temp = mCommentCache.pop(); } else { comment_temp = new CommentSimpleView(mContext); } mCommentUI.add(comment_temp); comment_temp.setData(cachedComments.get(i)); comment_temp.measure(width, height); if (MAX_COMMENT_HEIGHT > currentHeight) { comment_content.addView( comment_temp, new AbsoluteLayout.LayoutParams(1386, comment_temp .getMeasuredHeight(), 0, FIRST_COMMENT_INTERVAL + currentHeight)); mPositionRecord.add(FIRST_COMMENT_INTERVAL + currentHeight); mHeightRecord.add(comment_temp.getMeasuredHeight()); currentHeight = currentHeight + comment_temp.getMeasuredHeight(); comment_end_index++; sum++; if (sum < 5) { comment_temp.show_Divider(); } else if (sum == 5) { comment_temp.hide_Divider(); } } if (MAX_COMMENT_HEIGHT < currentHeight) { compareHeight = 1; isEnd = false; RelativeLayout.LayoutParams rl = (LayoutParams) comment_content .getLayoutParams(); rl.setMargins(0, 60, 0, 0); rl.width = 1386; rl.height = MAX_COMMENT_HEIGHT+20; comment_content.setLayoutParams(rl); break; } if (MAX_COMMENT_HEIGHT == currentHeight) { compareHeight = 0; if (maxNum == comment_end_index) { isEnd = true; comment_pagedown.setFocusStatus(false); } else { isEnd = false; } } } record_temp.setHeightRecord(mHeightRecord); record_temp.setPositionRecord(mPositionRecord); record_temp.setBegin_index(comment_begin_index); record_temp.setEnd_index(comment_end_index); if (MAX_COMMENT_HEIGHT > currentHeight) { isEnd = true; comment_pagedown.setFocusStatus(false); } }</span>
其中全局的宽、高定义如下:
int width = MeasureSpec.makeMeasureSpec(1386, MeasureSpec.EXACTLY);
int height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
3.翻页动态计算实现
/** * 点击下一页时,判断是否有空间剩余,若有剩余则用上一页数据补充,false:无剩余 * @return */ private boolean hasExtraSpace() { if(null != cachedComments && cachedComments.size()-comment_end_index >=5){ //剩下的评论大于5条 return false; } int beginIndex = 0; if(1 == compareHeight){ beginIndex = comment_end_index; }else if(0 == compareHeight){ beginIndex = comment_end_index+1; } int maxSize = cachedComments.size(); int HeightSum = 0; for(int i = beginIndex;i<maxSize;i++){ comment_temp = new CommentSimpleView(mContext); comment_temp.setData(cachedComments.get(i)); comment_temp.measure(width, height); HeightSum += comment_temp.getMeasuredHeight(); if(MAX_COMMENT_HEIGHT <= HeightSum){ return false; } } lastPageHeight = HeightSum; return true; } /** * 最后一页不满一屏,为倒数第一页,从最后一条倒序排列, */ public void showLastPage(){ int lastCommentNum = cachedComments.size() - comment_end_index; int copy_last_index = comment_end_index; while(128 <= MAX_COMMENT_HEIGHT - lastPageHeight){ lastCommentNum ++; comment_temp = new CommentSimpleView(mContext); comment_temp.setData(cachedComments.get(--copy_last_index)); comment_temp.measure(width, height); lastPageHeight+=comment_temp.getMeasuredHeight(); } if(MAX_COMMENT_HEIGHT < lastPageHeight){ lastCommentNum -- ; lastPageHeight -= comment_temp.getMeasuredHeight(); copy_last_index ++; } int sum = cachedComments.size(); int current_H = FIRST_COMMENT_INTERVAL + MAX_COMMENT_HEIGHT - lastPageHeight; for(int i= copy_last_index;i<sum;i++){ if(null != mCommentCache && !mCommentCache.empty()){ comment_temp = mCommentCache.pop(); }else{ comment_temp = new CommentSimpleView(mContext); } mCommentUI.add(comment_temp); comment_temp.setData(cachedComments.get(i)); comment_temp.measure(width, height); comment_content.addView(comment_temp, new AbsoluteLayout.LayoutParams(1386, comment_temp.getMeasuredHeight(), 0, current_H)); current_H = current_H + comment_temp.getMeasuredHeight(); if(i == sum -1){ comment_temp.hide_Divider(); }else{ comment_temp.show_Divider(); } } isEnd = true; comment_pagedown.setFocusStatus(false); } /** * 点击上一页,出栈,恢复数据并显示 */ public void showPageUp(){ if(mCommentRecord.empty()){ Toast.makeText(mContext, "已是第一页", Toast.LENGTH_SHORT).show(); return; } record_temp = mCommentRecord.pop(); int begin = record_temp.getBegin_index(); int end = record_temp.getEnd_index(); List<Integer> position = record_temp.getPositionRecord(); List<Integer> height = record_temp.getHeightRecord(); if(null == position || null == height){ return; } int m = 0; for(int i= begin;i<=end;i++){ if(null != mCommentCache && !mCommentCache.empty()){ comment_temp = mCommentCache.pop(); }else{ comment_temp = new CommentSimpleView(mContext); } mCommentUI.add(comment_temp); comment_temp.setData(cachedComments.get(i)); comment_content.addView(comment_temp, new AbsoluteLayout.LayoutParams(1386,height.get(m), 0, position.get(m))); m++; if(5 == m){ comment_temp.hide_Divider(); }else{ comment_temp.show_Divider(); } } isEnd = false; comment_begin_index = begin; comment_end_index = end; }
4.点击上一页、下一页事件处理
public class comment_pageup_click implements OkButtonViewClick { @Override public void onOkButtonViewClick() { if(1 == currentPage){ // Toast.makeText(mContext, "已是第一页", Toast.LENGTH_SHORT).show(); comment_pageup.setFocusStatus(false); return; }else{ currentPage = currentPage - 1; comment_content.removeAllViews(); while (!mCommentUI.isEmpty()) { mCommentCache.push(mCommentUI.remove(0)); } showPageUp(); comment_pagedown.setFocusStatus(true); } } } class comment_pagedown_click implements OkButtonViewClick { @Override public void onOkButtonViewClick() { if(isEnd){ // Toast.makeText(mContext, "已是最后一页", Toast.LENGTH_SHORT).show(); comment_pagedown.setFocusStatus(false); return; } else if(!isEnd){ //不到最后一页 if(!hasExtraSpace()){ //下一页无剩余空间,即该页不是倒数第二页 mCommentRecord.push(record_temp); currentPage = currentPage + 1; if(1 == compareHeight){ comment_begin_index = comment_end_index; comment_end_index --; }else{ comment_begin_index = comment_end_index+1; } if(currentPage%4 ==0){ //预加载数据 ParserHelper.getParserHelper().requestComment("1", "30", "9", callback); } comment_content.removeAllViews(); while (!mCommentUI.isEmpty()) { mCommentCache.push(mCommentUI.remove(0)); } initCommentView(); }else { //下一页有剩余空间,即该页为倒数第二页 mCommentRecord.push(record_temp); currentPage = currentPage + 1; comment_content.removeAllViews(); while (!mCommentUI.isEmpty()) { mCommentCache.push(mCommentUI.remove(0)); } showLastPage(); } comment_pageup.setFocusStatus(true); } } }
5.下一页点击时保存状态,用作恢复。(用栈保存,入栈出栈)
package com.helios.module.commentData; import java.util.List; public class CommentRecord { int begin_index; int end_index; List <Integer> positionRecord; List <Integer> heightRecord; public CommentRecord() { super(); } public int getBegin_index() { return begin_index; } public void setBegin_index(int begin_index) { this.begin_index = begin_index; } public int getEnd_index() { return end_index; } public void setEnd_index(int end_index) { this.end_index = end_index; } public List<Integer> getPositionRecord() { return positionRecord; } public void setPositionRecord(List<Integer> positionRecord) { this.positionRecord = positionRecord; } public List<Integer> getHeightRecord() { return heightRecord; } public void setHeightRecord(List<Integer> heightRecord) { this.heightRecord = heightRecord; } }
6.总结语
动态计算,动态设置布局还是挺常用的。
其中的关键就是,measure()方法的使用,设置好数据就可以measure(),量好高度后,再设置到显示面板中,即调用:
ViewGroup.addView(View child,
LayoutParams params)
第一次写动态布局,写的不好,希望大家勿喷,有疑问欢迎留言讨论,大家互相学习,慢慢进步。
时间: 2024-11-05 22:53:33