自定义高亮区域 作用户引导的思路
来源:互联网 发布:淘宝分享有礼怎样计费 编辑:程序博客网 时间:2024/04/28 09:24
先显示简易的效果
网上看了一些引导 发现自定义文本 和箭头指向都不够方便,就写了比较符合自己习惯的
//内容更新
视觉优化 将下面代码分别添加到两个addView之后
ObjectAnimator.ofFloat(高亮的view, "scaleY", 0.5f, 1.0f).setDuration(800).start(); ObjectAnimator.ofFloat(显示文本, "scaleX", 0.5f, 1.0f).setDuration(800).start(); ObjectAnimator.ofFloat(显示文本, "scaleY", 0.5f, 1.0f).setDuration(800).start();
效果如下
相关Module下载
1.已经实现的有3种简易功能
一种是连接两个高亮的view 提示语句在线(View)的中间
二是指向某一条文件
三是多个高亮区域的连接
核心思路就是遮盖一层。我选择直接放在根布局下面。当然你想 直接动态添加的方式也行。目前只是探讨一下思路。
通过传入的view` Region region = new Region(new Region(0, 0, getWidth(), getHeight()));
for (int i = 0; i < rects.size(); i++) { Region region0 = new Region(rects.get(i)); region.op(region0, Region.Op.DIFFERENCE); } RegionIterator iterator = new RegionIterator(region); Rect rectNew = new Rect(); while (iterator.next(rectNew)) { canvas.drawRect(rectNew, paint); }`
扣出高亮区域然后连线添加文本 剩下的就是具体坐标和角度的计算。
@Override protected void dispatchDraw(Canvas canvas) { //核心顺序 if (rects.size() != 0) { drawRect(canvas);//绘制高亮区域 super.dispatchDraw(canvas);//绘制子view -->如提示文字 箭头 } }
为了大家方便自定义自己的 指向箭头。我没有画这条线 而是留了一个简易的view。可以用自己ui设计的箭头去替换 那么你可能就需要加上 图片宽度带来的影响
使用方法简易示例
//盖在根布局最上层 可指定其他任意层级的view高亮 链接 提示 gcv = (GuideCoverView) findViewById(R.id.gcv); //后期可改进为 动态添加// gcv.doubleViewContact(view, view2, 0, "这是一个提示??", false); gcv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.i("rex", "v"); int c = index++ % 5; //第三处参数为 链接线的 自定义view 此处仅传图片资源id 传0即默认黄线 如需要其他自定义或者网络图片 可以去内部自定义addArr if (c == 0) { gcv.doubleViewContact(view, view2, 0, "这是一个提示~~", false); } else if (c == 1) { gcv.doubleViewContact(view, view3, 0, "这又是一个提示??", false); } else if (c == 2) { gcv.doubleViewContact(view2, view3, 0, "这又他妈是一个提示??", false); } else if (c == 3) { gcv.doubleViewContact(view, view4, 0, "熄火区域", true); } else { //第二种多连接示例 gcv.manyViewContact( asList(view, view2, view2, view3, view3, view4, view4,view), asList("多连接示例1", "多连接示例2", "多连接示例3", "多连接示例4"), asList(false, false, false, true) ); } } });
核心自定义遮盖引导层
package com.rex;import android.animation.ObjectAnimator;import android.animation.PropertyValuesHolder;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Rect;import android.graphics.Region;import android.graphics.RegionIterator;import android.os.Build;import android.util.AttributeSet;import android.util.Log;import android.view.Gravity;import android.view.View;import android.view.ViewTreeObserver;import android.widget.FrameLayout;import android.widget.ImageView;import android.widget.TextView;import org.w3c.dom.Text;import java.util.ArrayList;import java.util.List;/** * Created by Rex on 2017/1/4. * 比较开放性便于自定义文字 联系线的高亮引导容器 */public class GuideCoverView extends FrameLayout { private List<Rect> rects = new ArrayList<>(); private Paint paint; private int padding = 8; private int index; private View lastView; private int statusBarHeight; private boolean isOnlyOneViewToText; private int mResourId = 0; private Canvas mCanvas; public GuideCoverView(Context context) { this(context, null); } public GuideCoverView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public GuideCoverView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { statusBarHeight = getStatusBarHeight(); paint = new Paint(); paint.setColor(Color.parseColor("#8c000000")); } public View addArr(int w, int h) { FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(w, h); View view = new View(getContext()); if (mResourId > 0) view.setBackgroundResource(mResourId); else view.setBackgroundColor(Color.GREEN); addView(view, lp); return view; } /** * @param viewC1 * @param viewC2 * @param id 这里示例为 两个view高亮 自定义图片作为连接示意 线中心作为 提示语 * @param isText 是否为单高亮 末端指向文字 此时另一个view决定了文本显示的位置 */ public void doubleViewContact(final View viewC1, final View viewC2, final int id, final String msg, final boolean isText) { clear(); HighlightView(viewC1, msg, isText); HighlightView(viewC2, msg, isText); invalidate(); } public void manyViewContact(ArrayList<View> views, ArrayList<String> msg, ArrayList<Boolean> isText) { clear(); for (int i = 0; i < views.size(); i++) { if (i + 1 >= views.size()) return; int j = i / 2; Log.i("rex", "j-->" + j + "msg-->" + msg.get(j) + "boolean--->" + isText.get(j)); HighlightView(views.get(i), msg.get(j), isText.get(j)); ++i; HighlightView(views.get(i), msg.get(j), isText.get(j)); invalidate(); } } @Override protected void dispatchDraw(Canvas canvas) { //核心顺序 if (rects.size() != 0) { drawRect(canvas);//绘制高亮区域 super.dispatchDraw(canvas);//绘制子view -->如提示文字 箭头 } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); } public void clear() { rects.clear(); lastView = null; removeAllViews(); invalidate(); } private void drawRect(Canvas canvas) { Region region = new Region(new Region(0, 0, getWidth(), getHeight())); for (int i = 0; i < rects.size(); i++) { Region region0 = new Region(rects.get(i)); region.op(region0, Region.Op.DIFFERENCE); } RegionIterator iterator = new RegionIterator(region); Rect rectNew = new Rect(); while (iterator.next(rectNew)) { canvas.drawRect(rectNew, paint); } } public void HighlightView(final View viewH, final String msg, final boolean isText) { ViewTreeObserver vto = viewH.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { //监听一次马上结束 if (Build.VERSION.SDK_INT < 16) { viewH.getViewTreeObserver().removeGlobalOnLayoutListener(this); } else { viewH.getViewTreeObserver().removeOnGlobalLayoutListener(this); } int[] locationXy = getLocationXy(viewH); Rect rect = new Rect(locationXy[0] - padding, locationXy[1] - statusBarHeight - padding, locationXy[0] + viewH.getMeasuredWidth() + padding, locationXy[1] + viewH.getMeasuredHeight() - statusBarHeight + padding); if (lastView == null) { rects.add(rect); lastView = viewH; } else { if (!isText) { rects.add(rect);//是否高亮 } ContactDouble(lastView, viewH, msg, isText); lastView = null; } } }); } /** * 高亮view指向文本 * * @param view */ private void ContactText(View view) { } /** * 用自定义的view连接两个 * * @param viewC1 * @param viewC2 * @param isText */ private void ContactDouble(View viewC1, View viewC2, final String msg, final boolean isText) { int[] locationXy = getLocationXy(viewC1); int[] locationXy2 = getLocationXy(viewC2); final int x1 = locationXy[0] + viewC1.getWidth() / 2 - 2; final int x2 = locationXy2[0] + viewC2.getWidth() / 2; final int y1 = locationXy[1]; final int y2 = locationXy2[1]; final int lenth = (int) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)) - 20 * padding; final View view = addArr(3, lenth); float tan = (x1 - x2) * 1.0f / (y1 - y2); final float du = -(float) Math.toDegrees(Math.atan(tan)); ViewTreeObserver vto = view.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { //监听一次马上结束 if (Build.VERSION.SDK_INT < 16) { view.getViewTreeObserver().removeGlobalOnLayoutListener(this); } else { view.getViewTreeObserver().removeOnGlobalLayoutListener(this); } final int centerX = (x1 + x2) / 2 - 4 * padding; final int centerY = (y1 + y2) / 2 - view.getHeight() / 2 - 4 * padding; view.setX(centerX); view.setY(centerY); view.setRotation(du); FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); final TextView tv = new TextView(getContext()); tv.setText(msg); tv.setGravity(Gravity.CENTER); if (isText) { //线顶端 MeasureWH(tv, new measureOk() { @Override public void ok(View view, int w, int h) { view.setX(centerX + w / 2); view.setY(centerY); } }); } else { //线中间 tv.setX((x1 + x2) / 2 + 2 * padding); tv.setY((y1 + y2) / 2 + 2 * padding); } tv.setTextColor(Color.WHITE); addView(tv, params); } }); } /** * 获取屏幕的坐标(包括状态栏等) */ public int[] getLocationXy(View viewL) { int[] lXy = new int[2]; viewL.getLocationOnScreen(lXy); LogI("getLocationXy", lXy.toString()); return lXy; } /** * 监听绘制完成后测量宽高 */ public interface measureOk { void ok(View view, int w, int h); } public static void MeasureWH(final View viewL, final measureOk impl) { ViewTreeObserver vto = viewL.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { //监听一次马上结束 if (Build.VERSION.SDK_INT < 16) { viewL.getViewTreeObserver().removeGlobalOnLayoutListener(this); } else { viewL.getViewTreeObserver().removeOnGlobalLayoutListener(this); } if (impl != null) { impl.ok(viewL, viewL.getWidth(), viewL.getHeight()); } } }); } private void LogI(String msg1, String msg2) { LogI(msg1 + " ---- >" + msg2); } private void LogI(String msg) { Log.i("rex", msg); } public int getStatusBarHeight() { int result = 0; int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { result = getResources().getDimensionPixelSize(resourceId); } return result; }}
1 0
- 自定义高亮区域 作用户引导的思路
- 制作新手引导高亮区域方法之一:混合模式
- cocos2dx混合模式应用-制作新手引导高亮区域
- 用户自定义排序功能的设计思路
- android 引导用户指示操作 高亮显示 可以自定义文字或者图片来作为提示,文字会自动换行
- 制作新手引导高亮区域方法之二:裁剪模式
- [Quick-x]制作新手引导高亮区域方法之一:混合模式
- [Quick-x]制作新手引导高亮区域方法之二:裁剪模式
- 制作新手引导高亮区域方法之二:裁剪模式
- Excel从另一个Excel文件中用户自定义区域(UsedRange)拷贝数据和行高、列宽
- 新手引导的思路(抛弃引擎)
- 一个好的在线CSS编辑器,多语言,带语法高亮和用户自定义压缩
- 自定义NavigationBar的思路
- 自定义progressbar 的思路
- 区域生长算法的思路整理
- android不规则区域的点击响应思路
- android高亮引导页
- app高亮引导蒙层的实现
- tomcat配置详解
- JVM中垃圾收集器 serial、parNew、parallel Scavenge;serial old、parallel old、CMS、G1
- 【LeetCode】88. Merge Sorted Array
- 7.12 编程题2
- 时间的今天去面试新工作,老板是一个五十多岁的大
- 自定义高亮区域 作用户引导的思路
- SpringMVC 5(拦截器)
- EasyAR从入门到精通开发系列教程(2)--创建模型并互动
- Flume基本知识点
- Hadoop系列一HDFS简介
- JS中if语句中的条件
- 部署微服务:Spring Cloud vs. Kubernetes
- Cannot find autoconf. Please check your autoconf installation
- nginx_upload+javaWEB文件上传系统搭建