当前位置: 移动技术网 > 移动技术>移动开发>Android > android随机生成圆形云标签效果

android随机生成圆形云标签效果

2019年07月24日  | 移动技术网移动技术  | 我要评论
这个适合用于选择 用户的一些兴趣标签,个性名片等。 package com.dyl.cloudtags; import java.util.ar

这个适合用于选择 用户的一些兴趣标签,个性名片等。

package com.dyl.cloudtags; 
 
import java.util.arraylist; 
import java.util.arrays; 
import java.util.random; 
 
import android.app.activity; 
import android.content.sharedpreferences; 
import android.os.bundle; 
import android.view.view; 
import android.view.view.onclicklistener; 
import android.widget.edittext; 
import android.widget.imageview; 
import android.widget.textview; 
import android.widget.toast; 
 
public class mainactivity extends activity { 
 
 private keywordsflow keywordsflow; 
 private string[] keywords; 
 public static final string search_history = "search_history"; 
 private arraylist<searchdatapojo> searchitem; 
 private string longhistory; 
 private sharedpreferences sp; 
 private arraylist<string> history; 
 private edittext world_shopping_search_input; 
 private textview world_city_refresh, clear_history; 
 private imageview tosearch; 
 
 @override 
 protected void oncreate(bundle savedinstancestate) { 
  super.oncreate(savedinstancestate); 
  setcontentview(r.layout.activity_main); 
  initview(); 
  initsearchhistory(); 
  refreshtags(); 
 } 
 
 private void initview() { 
  world_shopping_search_input = (edittext) findviewbyid(r.id.world_shopping_search_input); 
  keywordsflow = (keywordsflow) findviewbyid(r.id.keywordsflow); 
 
  world_city_refresh = (textview) findviewbyid(r.id.world_city_refresh); 
  world_city_refresh.setonclicklistener(new onclicklistener() { 
 
   @override 
   public void onclick(view arg0) { 
    refreshtags(); 
   } 
  }); 
 
  clear_history = (textview) findviewbyid(r.id.clear_history); 
  clear_history.setonclicklistener(new onclicklistener() { 
 
   @override 
   public void onclick(view arg0) { 
    clearsearchhistory(); 
   } 
  }); 
 
  tosearch = (imageview) findviewbyid(r.id.tosearch); 
  tosearch.setonclicklistener(new onclicklistener() { 
 
   @override 
   public void onclick(view arg0) { 
    savesearchhistory(); 
    refreshtags(); 
   } 
  }); 
 } 
 
 private void refreshtags() { 
  initsearchhistory(); 
  keywordsflow.setduration(800l); 
  keywordsflow.setonitemclicklistener(new onclicklistener() { 
 
   @override 
   public void onclick(view v) { 
    string keyword = ((textview) v).gettext().tostring();// 获得点击的标签 
    world_shopping_search_input.settext(keyword); 
   } 
  }); 
  // 添加 
  feedkeywordsflow(keywordsflow, keywords); 
  keywordsflow.go2show(keywordsflow.animation_in); 
 } 
 
 private static void feedkeywordsflow(keywordsflow keywordsflow, string[] arr) { 
  random random = new random(); 
  for (int i = 0; i < keywordsflow.max; i++) { 
   int ran = random.nextint(arr.length); 
   string tmp = arr[ran]; 
   keywordsflow.feedkeyword(tmp); 
  } 
 } 
 
 /** 
  * 读取历史搜索记录 
  */ 
 private void initsearchhistory() { 
  sp = getsharedpreferences(mainactivity.search_history, 0); 
  longhistory = sp.getstring(mainactivity.search_history, ""); 
  if (!longhistory.equals("")) { 
   keywords = longhistory.split(","); 
   searchitem = new arraylist<searchdatapojo>(); 
   for (int i = 0; i < keywords.length; i++) { 
    searchitem.add(new searchdatapojo().setcontent(keywords[i])); 
   } 
  } else {// 如果sharedpreferences没有值得话,就显示默认的数据 
   keywords = new string[] { "口味虾", "牛蛙", "火锅", "真功夫", "料理", 
     "密室逃", "天成房", "波比艾" }; 
  } 
 } 
 
 /* 
  * 保存搜索记录 
  */ 
 private void savesearchhistory() { 
  string text = world_shopping_search_input.gettext().tostring().trim(); 
  toast.maketext(this, text, toast.length_long).show(); 
  if (!text.equals("") && text != null) { 
   if (text.length() < 1) { 
    return; 
   } 
   sp = getsharedpreferences(search_history, 0); 
   string longhistory = sp.getstring(search_history, ""); 
   string[] tmphistory = longhistory.split(","); 
   history = new arraylist<string>(arrays.aslist(tmphistory)); 
   if (history.size() > 0) { 
    int i; 
    for (i = 0; i < history.size(); i++) { 
     if (text.equals(history.get(i))) { 
      history.remove(i); 
      break; 
     } 
    } 
    history.add(0, text); 
   } 
   if (history.size() > 0) { 
    stringbuilder sb = new stringbuilder(); 
    for (int i = 0; i < history.size(); i++) { 
     sb.append(history.get(i) + ","); 
    } 
    sp.edit().putstring(search_history, sb.tostring()).commit(); 
   } else { 
    sp.edit().putstring(search_history, text + ",").commit(); 
   } 
   clear_history.setvisibility(view.visible); 
  } 
 } 
 
 // 清除历史数据 
 private void clearsearchhistory() { 
  searchitem.removeall(searchitem); 
  sp.edit().clear().commit(); 
  toast.maketext(this, "清除历史记录", toast.length_long).show(); 
 } 
} 

用于将控件 设置为圆形 的自定义textview

package com.dyl.cloudtags; 
 
import android.content.context; 
import android.graphics.canvas; 
import android.graphics.color; 
import android.graphics.paint; 
import android.graphics.paintflagsdrawfilter; 
import android.util.attributeset; 
import android.widget.textview; 
 
public class circleview extends textview { 
 
 private paint mbgpaint = new paint(); 
 
 paintflagsdrawfilter pfd = new paintflagsdrawfilter(0, paint.anti_alias_flag|paint.filter_bitmap_flag); 
 
 public circleview(context context, attributeset attrs, int defstyle) { 
  super(context, attrs, defstyle); 
  // todo auto-generated constructor stub 
 } 
 
 public circleview(context context, attributeset attrs) { 
  super(context, attrs); 
  // todo auto-generated constructor stub 
  mbgpaint.setcolor(color.white); 
  mbgpaint.setantialias(true); 
 } 
 
 public circleview(context context) { 
  super(context); 
  // todo auto-generated constructor stub 
  mbgpaint.setcolor(color.white); 
  mbgpaint.setantialias(true); 
 } 
 
 @override 
 protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { 
  // todo auto-generated method stub 
  super.onmeasure(widthmeasurespec, heightmeasurespec); 
  int measuredwidth = getmeasuredwidth(); 
  int measuredheight = getmeasuredheight(); 
  int max = math.max(measuredwidth, measuredheight); 
  setmeasureddimension(max, max); 
 } 
 
 @override 
 public void setbackgroundcolor(int color) { 
  // todo auto-generated method stub 
  mbgpaint.setcolor(color); 
 } 
 
 /** 
  * 设置通知个数显示 
  * @param text 
  */ 
 public void setnotifitext(int text){ 
  //  if(text>99){ 
  //   string string = 99+"+"; 
  //   settext(string); 
  //   return; 
  //  } 
  settext(text+""); 
 } 
 
 @override 
 public void draw(canvas canvas) { 
  // todo auto-generated method stub 
  canvas.setdrawfilter(pfd); 
  canvas.drawcircle(getwidth()/2, getheight()/2, math.max(getwidth(), getheight())/2, mbgpaint); 
  super.draw(canvas); 
 } 
} 

自定义布局 用于动态生成多个 控件  核心类

package com.dyl.cloudtags; 
 
import java.util.linkedlist; 
import java.util.random; 
import java.util.vector; 
import android.content.context; 
import android.graphics.color; 
import android.graphics.paint; 
import android.graphics.drawable.gradientdrawable; 
import android.util.attributeset; 
import android.view.gravity; 
import android.view.layoutinflater; 
import android.view.view; 
import android.view.viewtreeobserver.ongloballayoutlistener; 
import android.view.animation.alphaanimation; 
import android.view.animation.animation; 
import android.view.animation.animation.animationlistener; 
import android.view.animation.animationset; 
import android.view.animation.animationutils; 
import android.view.animation.interpolator; 
import android.view.animation.scaleanimation; 
import android.view.animation.translateanimation; 
import android.widget.framelayout; 
 
public class keywordsflow extends framelayout implements ongloballayoutlistener { 
 
 public static final int idx_x = 0; 
 public static final int idx_y = 1; 
 public static final int idx_txt_length = 2; 
 public static final int idx_dis_y = 3; 
 /** 由外至内的动画。 */ 
 public static final int animation_in = 1; 
 /** 由内至外的动画。 */ 
 public static final int animation_out = 2; 
 /** 位移动画类型:从外围移动到坐标点。 */ 
 public static final int outside_to_location = 1; 
 /** 位移动画类型:从坐标点移动到外围。 */ 
 public static final int location_to_outside = 2; 
 /** 位移动画类型:从中心点移动到坐标点。 */ 
 public static final int center_to_location = 3; 
 /** 位移动画类型:从坐标点移动到中心点。 */ 
 public static final int location_to_center = 4; 
 public static final long anim_duration = 800l; 
 public static final int max = 12; 
 public static final int text_size_max = 20; 
 public static final int text_size_min = 10; 
 private onclicklistener itemclicklistener; 
 private static interpolator interpolator; 
 private static alphaanimation animalpha2opaque; 
 private static alphaanimation animalpha2transparent; 
 private static scaleanimation animscalelarge2normal, animscalenormal2large, 
   animscalezero2normal, animscalenormal2zero; 
 /** 存储显示的关键字。 */ 
 private vector<string> veckeywords; 
 private int width, height; 
 /** 
  * go2show()中被赋值为true,标识开发人员触发其开始动画显示。<br/> 
  * 本标识的作用是防止在填充keywrods未完成的过程中获取到width和height后提前启动动画。<br/> 
  * 在show()方法中其被赋值为false。<br/> 
  * 真正能够动画显示的另一必要条件:width 和 height不为0。<br/> 
  */ 
 private boolean enableshow; 
 private random random; 
 
 private int txtanimintype, txtanimouttype; 
 /** 最近一次启动动画显示的时间。 */ 
 private long laststartanimationtime; 
 /** 动画运行时间。 */ 
 private long animduration; 
 private context context; 
 public keywordsflow(context context) { 
  super(context); 
  init(); 
 } 
 
 public keywordsflow(context context, attributeset attrs) { 
  super(context, attrs); 
  init(); 
 } 
 
 public keywordsflow(context context, attributeset attrs, int defstyle) { 
  super(context, attrs, defstyle); 
  init(); 
 } 
 
 private void init() { 
  laststartanimationtime = 0l; 
  animduration = anim_duration; 
  random = new random(); 
  veckeywords = new vector<string>(max); 
  getviewtreeobserver().addongloballayoutlistener(this); 
  interpolator = animationutils.loadinterpolator(getcontext(), 
    android.r.anim.decelerate_interpolator); 
  animalpha2opaque = new alphaanimation(0.0f, 1.0f); 
  animalpha2transparent = new alphaanimation(1.0f, 0.0f); 
  animscalelarge2normal = new scaleanimation(2, 1, 2, 1); 
  animscalenormal2large = new scaleanimation(1, 2, 1, 2); 
  animscalezero2normal = new scaleanimation(0, 1, 0, 1); 
  animscalenormal2zero = new scaleanimation(1, 0, 1, 0); 
 } 
 
 public long getduration() { 
  return animduration; 
 } 
 
 public void setduration(long duration) { 
  animduration = duration; 
 } 
 
 public boolean feedkeyword(string keyword) { 
  boolean result = false; 
  if (veckeywords.size() < max) { 
   result = veckeywords.add(keyword); 
  } 
  return result; 
 } 
 
 /** 
  * 开始动画显示。<br/> 
  * 之前已经存在的textview将会显示退出动画。<br/> 
  * 
  * @return 正常显示动画返回true;反之为false。返回false原因如下:<br/> 
  *   1.时间上不允许,受laststartanimationtime的制约;<br/> 
  *   2.未获取到width和height的值。<br/> 
  */ 
 public boolean go2show(int animtype) { 
  if (system.currenttimemillis() - laststartanimationtime > animduration) { 
   enableshow = true; 
   if (animtype == animation_in) { 
    txtanimintype = outside_to_location; 
    txtanimouttype = location_to_center; 
   } else if (animtype == animation_out) { 
    txtanimintype = center_to_location; 
    txtanimouttype = location_to_outside; 
   } 
   disapper(); 
   boolean result = show(); 
   return result; 
  } 
  return false; 
 } 
 
 private void disapper() { 
  int size = getchildcount(); 
  for (int i = size - 1; i >= 0; i--) { 
   final circleview txv = (circleview) getchildat(i); 
   if (txv.getvisibility() == view.gone) { 
    removeview(txv); 
    continue; 
   } 
   framelayout.layoutparams layparams = (layoutparams) txv 
     .getlayoutparams(); 
   int[] xy = new int[] { layparams.leftmargin, layparams.topmargin, 
     txv.getwidth() }; 
   animationset animset = getanimationset(xy, (width >> 1), 
     (height >> 1), txtanimouttype); 
   txv.startanimation(animset); 
   animset.setanimationlistener(new animationlistener() { 
    public void onanimationstart(animation animation) { 
    } 
 
    public void onanimationrepeat(animation animation) { 
    } 
 
    public void onanimationend(animation animation) { 
     txv.setonclicklistener(null); 
     txv.setclickable(false); 
     txv.setvisibility(view.gone); 
    } 
   }); 
  } 
 } 
 
 private boolean show() { 
  if (width > 0 && height > 0 && veckeywords != null 
    && veckeywords.size() > 0 && enableshow) { 
   enableshow = false; 
   laststartanimationtime = system.currenttimemillis(); 
   int xcenter = width >> 1, ycenter = height >> 1; 
   int size = veckeywords.size(); 
   int xitem = width / size, yitem = height / size; 
   linkedlist<integer> listx = new linkedlist<integer>(), listy = new linkedlist<integer>(); 
   for (int i = 0; i < size; i++) { 
    // 准备随机候选数,分别对应x/y轴位置 
    listx.add(i * xitem); 
    listy.add(i * yitem + (yitem >> 2)); 
   } 
   linkedlist<circleview> listtxttop = new linkedlist<circleview>(); 
   linkedlist<circleview> listtxtbottom = new linkedlist<circleview>(); 
   for (int i = 0; i < size; i++) { 
    string keyword = veckeywords.get(i); 
    // 随机位置,糙值 
    int xy[] = randomxy(random, listx, listy, xitem); 
    // 实例化textview 
    final circleview txv = new circleview(getcontext()); 
    txv.setbackgroundresource(r.drawable.text_view_border); 
    txv.setgravity(gravity.center); 
    txv.setonclicklistener(itemclicklistener); 
    txv.settext(keyword); 
    txv.settextcolor(color.white); 
    txv.setpadding(8, 6, 8, 6); 
    txv.setsingleline(true); 
    int r = random.nextint(256); 
    int g= random.nextint(256); 
    int b = random.nextint(256); 
    int mcolor = color.rgb(r, g, b); 
    gradientdrawable mygrad = (gradientdrawable)txv.getbackground(); 
    mygrad.setcolor(mcolor); 
//    txv.setbackgroundcolor(mcolor); 
    // 获取文本长度 
    paint paint = txv.getpaint(); 
    int strwidth = (int) math.ceil(paint.measuretext(keyword)); 
    xy[idx_txt_length] = strwidth; 
    // 第一次修正:修正x坐标 
    if (xy[idx_x] + strwidth > width - (xitem >> 1)) { 
     int basex = width - strwidth; 
     // 减少文本右边缘一样的概率 
     xy[idx_x] = basex - xitem + random.nextint(xitem >> 1); 
    } else if (xy[idx_x] == 0) { 
     // 减少文本左边缘一样的概率 
     xy[idx_x] = math.max(random.nextint(xitem), xitem / 3); 
    } 
    xy[idx_dis_y] = math.abs(xy[idx_y] - ycenter); 
    txv.settag(xy); 
    if (xy[idx_y] > ycenter) { 
     listtxtbottom.add(txv); 
    } else { 
     listtxttop.add(txv); 
    } 
   } 
   attach2screen(listtxttop, xcenter, ycenter, yitem); 
   attach2screen(listtxtbottom, xcenter, ycenter, yitem); 
   return true; 
  } 
  return false; 
 } 
 
 /** 修正textview的y坐标将将其添加到容器上。 */ 
 private void attach2screen(linkedlist<circleview> listtxt, int xcenter, 
   int ycenter, int yitem) { 
  int size = listtxt.size(); 
  sortxylist(listtxt, size); 
  for (int i = 0; i < size; i++) { 
   circleview txv = listtxt.get(i); 
   int[] ixy = (int[]) txv.gettag(); 
   // 第二次修正:修正y坐标 
   int ydistance = ixy[idx_y] - ycenter; 
   // 对于最靠近中心点的,其值不会大于yitem<br/> 
   // 对于可以一路下降到中心点的,则该值也是其应调整的大小<br/> 
   int ymove = math.abs(ydistance); 
   inner: for (int k = i - 1; k >= 0; k--) { 
    int[] kxy = (int[]) listtxt.get(k).gettag(); 
    int startx = kxy[idx_x]; 
    int endx = startx + kxy[idx_txt_length]; 
    // y轴以中心点为分隔线,在同一侧 
    if (ydistance * (kxy[idx_y] - ycenter) > 0) { 
     if (isxmixed(startx, endx, ixy[idx_x], ixy[idx_x] 
       + ixy[idx_txt_length])) { 
      int tmpmove = math.abs(ixy[idx_y] - kxy[idx_y]); 
      if (tmpmove > yitem) { 
       ymove = tmpmove; 
      } else if (ymove > 0) { 
       // 取消默认值。 
       ymove = 0; 
      } 
      break inner; 
     } 
    } 
   } 
   if (ymove > yitem) { 
    int maxmove = ymove - yitem; 
    int randommove = random.nextint(maxmove); 
    int realmove = math.max(randommove, maxmove >> 1) * ydistance 
      / math.abs(ydistance); 
    ixy[idx_y] = ixy[idx_y] - realmove; 
    ixy[idx_dis_y] = math.abs(ixy[idx_y] - ycenter); 
    // 已经调整过前i个需要再次排序 
    sortxylist(listtxt, i + 1); 
   } 
   framelayout.layoutparams layparams = new framelayout.layoutparams( 
     framelayout.layoutparams.wrap_content, 
     framelayout.layoutparams.wrap_content); 
   layparams.gravity = gravity.left | gravity.top; 
   layparams.leftmargin = ixy[idx_x]; 
   layparams.topmargin = ixy[idx_y]; 
   addview(txv, layparams); 
   // 动画 
   animationset animset = getanimationset(ixy, xcenter, ycenter, 
     txtanimintype); 
   txv.startanimation(animset); 
  } 
 } 
 
 public animationset getanimationset(int[] xy, int xcenter, int ycenter, 
   int type) { 
  animationset animset = new animationset(true); 
  animset.setinterpolator(interpolator); 
  if (type == outside_to_location) { 
   animset.addanimation(animalpha2opaque); 
   animset.addanimation(animscalelarge2normal); 
   translateanimation translate = new translateanimation((xy[idx_x] 
     + (xy[idx_txt_length] >> 1) - xcenter) << 1, 0, 
     (xy[idx_y] - ycenter) << 1, 0); 
   animset.addanimation(translate); 
  } else if (type == location_to_outside) { 
   animset.addanimation(animalpha2transparent); 
   animset.addanimation(animscalenormal2large); 
   translateanimation translate = new translateanimation(0, (xy[idx_x] 
     + (xy[idx_txt_length] >> 1) - xcenter) << 1, 0, 
     (xy[idx_y] - ycenter) << 1); 
   animset.addanimation(translate); 
  } else if (type == location_to_center) { 
   animset.addanimation(animalpha2transparent); 
   animset.addanimation(animscalenormal2zero); 
   translateanimation translate = new translateanimation(0, 
     (-xy[idx_x] + xcenter), 0, (-xy[idx_y] + ycenter)); 
   animset.addanimation(translate); 
  } else if (type == center_to_location) { 
   animset.addanimation(animalpha2opaque); 
   animset.addanimation(animscalezero2normal); 
   translateanimation translate = new translateanimation( 
     (-xy[idx_x] + xcenter), 0, (-xy[idx_y] + ycenter), 0); 
   animset.addanimation(translate); 
  } 
  animset.setduration(animduration); 
  return animset; 
 } 
 
 /** 
  * 根据与中心点的距离由近到远进行冒泡排序。 
  * 
  * @param endidx 
  *   起始位置。 
  * @param txtarr 
  *   待排序的数组。 
  * 
  */ 
 private void sortxylist(linkedlist<circleview> listtxt, int endidx) { 
  for (int i = 0; i < endidx; i++) { 
   for (int k = i + 1; k < endidx; k++) { 
    if (((int[]) listtxt.get(k).gettag())[idx_dis_y] < ((int[]) listtxt 
      .get(i).gettag())[idx_dis_y]) { 
     circleview itmp = listtxt.get(i); 
     circleview ktmp = listtxt.get(k); 
     listtxt.set(i, ktmp); 
     listtxt.set(k, itmp); 
    } 
   } 
  } 
 } 
 
 /** a线段与b线段所代表的直线在x轴映射上是否有交集。 */ 
 private boolean isxmixed(int starta, int enda, int startb, int endb) { 
  boolean result = false; 
  if (startb >= starta && startb <= enda) { 
   result = true; 
  } else if (endb >= starta && endb <= enda) { 
   result = true; 
  } else if (starta >= startb && starta <= endb) { 
   result = true; 
  } else if (enda >= startb && enda <= endb) { 
   result = true; 
  } 
  return result; 
 } 
 
 //得到随机坐标 
 private int[] randomxy(random ran, linkedlist<integer> listx, 
   linkedlist<integer> listy, int xitem) { 
  int[] arr = new int[4]; 
  arr[idx_x] = listx.remove(ran.nextint(listx.size())); 
  arr[idx_y] = listy.remove(ran.nextint(listy.size())); 
  return arr; 
 } 
 
 public void ongloballayout() { 
  int tmpw = getwidth(); 
  int tmph = getheight(); 
  if (width != tmpw || height != tmph) { 
   width = tmpw; 
   height = tmph; 
   show(); 
  } 
 } 
 
 public vector<string> getkeywords() { 
  return veckeywords; 
 } 
 
 public void rubkeywords() { 
  veckeywords.clear(); 
 } 
 
 /** 直接清除所有的textview。在清除之前不会显示动画。 */ 
 public void ruballviews() { 
  removeallviews(); 
 } 
 
 public void setonitemclicklistener(onclicklistener listener) { 
  itemclicklistener = listener; 
 } 
} 
package com.dyl.cloudtags; 
 
 
/** 
 * 搜索记录 
 * @author dengyalan 
 * 
 */ 
public class searchdatapojo { 
 
 private string content = ""; 
 
 public string getcontent() { 
  return content; 
 } 
 
 public searchdatapojo setcontent(string content) { 
  this.content = content; 
  return this; 
 } 
} 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网