android 自定义LabelView实现各类小标签,重要功能已标注
转载请注明出处:王亟亟的大牛之路
一个自定义TextView可实现各种控件右上,左上等位置附带便签实现。
项目结构:
运行效果:
只需要一个类就可以完成以上实现
LabelView
public class LabelView extends TextView {private float _offsetx;private float _offsety;private float _anchorx;private float _anchory;private float _angel;private int _labelViewContainerID;private Animation _animation = new Animation() {protected void applyTransformation(float interpolatedTime, Transformation t) {Matrix tran = t.getMatrix();tran.postTranslate(_offsetx, _offsety);tran.postRotate(_angel, _anchorx, _anchory);}};public enum Gravity {LEFT_TOP, RIGHT_TOP}public LabelView(Context context) {this(context, null);}public LabelView(Context context, AttributeSet attrs) {this(context, attrs, android.R.attr.textViewStyle);}@SuppressLint("NewApi")public LabelView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);init();_animation.setFillBefore(true);_animation.setFillAfter(true);_animation.setFillEnabled(true);}private void init() {if (!(getLayoutParams() instanceof ViewGroup.LayoutParams)) {LayoutParams layoutParams =new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);setLayoutParams(layoutParams);}// the default value//setPadding(dip2Px(40), dip2Px(2), dip2Px(40), dip2Px(2));_labelViewContainerID = -1;setGravity(android.view.Gravity.CENTER);setTextColor(Color.WHITE);setTypeface(Typeface.DEFAULT_BOLD);setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);setBackgroundColor(Color.BLUE);}public void setTargetView(View target, int distance, Gravity gravity) {if (!replaceLayout(target)) {return;}final int d = dip2Px(distance);final Gravity g = gravity;final View v = target;ViewTreeObserver vto = getViewTreeObserver();vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {public void onGlobalLayout() {getViewTreeObserver().removeGlobalOnLayoutListener(this);calcOffset(getMeasuredWidth(), d, g, v.getMeasuredWidth(), false);}});}public void setTargetViewInBaseAdapter(View target, int targetWidth, int distance, Gravity gravity) {if (!replaceLayout(target)) {return;}//measure(0, 0);//calcOffset(getMeasuredWidth(), distance, gravity, targetWidth, true);calcOffset(dip2Px(targetWidth), distance, gravity, targetWidth, true);}public void remove() {if (getParent() == null || _labelViewContainerID == -1) {return;}ViewGroup frameContainer = (ViewGroup) getParent();assert (frameContainer.getChildCount() == 2);View target = frameContainer.getChildAt(0);ViewGroup parentContainer = (ViewGroup) frameContainer.getParent();int groupIndex = parentContainer.indexOfChild(frameContainer);if (frameContainer.getParent() instanceof RelativeLayout) {for (int i = 0; i < parentContainer.getChildCount(); i++) {if (i == groupIndex) {continue;}View view = parentContainer.getChildAt(i);RelativeLayout.LayoutParams para = (RelativeLayout.LayoutParams) view.getLayoutParams();for (int j = 0; j < para.getRules().length; j++) {if (para.getRules()[j] == _labelViewContainerID) {para.getRules()[j] = target.getId();}}view.setLayoutParams(para);}}ViewGroup.LayoutParams frameLayoutParam = frameContainer.getLayoutParams();target.setLayoutParams(frameLayoutParam);parentContainer.removeViewAt(groupIndex);frameContainer.removeView(target);frameContainer.removeView(this);parentContainer.addView(target,groupIndex);_labelViewContainerID = -1;}@SuppressLint("NewApi")private boolean replaceLayout(View target) {if (getParent() != null || target == null || target.getParent() == null || _labelViewContainerID != -1) {return false;}ViewGroup parentContainer = (ViewGroup) target.getParent();if (target.getParent() instanceof FrameLayout) {((FrameLayout) target.getParent()).addView(this);} else if (target.getParent() instanceof ViewGroup) {int groupIndex = parentContainer.indexOfChild(target);_labelViewContainerID = generateViewId();// relativeLayout need copy ruleif (target.getParent() instanceof RelativeLayout) {for (int i = 0; i < parentContainer.getChildCount(); i++) {if (i == groupIndex) {continue;}View view = parentContainer.getChildAt(i);RelativeLayout.LayoutParams para = (RelativeLayout.LayoutParams) view.getLayoutParams();for (int j = 0; j < para.getRules().length; j++) {if (para.getRules()[j] == target.getId()) {para.getRules()[j] = _labelViewContainerID;}}view.setLayoutParams(para);}}parentContainer.removeView(target);// new dummy layoutFrameLayout labelViewContainer = new FrameLayout(getContext());ViewGroup.LayoutParams targetLayoutParam = target.getLayoutParams();labelViewContainer.setLayoutParams(targetLayoutParam);target.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));// add target and label in dummy layoutlabelViewContainer.addView(target);labelViewContainer.addView(this);labelViewContainer.setId(_labelViewContainerID);// add dummy layout in parent containerparentContainer.addView(labelViewContainer, groupIndex, targetLayoutParam);}return true;}private void calcOffset(int labelWidth, int distance, Gravity gravity, int targetWidth, boolean isDP) {int d = dip2Px(distance);int tw = isDP ? dip2Px(targetWidth) : targetWidth;float edge = (float) ((labelWidth - 2 * d) / (2 * 1.414));if (gravity == Gravity.LEFT_TOP) {_anchorx = -edge;_offsetx = _anchorx;_angel = -45;} else if (gravity == Gravity.RIGHT_TOP) {_offsetx = tw + edge - labelWidth;_anchorx = tw + edge;_angel = 45;}_anchory = (float) (1.414 * d + edge);_offsety = _anchory;clearAnimation();startAnimation(_animation);}private int dip2Px(float dip) {return (int) (dip * getContext().getResources().getDisplayMetrics().density + 0.5f);}private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);public static int generateViewId() {for (; ; ) {final int result = sNextGeneratedId.get();// aapt-generated IDs have the high byte nonzero; clamp to the range under that.int newValue = result + 1;if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.if (sNextGeneratedId.compareAndSet(result, newValue)) {return result;}}}
}
列出一些比较重要的内容,便于使用,修改:
整体布局的位置,左上以及右上,如果需要其他位置可自行添加
public enum Gravity {LEFT_TOP, RIGHT_TOP}
初始化参数:
字体大小:setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
背景颜色:setBackgroundColor(Color.BLUE);
字体颜色:setTextColor(Color.WHITE);
位置:setGravity(android.view.Gravity.CENTER);
字体风格:setTypeface(Typeface.DEFAULT_BOLD);
一般控件设置用
public void setTargetView(View target, int distance, Gravity gravity)
适配器控件设置用
public void setTargetViewInBaseAdapter(View target, int targetWidth, int distance, Gravity gravity)
让标签消失
public void remove()
MainActivity
public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);{final LabelView label = new LabelView(this);//涂鸦部分文字的内容label.setText("大长腿");//涂鸦部分的颜色label.setBackgroundColor(0x0EfE32E20);// public void setTargetView(View target, int distance, Gravity gravity) //3个参数,一个是控件的ID,填充带的长度或者说便宜的距离(反正越大那一条东西越长),填充带的位置label.setTargetView(findViewById(R.id.image1), 30,LabelView.Gravity.LEFT_TOP);//监听事件findViewById(R.id.image1).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//填充带消失label.remove();//吐司内容Toast.makeText(MainActivity.this,"大长腿消失了", Toast.LENGTH_SHORT).show();}});}{//效果同上,只是涂鸦层位置的变化final LabelView label = new LabelView(this);label.setText("绝对领域");label.setBackgroundColor(0xff491E23);label.setTargetView(findViewById(R.id.image2), 22,LabelView.Gravity.RIGHT_TOP);findViewById(R.id.image2).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {label.remove();Toast.makeText(MainActivity.this,"绝对领域消失了", Toast.LENGTH_SHORT).show();}});}{//Button也适用LabelView label = new LabelView(this);label.setText("按钮");label.setBackgroundColor(0xffE91E63);//位于右上角label.setTargetView(findViewById(R.id.button), 14,LabelView.Gravity.RIGHT_TOP);findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(MainActivity.this, "button click",Toast.LENGTH_SHORT).show();}});}{//TextView适用LabelView label = new LabelView(this);label.setText("Text");label.setBackgroundColor(0xff03a9f4);label.setTargetView(findViewById(R.id.text), 11,LabelView.Gravity.LEFT_TOP);findViewById(R.id.text).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(MainActivity.this,"please click ListView Demo",Toast.LENGTH_SHORT).show();}});}{LabelView label = new LabelView(this);label.setText("List");label.setBackgroundColor(0xff03a9f4);label.setTargetView(findViewById(R.id.click), 8,LabelView.Gravity.RIGHT_TOP);findViewById(R.id.click).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent i = new Intent(MainActivity.this,ListViewActivity.class);startActivity(i);}});}}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.menu_main, menu);return true;}}
布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context=".MainActivity"><Button
android:id="@+id/button"android:layout_width="200dp"android:layout_height="48dp"android:background="#03a9f4"android:text="按钮"android:textColor="#ffffff" /><LinearLayout
android:layout_marginTop="24dp"android:layout_width="match_parent"android:layout_height="wrap_content"><ImageView
android:id="@+id/image1"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:scaleType="centerCrop"android:src="@mipmap/image1" /><ImageView
android:id="@+id/image2"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:scaleType="centerCrop"android:src="@mipmap/image2" /></LinearLayout><TextView
android:id="@+id/text"android:layout_marginTop="24dp"android:layout_width="wrap_content"android:padding="16dp"android:background="#212121"android:layout_gravity="center"android:gravity="center"android:text="TextView"android:textColor="#ffffff"android:layout_height="48dp" /><Button
android:id="@+id/click"android:layout_marginTop="20dp"android:layout_width="200dp"android:layout_gravity="center_horizontal"android:layout_height="48dp"android:background="#E91E63"android:text="点击进入ListView"android:textColor="#ffffff" /></LinearLayout>
ListViewActivity
public class ListViewActivity extends Activity {public class CategoryData {public String image;public String text;public String label;}public class CategoryAdapter extends SimpleBaseAdapter<CategoryData> {public CategoryAdapter(Context context, List<CategoryData> data) {super(context, data);}@Overridepublic int getItemResource() {return R.layout.list_view_item;}@Overridepublic View getItemView(int position, View convertView, ViewHolder holder) {CategoryData item = (CategoryData) _categoryAdapter.getItem(position);TextView textView = holder.getView(R.id.text);textView.setText(item.text);ImageView imageView = holder.getView(R.id.image);imageView.setImageResource(Integer.parseInt(item.image));// you have to generate label ID manualLabelView label = holder.getView(12345);if (label == null) {label = new LabelView(ListViewActivity.this);label.setId(12345);label.setBackgroundColor(0xffE91E63);// public void setTargetViewInBaseAdapter(View target, int targetWidth, int distance, Gravity gravity)//传入4个参数,被画的控件,label中text的位置(数字越小越靠右),整个标签便宜的位置,总体所在的区域label.setTargetViewInBaseAdapter(imageView, 108, 25, LabelView.Gravity.LEFT_TOP);}label.setText(item.label);return convertView;}}private CategoryAdapter _categoryAdapter;private ListView _listView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_list_view);_listView = (ListView) findViewById(R.id.list_view);_categoryAdapter = new CategoryAdapter(this, null);_listView.setAdapter(_categoryAdapter);//重复三轮妹子getCategoryData();getCategoryData();getCategoryData();}private void getCategoryData() {List<CategoryData> data = new ArrayList<CategoryData>();{CategoryData item = new CategoryData();item.text = "妹子好看";item.image = R.mipmap.k1 + "";item.label = "妹子1";data.add(item);}{CategoryData item = new CategoryData();item.text = "绝对领域";item.image = R.mipmap.k2 + "";item.label = "妹子2";data.add(item);}{CategoryData item = new CategoryData();item.text = "妹子好看1";item.image = R.mipmap.k3 + "";item.label = "妹子3";data.add(item);}{CategoryData item = new CategoryData();item.text = "绝对领域1";item.image = R.mipmap.k4 + "";item.label = "妹子4";data.add(item);}{CategoryData item = new CategoryData();item.text = "啪啪啪";item.image = R.mipmap.k5 + "";item.label = "妹子5";data.add(item);}{CategoryData item = new CategoryData();item.text = "萌萌哒,呵呵哒";item.image = R.mipmap.k6 + "";item.label = "妹子6";data.add(item);}{CategoryData item = new CategoryData();item.text = "肉便器噼里啪啦";item.image = R.mipmap.k7 + "";item.label = "妹子7";data.add(item);}{CategoryData item = new CategoryData();item.text = "稀里哗啦";item.image = R.mipmap.k8 + "";item.label = "妹子8";data.add(item);}{CategoryData item = new CategoryData();item.text = "咖喱给给";item.image = R.mipmap.k9 + "";item.label = "妹子9";data.add(item);}{CategoryData item = new CategoryData();item.text = "呵呵哈hi";item.image = R.mipmap.k10 + "";item.label = "妹子10";data.add(item);}_categoryAdapter.addAll(data);_categoryAdapter.notifyDataSetChanged();}}
其他一些只是为了实现而写了,可以直接看源码
源码地址:http://yunpan.cn/cmxxzBp8T8MSX 访问密码 7dcc
部分内容参考网上,如有雷同,经供参考
android 自定义LabelView实现各类小标签,重要功能已标注相关推荐
- android手机微信收藏功能实现,Android模仿微信收藏文件的标签处理功能
最近需要用到微信的标签功能(如下图所示).该功能可以添加已有标签,也可以自定义标签.也可以删除已编辑菜单.研究了一番.发现还是挺有意思的,模拟实现相关功能. 该功能使用类似FlowLayout的功能. ...
- Android仿支付宝UI功能开发,Android 自定义view仿支付宝咻一咻功能
支付宝上有一个咻一咻的功能,就是点击图片后四周有水波纹的这种效果,今天也写一个类似的功能. 效果如下所示: 思路: 就是几个圆的半径不断在变大,这个可以使用动画缩放实现,还有透明动画 还有就是这是好几 ...
- android wear支付宝6,Android自定义View仿支付宝输入六位密码功能
跟选择银行卡界面类似,也是用一个PopupWindow,不过输入密码界面是一个自定义view,当输入六位密码完成后用回调在Activity中获取到输入的密码并以Toast显示密码.效果图如下: 自定义 ...
- Android 自定义动画view(小变大,旋转,色值)
也不知道到看了多少的动画总结了,但是用到的时候太少,过段时间就会忘记了. 既然如此,我选择直接去动手学习,步步进阶. 效果: 上代码之前我们分析一下才会加深自己的印象: 需要画一个矩形 和 一个圆形 ...
- Android自定义实现按周签到打卡功能
之前实现过<Android可签到的日历控件>的功能,跟这篇一样都是实现签到打卡功能,这篇实现的是按月进行打卡做标识,本篇内容实现的按周进行签到打卡. 实现签到规则如下: 1.连续签到7天, ...
- 安android自定义照相机,Android自定义照相机的实例
Android自定义照相机实现 近期小巫在学校有一个创新项目,也不是最近,是一个拖了很久的项目,之前一直没有去搞,最近因为要中期检查,搞得我跟小组成员一阵忙活,其实开发一款照相机软件并不太难,下面就是 ...
- android 自定义相机,Android自定义相机实现定时拍照功能
这篇博客为大家介绍Android自定义相机,并且实现倒计时拍照功能. 首先自定义拍照会用到SurfaceView控件显示照片的预览区域,以下是布局文件: activity_main.xml andro ...
- android 画布叠加,Android自定义图形,图形的拼接、叠加、相容
直接上Xfermode子类: AvoidXfermode 指定了一个颜色和容差,强制Paint避免在它上面绘图(或者只在它上面绘图). PixelXorXfermode 当覆盖已有的颜色时,应用一 ...
- android 实现自动拍照,Android自定义相机实现定时拍照功能
这篇博客为大家介绍Android自定义相机,并且实现倒计时拍照功能. 首先自定义拍照会用到SurfaceView控件显示照片的预览区域,以下是布局文件: activity_main.xml andro ...
最新文章
- 运算符中的二元重载,为什么要调用友元函数而不是全局函数的问题
- 算法------二叉树的层序遍历
- python yield遍历目录
- FreePascal - 如何在各个平台中安装CodeTyphon!
- Android --- 屏幕方向screenOrientation属性详解
- 如何把配置文件集成到.exe中_VSCode如何使用cmder
- Golang之envconfig的使用
- VB程序逆向常用的函数
- 经典排序算法 - 鸡尾酒排序Cocktail sort
- 2021年高考成绩查询山东德洲,2021年德州高考状元是谁分数多少分,历年德州高考状元名单...
- 安卓休眠唤醒ajax休线程,休眠无法获得远程服务器上当前线程的事务同步会话...
- mysql insert 主键冲突_在MySql中建立存储过程和解决insert into select 中主键冲突的有关问题...
- 基于WebActivator的改进版本KudyStudio.Web.Activating讲解与下载
- Jquery关闭离开页面时提醒
- java实现KMZ文件转KML文件
- SOLD格雷母线是什么?
- 全网最全最细的vmware虚拟机创建教程,一步一步教你完成虚拟机创建。
- 【Python入门练手小项目】画一个蓝胖子❤️
- python 对比matlab_全面对比 MATLAB、Julia、Python,谁在科学计算中更胜一筹?
- 小程序连接优声云打印机流程
热门文章
- Surciata源码分析之IpsNFQ模式(1)
- Python爬虫实现无api版本各国汇率实时兑换(美元、英镑等)
- 栈——栈的基本概念和基本操作
- Automated Phrase
- c语言程序考试试题,C语言程序设计期末考试试题(含答案)
- vue之push() pop() shift() unshift() splice() sort() reverse()等等
- swust2020春季《形势与政策》mooc考试答案参考
- nanohttp简单使用
- 视频监控网络传输计算方法
- apidoc写php接口文档