开发蒙版向导的一些领悟

来源:互联网 发布:ip网络计算 编辑:程序博客网 时间:2024/05/16 09:07

先上效果图!


奉上git地址,还有一些属性和点击事件的设置可以自己封装
https://github.com/mocn26169/Android-GuideHelper

这次主要是使用了自定义Dialog的方式来实现这个效果
主要步骤:
1、创建一个自定义VIew的Dialog
2、复制一个需要高亮显示的View在同样的位置,并完美覆盖(重点)
3、绘制提示图片

1  创建一个自定义VIew的Dialog


guidelayout = new RelativeLayout(activity);//创建Dialog,遮挡状态栏guideDialog = new Dialog(activity, android.R.style.Theme_DeviceDefault_Light_DialogWhenLarge_NoActionBar);//设置背景颜色guideDialog.getWindow().setBackgroundDrawable(new ColorDrawable(0x66000000));//设置自定义的布局guideDialog.setContentView(guidelayout);//设置布局的属性guideDialog.getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);//设置点击不能取消guideDialog.setCancelable(false);//显示DialogguideDialog.show();

2  复制一个需要高亮显示的View在同样的位置,并完美覆盖(重点)

2.1、获取原来的VIew的位置和宽高
//获取view的宽高int vWidth = lightView.getMeasuredWidth();int vHeight = lightView.getMeasuredHeight();//如果宽高都小于等于0,再measure试下获取if (vWidth <= 0 || vHeight <= 0) {  ViewGroup.LayoutParams mlayoutParams = lightView.getLayoutParams();  lightView.measure(mlayoutParams.width, mlayoutParams.height);  vWidth = lightView.getMeasuredWidth();  vHeight = lightView.getMeasuredHeight();}//获取不到宽高则返回操作if (vWidth <= 0 || vHeight <= 0) {  Log.e("GuideHelper", "宽高都小于等于0");  return;}

2.2  获取自定义布局在视图的位置,View的Y轴坐标减去这个位置的Y轴坐标,避免Dialog不是全屏的时候位置偏移,就可以可以实现全局覆盖了

//获取view在屏幕的位置int[] location = new int[2];lightView.getLocationOnScreen(location);//获取layout在屏幕上的位置int layoutOffset[] = new int[2];guidelayout.getLocationOnScreen(layoutOffset);//这里避免dialog不是全屏,导致view的绘制位置不对应location[1] -= layoutOffset[1];

2.3  根据视图缓存获取bitmap

//开启能缓存图片信息lightView.setDrawingCacheEnabled(true);//获取视图缓存lightView.buildDrawingCache();Bitmap LightBitmap = lightView.getDrawingCache();if (LightBitmap != null) {  //根据缓存获取Bitmap  LightBitmap = Bitmap.createBitmap(LightBitmap);} else {  //如果获取不到,则用创建一个view宽高一样的bitmap用canvas把view绘制上去  LightBitmap = Bitmap.createBitmap(vWidth, vHeight, Bitmap.Config.ARGB_8888);  Canvas canvas = new Canvas(LightBitmap);  lightView.draw(canvas);}//关闭能缓存图片信息lightView.setDrawingCacheEnabled(false);//释放缓存lightView.destroyDrawingCache();

2.4  创建一个ImageView,设置位置,把bitmap设置为背景,添加到布局

//设置ImageView属性ImageView newLightView = new ImageView(activity);newLightView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);newLightView.setImageBitmap(LightBitmap);//动态设置Viwe的idint imageViewId = R.id.snack;newLightView.setId(imageViewId);//设置位置RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);params.leftMargin = location[0];params.topMargin = location[1];//添加到布局guidelayout.addView(newLightView, params);

到这里就完成对需要高亮的View的复制了,注意的是这个view最好设置背景颜色,不然有可能没有效果。

3  显示提示图片

获取资源的Bitmap,然后创建ImageView,设Bitmap为背景,在指定位置显示

/**********显示提示图片**********///获取提示图片的BitmapBitmap tipBitmap = BitmapFactory.decodeResource(activity.getResources(), tipsImageResourceId);//设置大小RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);int showViewHeight = tipBitmap.getHeight();int showViewWidth = tipBitmap.getWidth();//设置ImageView属性ImageView newTipView = new ImageView(activity);newTipView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);layoutParams.width = showViewWidth;layoutParams.height = showViewHeight;newTipView.setImageBitmap(tipBitmap);//设置间距(可自行封装)//layoutParams.topMargin += dipToPix(activity, 20);//设置相对位置(可自行封装)layoutParams.addRule(RelativeLayout.BELOW, newLightView.getId());layoutParams.addRule(RelativeLayout.ALIGN_LEFT, newLightView.getId());//layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL);//添加到布局guidelayout.addView(newTipView, layoutParams);


完整代码:
package com.mocn.guidehelper;import android.app.Activity;import android.app.Dialog;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Rect;import android.graphics.drawable.ColorDrawable;import android.os.Build;import android.support.annotation.RequiresApi;import android.util.DisplayMetrics;import android.util.Log;import android.util.TypedValue;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.view.Window;import android.view.WindowManager;import android.widget.ImageView;import android.widget.RelativeLayout;import java.util.List;public class GuideHelper {    private List<PageData> pageDatas;    private Activity activity;    private Dialog guideDialog;    private RelativeLayout guidelayout;    public GuideHelper(Activity activity, List<PageData> pageDatas) {        this.activity = activity;        this.pageDatas = pageDatas;    }    public void show() {        if (pageDatas.size() <= 0) {            Log.e("GuideHelper", "没有数据");            return;        }        if (guidelayout == null) {            guidelayout = new RelativeLayout(activity);            //创建Dialog,不遮挡状态栏            guideDialog = new Dialog(activity, R.style.popupDialog);            guideDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);            guideDialog.setContentView(guidelayout);            guideDialog.setCanceledOnTouchOutside(false);            guideDialog.setCancelable(false);            guideDialog.getWindow().setBackgroundDrawable(new ColorDrawable(0x66000000));            //设置不遮挡状态栏            WindowManager.LayoutParams lay = guideDialog.getWindow().getAttributes();            DisplayMetrics dm = new DisplayMetrics();            activity.getWindowManager().getDefaultDisplay().getMetrics(dm);            Rect rect = new Rect();            View view = activity.getWindow().getDecorView();//decorView是window中的最顶层view,可以从window中获取到decorView            view.getWindowVisibleDisplayFrame(rect);            lay.height = dm.heightPixels - rect.top;            lay.width = dm.widthPixels;            guideDialog.show();//            //创建Dialog,遮挡状态栏//            guideDialog = new Dialog(activity, android.R.style.Theme_DeviceDefault_Light_DialogWhenLarge_NoActionBar);//            //设置背景颜色//            guideDialog.getWindow().setBackgroundDrawable(new ColorDrawable(0x66000000));//            //设置自定义的布局//            guideDialog.setContentView(guidelayout);//            //设置布局的属性//            guideDialog.getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);//           //设置点击不能取消//            guideDialog.setCancelable(false);//            //显示Dialog//            guideDialog.show();        }        pageDatas.get(0).getLightView().post(new Runnable() {            @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)            @Override            public void run() {                showTip(guidelayout);            }        });    }    private void showTip(final RelativeLayout guidelayout) {        View lightView = pageDatas.get(0).getLightView();        int tipsImageResourceId = pageDatas.get(0).getTipsImageResourceId();        /**********显示高亮控件**********/        //获取view的宽高        int vWidth = lightView.getMeasuredWidth();        int vHeight = lightView.getMeasuredHeight();        //如果宽高都小于等于0,再measure试下获取        if (vWidth <= 0 || vHeight <= 0) {            ViewGroup.LayoutParams mlayoutParams = lightView.getLayoutParams();            lightView.measure(mlayoutParams.width, mlayoutParams.height);            vWidth = lightView.getMeasuredWidth();            vHeight = lightView.getMeasuredHeight();        }        //获取不到宽高则返回操作        if (vWidth <= 0 || vHeight <= 0) {            Log.e("GuideHelper", "宽高都小于等于0");            return;        }        //获取view在屏幕的位置        int[] location = new int[2];        lightView.getLocationOnScreen(location);        //获取layout在屏幕上的位置        int layoutOffset[] = new int[2];        guidelayout.getLocationOnScreen(layoutOffset);        //这里避免dialog不是全屏,导致view的绘制位置不对应        location[1] -= layoutOffset[1];        //开启能缓存图片信息        lightView.setDrawingCacheEnabled(true);        //获取视图缓存        lightView.buildDrawingCache();        Bitmap LightBitmap = lightView.getDrawingCache();        if (LightBitmap != null) {            //根据缓存获取Bitmap            LightBitmap = Bitmap.createBitmap(LightBitmap);        } else {            //如果获取不到,则用创建一个view宽高一样的bitmap用canvas把view绘制上去            LightBitmap = Bitmap.createBitmap(vWidth, vHeight, Bitmap.Config.ARGB_8888);            Canvas canvas = new Canvas(LightBitmap);            lightView.draw(canvas);        }        //关闭能缓存图片信息        lightView.setDrawingCacheEnabled(false);        //释放缓存        lightView.destroyDrawingCache();        //设置ImageView属性        ImageView newLightView = new ImageView(activity);        newLightView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);        newLightView.setImageBitmap(LightBitmap);        //动态设置Viwe的id        int imageViewId = R.id.snack;        newLightView.setId(imageViewId);        //设置位置        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);        params.leftMargin = location[0];        params.topMargin = location[1];        //添加到布局        guidelayout.addView(newLightView, params);        /**********显示提示图片**********/        //获取提示图片的Bitmap        Bitmap tipBitmap = BitmapFactory.decodeResource(activity.getResources(), tipsImageResourceId);        //设置大小        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);        int showViewHeight = tipBitmap.getHeight();        int showViewWidth = tipBitmap.getWidth();        //设置ImageView属性        ImageView newTipView = new ImageView(activity);        newTipView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);        layoutParams.width = showViewWidth;        layoutParams.height = showViewHeight;        newTipView.setImageBitmap(tipBitmap);        //设置间距(可自行封装)        //layoutParams.topMargin += dipToPix(activity, 20);        //设置相对位置(可自行封装)        layoutParams.addRule(RelativeLayout.BELOW, newLightView.getId());        layoutParams.addRule(RelativeLayout.ALIGN_LEFT, newLightView.getId());        //layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL);        //添加到布局        guidelayout.addView(newTipView, layoutParams);        //点击布局执行下一步动作        guidelayout.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                //清理布局控件                guidelayout.removeAllViews();                //操作有第二步继续执行                if (pageDatas.size() >= 2) {                    pageDatas.remove(0);                    show();                } else {                    guideDialog.dismiss();                }            }        });    }    public static class PageData {        /**         * 高亮View         */        private View lightView;        /**         * 提示图片id         */        private int tipsImageResourceId;        public PageData(View lightView, int tipsImageResourceId) {            this.lightView = lightView;            this.tipsImageResourceId = tipsImageResourceId;        }        public View getLightView() {            return lightView;        }        public void setLightView(View lightView) {            this.lightView = lightView;        }        public int getTipsImageResourceId() {            return tipsImageResourceId;        }        public void setTipsImageResourceId(int tipsImageResourceId) {            this.tipsImageResourceId = tipsImageResourceId;        }    }    /**     * dip转px     */    public int dipToPix(Context context, int dip) {        int size = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, context.getResources().getDisplayMetrics());        return size;    }    /**     * 实例化布局     *     * @param layoutId     * @return     */    public View inflate(int layoutId) {        LayoutInflater inflater = LayoutInflater.from(activity);        View view = inflater.inflate(layoutId, null);        return view;    }}

使用方法:
package com.mocn.guidehelper;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.widget.Button;import android.widget.TextView;import java.util.ArrayList;import java.util.List;public class GuideHelperActivity extends AppCompatActivity {    private TextView tv_first;    private Button btn_first;    private Button btn_second;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_guide_helper);        tv_first = (TextView) findViewById(R.id.tv_first);        btn_first = (Button) findViewById(R.id.btn_first);        btn_second = (Button) findViewById(R.id.btn_second);        btn_first.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                List<GuideHelper.PageData> pageDatas = new ArrayList<GuideHelper.PageData>();                pageDatas.add(new GuideHelper.PageData(btn_first, R.mipmap.tip1));                pageDatas.add(new GuideHelper.PageData(tv_first, R.mipmap.tip1));                pageDatas.add(new GuideHelper.PageData(btn_second, R.mipmap.tip1));                GuideHelper guideHelper = new GuideHelper(GuideHelperActivity.this, pageDatas);                guideHelper.show();            }        });    }}


在这个例子当中最重要的是复制一个view,而复制一个View的重点又是根据getDrawingCache()获取缓存的Bitmap,并显示在界面上

getDrawingCache()被经常用来做屏幕截图,比如说:

看下手机截图:


截图之后的效果图


可以看到,截取了除状态栏外,标题栏和内容的界面,关键代码如下:

  /**     * 截取当前程序界面     */    private void saveView() {        //DecorView只有一个子元素为LinearLayout。代表整个Window界面,包含通知栏,标题栏,内容显示栏三块区域        View decorView = getWindow().getDecorView();        //开启能缓存图片信息        decorView.setDrawingCacheEnabled(true);        //获取视图缓存        decorView.buildDrawingCache();        //根据缓存获取Bitmap        Bitmap bmp = decorView.getDrawingCache();        Rect rect = new Rect();        //getWindowVisibleDisplayFrame方法可以获取到程序显示的区域,包括标题栏,但不包括状态栏        decorView.getWindowVisibleDisplayFrame(rect);        //获取状态栏高度        int statusBarHeight = rect.top;        //获取图片宽高        int width = bmp.getWidth();        int height = bmp.getHeight();        //坐标轴和高度都减去状态栏的高度        Bitmap saveBmp = Bitmap.createBitmap(bmp, 0, statusBarHeight,                width, height - statusBarHeight, null, false);        //关闭能缓存图片信息        decorView.setDrawingCacheEnabled(false);        //释放缓存        decorView.destroyDrawingCache();        //将图片保存到SD卡        saveBitmap("ScreenShot", saveBmp);    }



有时候,我们需要截取超过屏幕外的界面,比如说listview和scrollView,就要动态计算加起来的子view的总高度了,效果图如下:



代码如下:

    /**     * 截取超过程序界面的长图     */    private void saveLongView() {        int h = 0;                // 获取listView实际高度//        for (int i = 0; i < listView.getChildCount(); i++) {//            h += listView.getChildAt(i).getHeight();//        }                // 获取scrollView实际高度        for (int i = 0; i < scrollView.getChildCount(); i++) {            h += scrollView.getChildAt(i).getHeight();        }                //如果是webView//        Picture snapShot = webView.capturePicture();//        Bitmap bmp = Bitmap.createBitmap(snapShot.getWidth(), snapShot.getHeight(), Bitmap.Config.ARGB_8888);//        Canvas canvas = new Canvas(bmp);//        snapShot.draw(canvas);                Log.i("ScreenShot", " 高度:" + scrollView.getHeight());        Log.i("ScreenShot", "实际高度:" + h);        Bitmap bitmap;        // 创建对应大小的bitmap        bitmap = Bitmap.createBitmap(scrollView.getWidth(), h, Bitmap.Config.ARGB_8888);        final Canvas canvas = new Canvas(bitmap);        scrollView.draw(canvas);        //将图片保存到SD卡        saveBitmap("ScreenShot", bitmap);    }


0 0
原创粉丝点击