android 动态添加View
16lz
2021-01-23
项目中遇到动态添加view的需求来展示视频画面,整理一下供大家参考import android.annotation.SuppressLint;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Point;import android.graphics.Rect;import android.os.Build;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.util.Log;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.view.WindowManager;import android.widget.LinearLayout;import android.widget.TextView;import com.cloudroom.cloudroomvideosdk.model.UsrVideoId;import com.example.chenhe.s.sxlivevideo.R;import com.example.chenhe.s.sxlivevideo.common.Constants;import java.util.ArrayList;import java.util.Arrays;import java.util.Collections;import java.util.List;/** * @author:chenhe * @date:2019/4/1 11:44 */public class FlowTagLayout extends ViewGroup { private Context context; private Rect[] childrenBounds;// private List tagList; private ArrayList tagWatchableVideos; ArrayList WatchVideos = new ArrayList();//所有视频流 private OnTagClickListener onTagClickListener; private int defaultColor = Color.parseColor("#666666"); private float defaultTextSize = Utils.spToPx(16); /****************** 自定义的Attribute *************************/ private int leftMargin; private int rightMargin; private int topMargin; private int bottomMargin; private int leftPadding; private int rightPadding; private int topPadding; private int bottomPadding; private int background; private int textColor; private float textSize; public static int devd_w = 2; public static int devd_h = 1; private int screenWidth; private int screenHeight; public FlowTagLayout(Context context) { super(context); this.context = context; } public FlowTagLayout(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; init(attrs); getScreenSize(); } public FlowTagLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.context = context; init(attrs); getScreenSize(); } private void init(AttributeSet attrs) { TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.FlowTagLayout); leftMargin = (int) typedArray.getDimension(R.styleable.FlowTagLayout_item_leftMargin, 0); rightMargin = (int) typedArray.getDimension(R.styleable.FlowTagLayout_item_rightMargin, 0); topMargin = (int) typedArray.getDimension(R.styleable.FlowTagLayout_item_topMargin, 0); bottomMargin = (int) typedArray.getDimension(R.styleable.FlowTagLayout_item_bottomMargin, 0); leftPadding = (int) typedArray.getDimension(R.styleable.FlowTagLayout_item_leftPadding, 0); rightPadding = (int) typedArray.getDimension(R.styleable.FlowTagLayout_item_rightPadding, 0); topPadding = (int) typedArray.getDimension(R.styleable.FlowTagLayout_item_topPadding, 0); bottomPadding = (int) typedArray.getDimension(R.styleable.FlowTagLayout_item_bottomPadding, 0); background = typedArray.getResourceId(R.styleable.FlowTagLayout_item_background, -1); textColor = typedArray.getColor(R.styleable.FlowTagLayout_item_textColor, defaultColor); textSize = typedArray.getDimension(R.styleable.FlowTagLayout_item_textSize, defaultTextSize); typedArray.recycle(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { Log.e("onMeasure", "----------------------onMeasure----------------------"); // 已用宽度 int widthUsed = getPaddingLeft(); // 已用高度 int heightUsed = getPaddingTop(); // 当前行高度 int lineHeight = 0; // 当前行宽度 int lineWidth = 0; // 本身的宽度 int parentWidth = 0; // 本身的高度 int parentHeight = 0; int specWidth = MeasureSpec.getSize(widthMeasureSpec); int specWidthMode = MeasureSpec.getMode(widthMeasureSpec); int specHeight = MeasureSpec.getSize(heightMeasureSpec); int specHeightMode = MeasureSpec.getMode(heightMeasureSpec); int childCount = getChildCount(); if (childrenBounds == null) { childrenBounds = new Rect[childCount]; } else if (childrenBounds.length < childCount) { childrenBounds = Arrays.copyOf(childrenBounds, childCount); } // 遍历测量子view for (int i = 0; i < childCount; i++) { View child = getChildAt(i); // 测量子view measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0); MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); // 判断是否换行(1.不是非限制 2.已用宽度+当前添加的child宽度+左右的padding 是否大于 父view自身测量的宽度) int paddingRight = getPaddingRight(); Log.e("20000", paddingRight + ":padding"); Log.e("20000", lp.leftMargin + ":margin"); Log.e("20000", child.getMeasuredWidth() + ":width"); widthUsed = widthUsed + leftMargin; if (specWidthMode != MeasureSpec.UNSPECIFIED && widthUsed + child.getMeasuredWidth() + rightMargin + getPaddingRight() > specWidth) { parentWidth = specWidth; widthUsed = getPaddingLeft() + leftMargin; // 已用高度 = 之前已用高度 + 当前行的高度 heightUsed = heightUsed + lineHeight; measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0); measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0); } Rect childBounds = childrenBounds[i]; if (childBounds == null) { childBounds = childrenBounds[i] = new Rect(); } lineHeight = child.getMeasuredHeight() + topMargin + bottomMargin; // 保存child的位置 childBounds.set(widthUsed, heightUsed + topMargin, widthUsed + child.getMeasuredWidth(), heightUsed + lineHeight - bottomMargin); // 当前行已用的宽度 widthUsed = widthUsed + child.getMeasuredWidth() + rightMargin; } // 因为换行parentWidth会被赋值,所以需要对比是否换行过赋值后的parentWidth parentWidth = Math.max(parentWidth, widthUsed + getPaddingRight()); // 父view的高度 = 已用高度 + 当前行高度 + padding parentHeight = heightUsed + lineHeight + getPaddingBottom(); setMeasuredDimension(resolveSizeAndState(parentWidth, widthMeasureSpec, 0), resolveSizeAndState(parentHeight, heightMeasureSpec, 0)); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { for (int i = 0; i < getChildCount(); i++) { View view = getChildAt(i); Rect childRect = childrenBounds[i]; view.layout(childRect.left, childRect.top, childRect.right, childRect.bottom); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); } /** * 必须重写这个方法,不然measure的时候child.getLayoutParams()的margin是为0的 * * @param attrs * @return */ @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); } @Override protected LayoutParams generateDefaultLayoutParams() { return new MarginLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); } /** * 添加tags列表 * * @param watchableVideos */ public void addTags(ArrayList watchableVideos) { Log.e("调试方法","--------addTags"+watchableVideos.toString()); if (tagWatchableVideos == null) { tagWatchableVideos = new ArrayList<>(); } else { tagWatchableVideos.clear(); }// tagWatchableVideos.addAll(watchableVideos); tagWatchableVideos = watchableVideos; setDevid(tagWatchableVideos.size()); loadTagView(); } /** * 添加控件数量 * * @param num */ public void addTags(int num) { Log.e("视频","addTags(int num)"); setDevid(num); for (int i = 0; i < num; i++) { setTagContent(i); } } /** * 初始化tags */ private void setDevid(int num) { switch (num) { case 0: case 1: devd_w = 1; devd_h = 1; break; case 2: devd_w = 2; devd_h = 1; break; case 3: devd_w = 2; devd_h = 2; break; case 4: devd_w = 2; devd_h = 2; break; case 5: devd_w = 3; devd_h = 2; break; case 6: devd_w = 3; devd_h = 2; break; case 7: devd_w = 4; devd_h = 2; break; case 8: devd_w = 4; devd_h = 2; break; case 9: devd_w = 3; devd_h = 3; break; default: devd_w = 2; devd_h = 2; break; } } /** * 初始化tags */ private void loadTagView() { removeAllViews(); Log.e("调试方法","--------loadTagView"); for (int i = 0; i < tagWatchableVideos.size(); i++) { setTagContent(i); } } /** * 添加到尾部 * * @param label */ public void addTag(UsrVideoId label) { Log.e("调试方法","--------addTaglabel"); if (tagWatchableVideos == null) { tagWatchableVideos = new ArrayList<>(); } tagWatchableVideos.add(label); setDevid(tagWatchableVideos.size()); setTagContent(tagWatchableVideos.size() - 1); } /** * 添加到尾部 * * @param videolist */ public void addTag( ArrayList videolist,int pos) { Log.e("视频","周到这李addtag"); WatchVideos.add(videolist.get(pos)); setDevid(WatchVideos.size()); setTagContent(WatchVideos.size() - 1);// int childCount = getChildCount();// WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);// int screenWidth = wm.getDefaultDisplay().getWidth();// int screenHeight = wm.getDefaultDisplay().getHeight();//// // 遍历测量子view// for (int i = 0; i < childCount; i++) {// View child = getChildAt(i);// VideoView videoView = child.findViewById(R.id.item_videoview);//// LinearLayout.LayoutParams Params = (LinearLayout.LayoutParams) videoView.getLayoutParams();// Params.height = (int) screenHeight / devd_h;// Params.width = (int) screenWidth / devd_w;// videoView.setLayoutParams(Params);//// if (i<=WatchVideos.size()){// videoView.setUsrVideoId(WatchVideos.get(i));// }//// } } /** * 添加tag到index位置 * * @param index * @param label */ public void addTagOfIndex(int index, UsrVideoId label) { if (tagWatchableVideos == null) { tagWatchableVideos = new ArrayList<>(); } tagWatchableVideos.add(index, label); setTagOfIndex(index); } /** * 初始化item * * @param i */ @SuppressLint("NewApi") private void setTagContent(int i) { Log.e("调试方法","--------setTagContent"+i); LayoutInflater.from(context).inflate(R.layout.item_videoview, this); // 这里用是getChildAt(index)获取子view,不能直接拿上面inflate的view VideoView videoView = getChildAt(i).findViewById(R.id.item_videoview); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); lp.setMargins(leftPadding, topPadding, rightPadding, bottomPadding); lp.height = (int) screenHeight / devd_h; lp.width = (int) screenWidth / devd_w; videoView.setLayoutParams(lp); Log.e("调试方法","--------setTagContent"+tagWatchableVideos.get(i).toString()); videoView.setUsrVideoId(tagWatchableVideos.get(i));// textView.setText(tagList.get(i));// textView.setTextColor(textColor);// textView.setTextSize(Utils.pxToSp(textSize)); refreshTag(tagWatchableVideos.size()); final int finalI = i; if (background == -1) { getChildAt(i).setBackground(null); } else { getChildAt(i).setBackground(getResources().getDrawable(background)); } getChildAt(i).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (onTagClickListener != null) { onTagClickListener.tagClick(finalI); } } }); } /** * 添加到index位置,使用的是addView(view ,index),最后需要把点击事件重置 * * @param i */ @SuppressLint("NewApi") private void setTagOfIndex(int i) { View view = LayoutInflater.from(context).inflate(R.layout.item_tag, null, false); addView(view, i); // 这里用是getChildAt(index)获取子view,不能直接拿上面inflate的view// TextView textView = getChildAt(i).findViewById(R.id.item_text); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); lp.setMargins(leftPadding, topPadding, rightPadding, bottomPadding);// textView.setLayoutParams(lp);// textView.setText(tagList.get(i));// textView.setTextColor(textColor);// textView.setTextSize(Utils.pxToSp(textSize)); if (background == -1) { getChildAt(i).setBackground(null); } else { getChildAt(i).setBackground(getResources().getDrawable(background)); } for (int j = 0; j < getChildCount(); j++) { // 去掉点击事件 getChildAt(j).setOnClickListener(null); final int finalJ = j; // 重新绑定点击监听 getChildAt(j).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (onTagClickListener != null) { onTagClickListener.tagClick(finalJ); } } }); } } /** * 移除最后一个tag */ public void removeTag(int s) {// getChildAt(tagList.size() - 1).setOnClickListener(null);// removeViewAt(tagList.size() - 1);// tagList.remove(tagList.size() - 1); getChildAt(s).setOnClickListener(null); removeViewAt(s); tagWatchableVideos.remove(s); } /** * 更新布局 */ public void refreshTag(int num) { Log.e("调试方法","refreshTag----->"+num); setDevid(num);// this.devd = devd; int childCount = getChildCount(); int randomnum = (int) (Math.random() * 10) + 1;//0到10随机数 // 遍历测量子view for (int i = 0; i < childCount; i++) { View child = getChildAt(i); VideoView videoView = child.findViewById(R.id.item_videoview); LinearLayout.LayoutParams Params = (LinearLayout.LayoutParams) videoView.getLayoutParams(); Params.height = (int) screenHeight / devd_h; Params.width = (int) screenWidth / devd_w; videoView.setLayoutParams(Params); } } /** * 更新布局 */ public void refreshTag( ArrayList watchableVideos ) { setDevid(watchableVideos.size());// this.devd = devd; int childCount = getChildCount(); // 遍历测量子view for (int i = 0; i < childCount; i++) { View child = getChildAt(i); VideoView videoView = child.findViewById(R.id.item_videoview); LinearLayout.LayoutParams Params = (LinearLayout.LayoutParams) videoView.getLayoutParams(); Params.height = (int) screenHeight / devd_h; Params.width = (int) screenWidth / devd_w; videoView.setLayoutParams(Params); if (i<=watchableVideos.size()){ videoView.setUsrVideoId(watchableVideos.get(i)); } } } /** * 移除index位置的tag * * @param usrVideoId */ public void removeTagOfIndex(UsrVideoId usrVideoId) { int index = 0; for (int i = 0;i= Build.VERSION_CODES.JELLY_BEAN_MR1) {//获取真实高度 包括导航栏 状态栏 WindowManager wmManager=(WindowManager) context.getSystemService(Context.WINDOW_SERVICE); wmManager.getDefaultDisplay().getRealMetrics(dm); screenHeight = dm.heightPixels; } }}
//新增flowTagLayout.addTag(new_otherWatchVideos.get(i));
//移除
flowTagLayout.removeTagOfIndex(old_otherWatchVideos.get(j));
//删除所有
flowTagLayout.removeAllViews();
demo
https://download.csdn.net/download/csdndouniwan/11081839
更多相关文章
- Android文件递归遍历
- 2010.12.19——— android 设置组件的高度
- Android:漫画APP开发笔记之ListView中图片按屏幕宽度缩放
- Android中获取屏幕相关信息(屏幕大小,状态栏、标题栏高度)
- Android 获取状态栏的高度
- android 中超出屏幕宽度的字符 省略号显示
- Android 使用 TableLayout 布局拉伸宽度