成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

您的位置:首頁技術文章
文章詳情頁

Android自定義流式布局/自動換行布局實例

瀏覽:183日期:2022-09-26 14:48:39

最近,Google開源了一個流式排版庫“FlexboxLayout”,功能強大,支持多種排版方式,如各種方向的自動換行等,具體資料各位可搜索學習^_^。

由于我的項目中,只需要從左到右S型的自動換行,需求效果圖如下:

Android自定義流式布局/自動換行布局實例

使用FlexboxLayout這個框架未免顯得有些臃腫,所以自己動手寫了一個流式ViewGroup。

安卓中自定義ViewGroup的步驟是:

1. 新建一個類,繼承ViewGroup

2. 重寫構造方法

3. 重寫onMeasure、onLayout方法

onMeasuer方法里一般寫測量子View寬高、確定此控件寬高的代碼;onLayout方法則是確定子View如何擺放(排版)。

代碼如下:

import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; public class FlexBoxLayout extends ViewGroup { private int mScreenWidth; private int horizontalSpace, verticalSpace; private float mDensity;//設備密度,用于將dp轉為px public FlexBoxLayout(Context context) { this(context, null); } public FlexBoxLayout(Context context, AttributeSet attrs) { super(context, attrs); //獲取屏幕寬高、設備密度 mScreenWidth = context.getResources().getDisplayMetrics().widthPixels; mDensity = context.getResources().getDisplayMetrics().density; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //確定此容器的寬高 int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); //測量子View的寬高 int childCount = getChildCount(); View child = null; //子view擺放的起始位置 int left = getPaddingLeft(); //一行view中將最大的高度存于此變量,用于子view進行換行時高度的計算 int maxHeightInLine = 0; //存儲所有行的高度相加,用于確定此容器的高度 int allHeight = 0; for (int i = 0; i < childCount; i++) {child = getChildAt(i);//測量子View寬高measureChild(child, widthMeasureSpec, heightMeasureSpec);//兩兩對比,取得一行中最大的高度if (child.getMeasuredHeight() + child.getPaddingTop() + child.getPaddingBottom() > maxHeightInLine) { maxHeightInLine = child.getMeasuredHeight() + child.getPaddingTop() + child.getPaddingBottom();}left += child.getMeasuredWidth() + dip2px(horizontalSpace) + child.getPaddingLeft() + child.getPaddingRight();if (left >= widthSize - getPaddingRight() - getPaddingLeft()) {//換行 left = getPaddingLeft(); //累積行的總高度 allHeight += maxHeightInLine + dip2px(verticalSpace); //因為換行了,所以每行的最大高度置0 maxHeightInLine = 0;} } //再加上最后一行的高度,因為之前的高度累積條件是換行 //最后一行沒有換行操作,所以高度應該再加上 allHeight += maxHeightInLine; if (widthMode != MeasureSpec.EXACTLY) {widthSize = mScreenWidth;//如果沒有指定寬,則默認為屏幕寬 } if (heightMode != MeasureSpec.EXACTLY) {//如果沒有指定高度heightSize = allHeight + getPaddingBottom() + getPaddingTop(); } setMeasuredDimension(widthSize, heightSize); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { if (changed) { //擺放子view View child = null; //初始子view擺放的左上位置 int left = getPaddingLeft(); int top = getPaddingTop(); //一行view中將最大的高度存于此變量,用于子view進行換行時高度的計算 int maxHeightInLine = 0; for (int i = 0, len = getChildCount(); i < len; i++) { child = getChildAt(i); //從第二個子view開始算起 //因為第一個子view默認從頭開始擺放 if (i > 0) { //兩兩對比,取得一行中最大的高度 if (getChildAt(i - 1).getMeasuredHeight() > maxHeightInLine) { maxHeightInLine = getChildAt(i - 1).getMeasuredHeight(); } //當前子view的起始left為 上一個子view的寬度+水平間距 left += getChildAt(i - 1).getMeasuredWidth() + dip2px(horizontalSpace); if (left + child.getMeasuredWidth() >= getWidth() - getPaddingRight() - getPaddingLeft()) {//這一行所有子view相加的寬度大于容器的寬度,需要換行 //換行的首個子view,起始left應該為0+容器的paddingLeft left = getPaddingLeft(); //top的位置為上一行中擁有最大高度的某個View的高度+垂直間距 top += maxHeightInLine + dip2px(verticalSpace); //將上一行View的最大高度置0 maxHeightInLine = 0; } } //擺放子view child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight()); } } } /** * dp轉為px * * @param dpValue * @return */ private int dip2px(float dpValue) { return (int) (dpValue * mDensity + 0.5f); } /** * 設置子view間的水平間距 單位dp * * @param horizontalSpace */ public void setHorizontalSpace(int horizontalSpace) { this.horizontalSpace = horizontalSpace; } /** * 設置子view間的垂直間距 單位dp * * @param verticalSpace */ public void setVerticalSpace(int verticalSpace) { this.verticalSpace = verticalSpace; } }

使用如下:

xml文件:

<com.zengd.FlexBoxLayout android: android:layout_width='match_parent' android:layout_height='match_parent'> <!--這里寫子View,也可代碼動態添加--> …… </com.zengd.FlexBoxLayout>

Activity里的代碼:

FlexBoxLayout flexBoxLayout = (FlexBoxLayout) findViewById(R.id.flex_box_layout); flexBoxLayout.setHorizontalSpace(10);//不設置默認為0 flexBoxLayout.setVerticalSpace(10);//不設置默認為0

運行效果如圖:

Android自定義流式布局/自動換行布局實例

本項目Demo地址:

https://github.com/zengd0/FlexBoxLayout

補充知識:Android 流式布局(修改版) 當達到兩行,隱藏多余的

我就廢話不多說了,還是直接看代碼吧!

public class SearchLayout extends LinearLayout { private final int mParentWidth; private float textSize; private boolean textColor; private boolean background; private boolean isHide = true; public void setHide(boolean hide) { isHide = hide; } public SearchLayout(Context context, AttributeSet attrs) { super(context, attrs); //獲取屏幕的寬度 DisplayMetrics metrics = context.getResources().getDisplayMetrics(); mParentWidth = metrics.widthPixels - dip2px(16f); //自定義屬性 TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.SearchLayout); background = array.getBoolean(R.styleable.SearchLayout_Sear_background,false); textColor = array.getBoolean(R.styleable.SearchLayout_Sear_textColor, false); textSize = array.getDimension(R.styleable.SearchLayout_Sear_textSize, 0); //方向為縱向 setOrientation(VERTICAL); } //移除子控件 public void removeView() { removeAllViews(); } //流式布局 public void setData(List<String> data) { if (data.isEmpty()){ return; } //獲取一個子布局 LinearLayout linearLayout = getLinearLayout(); for (int i = 0; i < data.size(); i++) { //標題 final String name = data.get(i); //已存在的寬度 int numBar = 0; //子控件的個數 int count = linearLayout.getChildCount(); for (int j = 0; j < count; j++) {//一個一個獲取ThemeTextView textView = (ThemeTextView) linearLayout.getChildAt(j);//獲取左外邊距LayoutParams params = (LayoutParams) textView.getLayoutParams();int leftWidth = params.leftMargin;int rightWidth = params.rightMargin;//獲取寬高textView.measure(getMeasuredWidth(), getMeasuredHeight());//計算已存在的寬度numBar += textView.getMeasuredWidth()+leftWidth+rightWidth; } //獲取一個子控件 ThemeTextView text = getText(); //給每一個控件設置點擊事件 text.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View view) { if (onItemTitleClickListener != null){ onItemTitleClickListener.onItemTitle(name); }} }); //賦值 text.setText(name); //獲取寬高 text.measure(getMeasuredWidth(), getMeasuredHeight()); //當前控件的寬度 int textWidth = text.getMeasuredWidth() + text.getPaddingLeft() + text.getPaddingRight(); //判斷是否超過屏幕 if (isHide && getChildCount() == 2){ImageView imageView = getMore(false);LayoutParams layoutParams = (LayoutParams) imageView.getLayoutParams();int leftM = layoutParams.leftMargin;int rightM = layoutParams.rightMargin;imageView.measure(getMeasuredWidth(), getMeasuredHeight());int width = imageView.getMeasuredWidth() + imageView.getPaddingLeft() + imageView.getPaddingRight();int imageWidth = leftM + rightM + width;if (numBar + textWidth + imageWidth >= mParentWidth){ if (numBar + textWidth + imageWidth > mParentWidth){ imageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) {if (onMoreClickListener != null){ onMoreClickListener.onShowMore(isHide);} } }); linearLayout.addView(imageView); return; } else { imageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) {if (onMoreClickListener != null){ onMoreClickListener.onShowMore(isHide);} } }); linearLayout.addView(text); linearLayout.addView(imageView); return; }}else { if (i + 1 <= data.size()-1) { String title = data.get(i + 1); ThemeTextView themeTextView = getText(); themeTextView.setText(title); themeTextView.measure(getMeasuredWidth(),getMeasuredHeight()); int themeTextViewWidth = themeTextView.getMeasuredWidth() + themeTextView.getPaddingLeft() + themeTextView.getPaddingRight(); if (mParentWidth >= numBar + textWidth + imageWidth + themeTextViewWidth ){ linearLayout.addView(text); continue; }else { imageView.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) { if (onMoreClickListener != null){ onMoreClickListener.onShowMore(isHide); }} }); linearLayout.addView(text); linearLayout.addView(imageView); return; } }} } if (i == data.size() - 1 && (getChildCount() >= 3 || (mParentWidth < numBar + textWidth) && getChildCount() == 2)){ImageView imageView = getMore(true);LayoutParams layoutParams = (LayoutParams) imageView.getLayoutParams();int leftM = layoutParams.leftMargin;int rightM = layoutParams.rightMargin;imageView.measure(getMeasuredWidth(), getMeasuredHeight());int width = imageView.getMeasuredWidth() + imageView.getPaddingLeft() + imageView.getPaddingRight();int imageWidth = leftM + rightM + width;imageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (onMoreClickListener != null){ onMoreClickListener.onShowMore(isHide); } }});if (mParentWidth >= numBar + textWidth + imageWidth){ linearLayout.addView(text); linearLayout.addView(imageView);}else { if (mParentWidth >= numBar + textWidth){ linearLayout.addView(text); linearLayout = getLinearLayout(); linearLayout.addView(imageView); }else { linearLayout = getLinearLayout(); linearLayout.addView(text); linearLayout.addView(imageView); }}return; } if (mParentWidth >= numBar + textWidth) {//沒有,繼續添加linearLayout.addView(text); } else {//否者,重新獲取一個子布局,再添加linearLayout = getLinearLayout();linearLayout.addView(text); } } } public LinearLayout getLinearLayout() { //創建LinearLayout布局 LinearLayout linearLayout = new LinearLayout(getContext()); //設置寬高 LayoutParams params = new LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); linearLayout.setLayoutParams(params); //添加到主布局中 this.addView(linearLayout); return linearLayout; } public ThemeTextView getText() { //創建TextView控件 //設置字體大小,顏色,內邊距 ThemeTextView themeTextView = new ThemeTextView(getContext()); themeTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX , textSize); themeTextView.setMaxEms(7); themeTextView.setLines(1); themeTextView.setEllipsize(TextUtils.TruncateAt.END); themeTextView.setPadding(dip2px(8), dip2px(4), dip2px(8), dip2px(4)); if (textColor){//可以根據自己的需求修改判斷 themeTextView.setTextColor(ContextCompat.getColor(getContext(),R.color.day_text_color_thirdly)); }else { themeTextView.setTextColor(ContextCompat.getColor(getContext(),R.color.day_text_color_thirdly)); } if (background){ themeTextView.setBackgroundResource(R.drawable.border_search_background_day); } //設置寬高 LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); //外邊距 params.setMargins(dip2px(8),dip2px(8),dip2px(8),dip2px(8)); themeTextView.setLayoutParams(params); return themeTextView; } public ImageView getMore(boolean isHide){ ImageView imageView = new ImageView(getContext()); if (background){ imageView.setBackgroundResource(R.drawable.border_search_background_day); } imageView.setImageResource(R.drawable.icon_more); if (isHide){ imageView.setRotation(180f); } imageView.setColorFilter(ContextCompat.getColor(getContext(),R.color.day_text_color_primary)); imageView.setPadding(dip2px(6), dip2px(6), dip2px(7), dip2px(7)); //設置寬高 LayoutParams params = new LayoutParams(ConfigSingleton.dip2px(27), ConfigSingleton.dip2px(27)); //外邊距 params.setMargins(dip2px(8),dip2px(8),dip2px(8),dip2px(8)); imageView.setLayoutParams(params); return imageView; } public interface OnItemTitleClickListener{ void onItemTitle(String title); } public interface OnMoreClickListener{ void onShowMore(boolean ishide); } private OnItemTitleClickListener onItemTitleClickListener; private OnMoreClickListener onMoreClickListener; public void setOnItemTitleClickListener(OnItemTitleClickListener onItemTitleClickListener) { this.onItemTitleClickListener = onItemTitleClickListener; } public void setOnMoreClickListener(OnMoreClickListener onMoreClickListener) { this.onMoreClickListener = onMoreClickListener; }public int dip2px(float dipValue) {float scale = getContext().getResources().getDisplayMetrics().density;return (int) (dipValue * scale + 0.5f);}}

attrs文件:

<declare-styleable name='SearchLayout'> <attr name='Sear_textSize' format='dimension'/> <attr name='Sear_textColor' format='boolean'/> <attr name='Sear_background' format='boolean'/> </declare-styleable>

以上這篇Android自定義流式布局/自動換行布局實例就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持好吧啦網。

標簽: Android
相關文章:
成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
不卡视频一二三| 91麻豆精品国产91久久久久| 视频精品一区二区| 日韩毛片一二三区| 亚洲精品福利视频网站| 日韩中文字幕一区二区三区| 欧美日韩在线播放一区二区| 亚洲精品影院| 91成人看片片| 欧美一级片在线观看| 国产欧美一区在线| 国产精品国产三级国产专播品爱网| 欧美成人a∨高清免费观看| 久久这里只精品最新地址| 亚洲欧洲在线观看av| 久久狠狠亚洲综合| 91香蕉视频mp4| 国产三区精品| 在线亚洲人成电影网站色www| 欧美午夜片在线看| 久久先锋影音av鲁色资源网| 成人综合婷婷国产精品久久蜜臀| 黑丝一区二区三区| 91黄色激情网站| 三级不卡在线观看| 国产一区二区高清| 一区二区三区在线播| 免费一级欧美片在线观看| 国产精品一区在线| 99久久99久久免费精品蜜臀| 国产精品视频免费观看| 国产精品大尺度| 一区在线视频| 亚洲国产成人不卡| 中文成人综合网| 国产在线观看一区二区| 亚洲区国产区| 日韩欧美成人一区| 亚洲资源在线观看| 国产不卡视频在线播放| 99riav1国产精品视频| 中文字幕一区二区三| 欧美午夜在线视频| ●精品国产综合乱码久久久久 | 欧美不卡视频一区| 国产大陆a不卡| 国产伦一区二区三区色一情| 精品国产乱码久久久久久浪潮| 丝袜脚交一区二区| 在线精品亚洲一区二区不卡| 精品一区二区三区蜜桃| 亚洲精品乱码| 亚洲二区在线视频| 国外成人免费视频| 一区二区三区日韩欧美精品| 久久国产精品亚洲77777| 日韩视频免费观看高清完整版在线观看| 亚洲靠逼com| 免费日韩精品中文字幕视频在线| 久久久久久久久久久久电影| 久久精品国产亚洲aⅴ| 欧美日韩一区二区在线观看| 中文字幕日本不卡| 国产女主播一区二区三区| 美女网站在线免费欧美精品| 国产伦精品一区二区三区高清版| 亚洲成a人片在线观看中文| 欧美91大片| 欧美日韩国产成人在线91| 亚洲综合无码一区二区| 老牛国产精品一区的观看方式| 日韩一区中文字幕| 一本色道久久综合一区 | 337p亚洲精品色噜噜| 99精品视频一区二区| 亚洲女同ⅹxx女同tv| 欧美一区二区三区在线播放 | 日本精品一区二区三区高清| 国产精品一线二线三线| 中国色在线观看另类| 性一交一乱一区二区洋洋av| 国产精品一区二区不卡| 国产精品久久三区| 一本色道久久综合精品竹菊| 国产福利一区二区三区视频在线 | 在线亚洲观看| 国产又黄又大久久| 中文字幕在线播放不卡一区| 91久久久免费一区二区| 成人久久视频在线观看| 亚洲日本在线观看| 欧美日韩一区二区欧美激情| 你懂的成人av| 日韩精品久久久久久| 精品国产精品网麻豆系列 | 亚洲久久成人| 久久精品国产77777蜜臀| 久久久久久麻豆| 久久riav二区三区| av日韩在线网站| 91精品久久久久久久久99蜜臂| 色综合天天综合| 精品国产伦一区二区三区观看体验 | 亚洲高清一区二区三区| 日韩精品中文字幕一区| 在线观看成人av电影| 国产原创一区二区三区| 亚洲人成伊人成综合网小说| 6080国产精品一区二区| 亚洲欧洲日夜超级视频| 国产精品18久久久久| 亚洲人精品午夜| 欧美一区二区精品| 国产精品丝袜xxxxxxx| 丁香另类激情小说| 香蕉久久夜色精品国产使用方法 | 亚洲综合男人的天堂| 欧美一区二区在线免费观看| 99xxxx成人网| 不卡的av电影在线观看| 亚洲国产精品综合小说图片区| 精品少妇一区二区三区免费观看| 亚久久调教视频| 欧美 日韩 国产精品免费观看| 日韩精品欧美精品| 国产精品色呦呦| 7777精品久久久大香线蕉| 国产区日韩欧美| 99精品在线观看视频| 久久99精品久久久久久国产越南| 综合色中文字幕| 日韩精品一区二区三区在线播放| 欧美亚洲一区二区三区| 99精品国产91久久久久久| 捆绑调教一区二区三区| 亚洲精品视频免费看| 国产亚洲精品7777| 欧美色图麻豆| 韩国精品主播一区二区在线观看| 日韩精品一区二区三区老鸭窝| 久久久久国产精品一区二区| 国产综合色在线视频区| 一区二区三区中文字幕电影 | 好看的亚洲午夜视频在线| 国产成人精品亚洲777人妖| 五月婷婷另类国产| 欧美视频一区二区三区在线观看 | 亚洲精品乱码久久久久久蜜桃麻豆| 成人av在线观| 美国毛片一区二区三区| 一区二区视频免费在线观看| 中文字幕av资源一区| 中文精品视频| 欧美激情日韩| 婷婷亚洲久悠悠色悠在线播放 | 国产夜色精品一区二区av| 欧美日韩aaaaa| 色综合久久天天| 国产欧美亚洲日本| 亚洲二区在线| 欧美日韩国内| 91老师国产黑色丝袜在线| 国产精品一区二区三区四区| 秋霞午夜鲁丝一区二区老狼| 亚洲成人综合网站| 亚洲乱码国产乱码精品精可以看| 欧美国产乱子伦| 久久综合国产精品| 精品久久久网站| 在线综合视频播放| 欧美日韩一区二区三区免费看 | 99re视频这里只有精品| 成人一区在线观看| 国产一区二区三区黄视频| 奇米色一区二区| 亚洲aaa精品| 亚洲第一精品在线| 亚洲午夜私人影院| 亚洲一区二区三区爽爽爽爽爽| 亚洲人成电影网站色mp4| 国产精品每日更新在线播放网址| 国产婷婷色一区二区三区在线| 久久蜜桃av一区二区天堂| 精品日本一线二线三线不卡| 欧美一区永久视频免费观看| 欧美日本一道本在线视频| 欧美日韩一区中文字幕| 欧美日韩美少妇| 91精品国产综合久久香蕉的特点| 在线免费观看日本欧美| 欧美在线观看视频一区二区 | 欧美喷水一区二区| 欧美另类久久久品| 伊大人香蕉综合8在线视| 欧美日韩一区二区视频在线观看| 国语精品中文字幕| 亚洲精品欧洲精品| 亚洲一区国产一区| 久久精品一区二区国产| 色呦呦日韩精品|