欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2023-12-04 17:42:34
这个适合用于选择 用户的一些兴趣标签,个性名片等。 package com.dyl.cloudtags; import java.util.ar...

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

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

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; 
 } 
} 

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