以前、マスター ホンヤンによるカスタマイズされた View の記事をいくつか勉強していて、フローティング ラベルを実装するためのカスタム ViewGroup を見て、彼のアイデアを予備的に検討し、自分のアイデアを組み合わせてフローティング ラベル用の独自のカスタム ViewGroup を完成させました。現在の実装では、ラベルを動的に追加してクリック可能にすることができます。レンダリングは次のとおりです。
1. アイデア
まず、onMeasure メソッドで ViewGroup の幅と高さを測定します。ここでは、wrap_content に設定されているカスタマイズされた ViewGroup のサイズを測定する方法に焦点を当てます。カスタマイズされた ViewGroup が Wrap_content に設定されている場合、最初にサブビュー自体を測定させる必要があります。サブビューが測定された後、サブビューの getMeasuredWidth メソッドと getMeasureHeight メソッドを通じてサブビューの幅と高さを取得できます。 -ビュー。サブビューを測定する前に、サブビューが追加される場合に現在の行がサブビューを収容できるかどうかを判断する必要があります。そうでない場合は、新しい行を開いて現在の行の最大高さを記録する必要があります。 。
onLayout メソッドの中心的な役割は、各サブビューを配置することです。つまり、ViewGroup 内の各サブビューのボックス モデル上の 2 つの点 (左上隅と右下隅) を見つけることです。つまり、点(l,t)と点(r,b)の2点が決まり、SubViewの位置も決まります。
2. 実装
基本的なアイデアを理解したら、それを実装してみます。
Customized ViewGroup:
/** * 流式标签(动态的,根据传入的数据动态添加标签) */ public class DynamicTagFlowLayout extends ViewGroup { private List<String> mTags = new ArrayList<String>(); public DynamicTagFlowLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public DynamicTagFlowLayout(Context context, AttributeSet attrs) { super(context, attrs); } public DynamicTagFlowLayout(Context context) { super(context); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); //当前ViewGroup的总高度 int totalHeight= 0; //所有行中的最大宽度 int maxLineWidth = 0; //当前行的最大高度 int lineMaxHeight = 0; //当前行的总宽度 int currentLineWidth = 0; //每个childView所占用的宽度 int childViewWidthSpace = 0; //每个childView所占用的高度 int childViewHeightSpace = 0; int count = getChildCount(); MarginLayoutParams layoutParams; for(int i = 0; i < count; i++){ View child = getChildAt(i); if(child.getVisibility() != View.GONE){//只有当这个View能够显示的时候才去测量 //测量每个子View,以获取子View的宽和高 measureChild(child, widthMeasureSpec, heightMeasureSpec); layoutParams = (MarginLayoutParams) child.getLayoutParams(); childViewWidthSpace = child.getMeasuredWidth() + layoutParams.leftMargin + layoutParams.rightMargin; childViewHeightSpace = child.getMeasuredHeight() + layoutParams.topMargin + layoutParams.bottomMargin; if(currentLineWidth + childViewWidthSpace > widthSize){//表示如果当前行再加上现在这个子View,就会超出总的规定宽度,需要另起一行 totalHeight += lineMaxHeight; if(maxLineWidth < currentLineWidth){//如果行的最长宽度发生了变化,更新保存的最长宽度 maxLineWidth = currentLineWidth; } currentLineWidth = childViewWidthSpace;//另起一行后,需要重置当前行宽 lineMaxHeight = childViewHeightSpace; }else{//表示当前行可以继续添加子元素 currentLineWidth += childViewWidthSpace; if(lineMaxHeight < childViewHeightSpace){ lineMaxHeight = childViewHeightSpace; } } } } setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : maxLineWidth, heightMode == MeasureSpec.EXACTLY ? heightSize : totalHeight); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { //当前是第几行 int currentLine = 1; //存放每一行的最大高度 List<Integer> lineMaxHeightList = new ArrayList<Integer>(); //每个childView所占用的宽度 int childViewWidthSpace = 0; //每个childView所占用的高度 int childViewHeightSpace = 0; //当前行的最大高度 int lineMaxHeight = 0; //当前行的总宽度 int currentLineWidth = 0; int count = getChildCount(); MarginLayoutParams layoutParams; for(int i = 0; i < count; i++){ int cl= 0, ct = 0, cr = 0, cb = 0; View child = getChildAt(i); if(child.getVisibility() != View.GONE){//只有当这个View能够显示的时候才去测量 layoutParams = (MarginLayoutParams) child.getLayoutParams(); childViewWidthSpace = child.getMeasuredWidth() + layoutParams.leftMargin + layoutParams.rightMargin; childViewHeightSpace = child.getMeasuredHeight() + layoutParams.topMargin + layoutParams.bottomMargin; System.out.println("getWidth()---->"+getWidth()); if(currentLineWidth + childViewWidthSpace > getWidth()){//表示如果当前行再加上现在这个子View,就会超出总的规定宽度,需要另起一行 lineMaxHeightList.add(lineMaxHeight);//此时先将这一行的最大高度加入到集合中 //新的一行,重置一些参数 currentLine++; currentLineWidth = childViewWidthSpace; lineMaxHeight = childViewHeightSpace; cl = layoutParams.leftMargin; if(currentLine > 1){ for(int j = 0; j < currentLine - 1; j++){ ct += lineMaxHeightList.get(j); } ct += layoutParams.topMargin ; }else{ ct = layoutParams.topMargin; } }else{//表示当前行可以继续添加子元素 cl = currentLineWidth + layoutParams.leftMargin; if(currentLine > 1){ for(int j = 0; j < currentLine - 1; j++){ ct += lineMaxHeightList.get(j); } ct += layoutParams.topMargin; }else{ ct = layoutParams.topMargin; } currentLineWidth += childViewWidthSpace; if(lineMaxHeight < childViewHeightSpace){ lineMaxHeight = childViewHeightSpace; } } cr = cl + child.getMeasuredWidth(); cb = ct + child.getMeasuredHeight(); child.layout(cl, ct, cr, cb); } } } @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); } public void setTags(List<String> tags){ if(tags!= null){ mTags.clear(); mTags.addAll(tags); for(int i = 0; i < mTags.size(); i++){ TextView tv = new TextView(getContext()); MarginLayoutParams lp = new MarginLayoutParams(MarginLayoutParams.WRAP_CONTENT, MarginLayoutParams.WRAP_CONTENT); lp.setMargins(15, 15, 15, 15); // lp.width = MarginLayoutParams.WRAP_CONTENT; // lp.height = MarginLayoutParams.WRAP_CONTENT; tv.setLayoutParams(lp); tv.setBackgroundResource(R.drawable.tv_bg); /* * setPadding一定要在setBackgroundResource后面使用才有效!!! * http://stackoverflow.com/questions/18327498/setting-padding-for-textview-not-working */ tv.setPadding(15, 15, 15, 15); tv.setTextColor(Color.WHITE); tv.setText(mTags.get(i)); tv.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if(listener != null){ listener.onClick(v); } } }); addView(tv); } requestLayout(); } } private OnTagItemClickListener listener; public interface OnTagItemClickListener{ public void onClick(View v); } public void setOnTagItemClickListener(OnTagItemClickListener l){ listener = l; } }
MainActivity:
public class MainActivity extends Activity { private DynamicTagFlowLayout dynamicTagFlowLayout; List<String> tags = new ArrayList<String>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_dynamic_tagflowlayout); dynamicTagFlowLayout = (DynamicTagFlowLayout) findViewById(R.id.dynamic_tag); dynamicTagFlowLayout.setOnTagItemClickListener(new OnTagItemClickListener() { @Override public void onClick(View v) { TextView tv = (TextView) v; Toast.makeText(MainActivity.this, tv.getText().toString(), Toast.LENGTH_SHORT).show(); } }); initData(); dynamicTagFlowLayout.setTags(tags); } private void initData() { tags.add("阳哥你好!"); tags.add("Android开发"); tags.add("新闻热点"); tags.add("热水进宿舍啦!"); tags.add("I love you"); tags.add("成都妹子"); tags.add("新余妹子"); tags.add("仙女湖"); tags.add("创新工厂"); tags.add("孵化园"); tags.add("神州100发射"); tags.add("有毒疫苗"); tags.add("顶你阳哥阳哥"); tags.add("Hello World"); tags.add("闲逛的蚂蚁"); tags.add("闲逛的蚂蚁"); tags.add("闲逛的蚂蚁"); tags.add("闲逛的蚂蚁"); tags.add("闲逛的蚂蚁"); tags.add("闲逛的蚂蚁"); } }
以上がこの記事の内容です。皆さんの学習に役立つと思います。ぜひ PHP 中国語 Web サイトをサポートしてください。
ラベル フローティング効果を実装する Android カスタム ViewGroup に関連するその他の記事については、PHP 中国語 Web サイトに注目してください。