ホームページ  >  記事  >  Java  >  Android カスタム ViewGroup はラベル フローティング効果を実装します

Android カスタム ViewGroup はラベル フローティング効果を実装します

高洛峰
高洛峰オリジナル
2017-01-16 17:04:471651ブラウズ

以前、マスター ホンヤンによるカスタマイズされた View の記事をいくつか勉強していて、フローティング ラベルを実装するためのカスタム ViewGroup を見て、彼のアイデアを予備的に検討し、自分のアイデアを組み合わせてフローティング ラベル用の独自のカスタム ViewGroup を完成させました。現在の実装では、ラベルを動的に追加してクリック可能にすることができます。レンダリングは次のとおりです。

Android カスタム 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 サイトに注目してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。