在我们第一次安装app的时候,有一些app会出现一个覆盖在我们原来View上面的浮层view,用来做一个app的指示,让用户更快的知道app的整体架构和功能点。下面大家看一下效果图;

这就是我们要出现的效果。首先我们需要实现的功能点大概就是 ,在第一次安装的时候我们才会去触发这个浮层view的效果,我们就需要去保存这个。我们还需要去绘制一个浮层view在盖在原有的view上面,需要写一个列表,当他下拉的时候,符合某些条件就触发一个浮层。大概的要求我们知道了就可以开工了,

我们先看一下整体的项目结构: 大概的架构也跃然于屏了,获取屏幕像素的工具类,浮层view管理者,构造类,对象类,主类实现 效果和一点小小逻辑。

我们先从 像素工具类开始看:

ScreenUtils
package com.newbieguide;import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.graphics.Rect;
import android.util.DisplayMetrics;import java.lang.reflect.Field;/*** 获取手机屏幕参数的功能工具类* Created by nzx on 2016/9/2.* 屏幕区域的获取  :就是整个手机的可见范围* activity.getWindowManager().getDefaultDisplay();* 应用区域的获取:就是没有包括 那些 应用商,时间的那个栏 剩下的部分=屏幕部分减去时间栏* <p/>* Rect outRect = new Rect();* activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(outRect);* 我们绘制view的绘制:就是应用区域 减去(我们没有隐藏标题栏应用状态下( this.requestWindowFeature(Window.FEATURE_NO_TITLE);//去掉标题栏  ) )的部分=View 部分* <p/>* Rect outRect = new Rect();* activity.getWindow().findViewById(Window.ID_ANDROID_CONTENT).getDrawingRect(outRect);*/
public class ScreenUtils {private ScreenUtils() {throw new AssertionError();}//屏幕距离(dp)转换成像素距离(px)public static float dpToPx(Context context, float dp) {if (context == null) {return -1;}return dp * context.getResources().getDisplayMetrics().density;}public static int dpToPx(Context context, int dp) {return (int) (dp * context.getResources().getDisplayMetrics().density);}/*** 获取屏幕宽度* DisplayMetrics 这是 一个系统 用来 专门 管理 手机 像素 屏幕尺寸的类*/public static int getScreenWidth(Context context) {DisplayMetrics dm = context.getResources().getDisplayMetrics();int screenHeight = dm.widthPixels;return screenHeight;}/*** 获取屏幕高度*/public static int getScreenHeight(Context context) {DisplayMetrics dm = context.getResources().getDisplayMetrics();int screenHeight = dm.heightPixels;return screenHeight;}/*** 获取状态栏的高*/public static int getStatusBarHeight(Activity context) {Rect frame = new Rect();context.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);int statusBarHeight = frame.top;if (0 == statusBarHeight) {statusBarHeight = getStatusBarHeightByReflection(context);}return statusBarHeight;}public static int getStatusBarHeight1(Activity context) {Rect rect = new Rect();context.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);int statuBarHeight = rect.top;if (0 == statuBarHeight) {statuBarHeight = getStatusBarHeightByReflection(context);}return statuBarHeight;}//获取状态栏高度 。public static int getStatusBarHeightByReflection(Context context) {Class<?> c;Object obj;Field field;// 默认为38,貌似大部分是这样的int x, statusBarHeight = 38;try {c = Class.forName("com.android.internal.R$dimen");obj = c.newInstance();field = c.getField("status_bar_height");x = Integer.parseInt(field.get(obj).toString());statusBarHeight = context.getResources().getDimensionPixelSize(x);} catch (Exception e1) {e1.printStackTrace();}return statusBarHeight;}
}

我生疏一点的方法我都会去写上注释这样看来 也比较轻松。

下面 我们开始绘制 我们的表面的浮层view了

GuideView
package com.newbieguide;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.widget.RelativeLayout;import java.util.List;/*** Created by nzx on 2016/9/2.* 我们实现浮层指引view的业务代码逻辑的实现*/
public class GuideView extends RelativeLayout {private int mBgColor = 0xb2000000;private float mStrokeWidth;private Paint mPaint;private Bitmap mBitmap;private RectF mBitmapRect;private Canvas mCanvas;private List<HoleBean> mHoleList;private PorterDuffXfermode pdf;public GuideView(Context context) {super(context);init();}public GuideView(Context context, AttributeSet attrs) {super(context, attrs);init();}public GuideView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {pdf = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);mPaint = new Paint();mPaint.setAntiAlias(true);mPaint.setColor(mBgColor);mPaint.setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter.Blur.INNER));mBitmapRect = new RectF();setClickable(true);setWillNotDraw(false);}public void setDate(List<HoleBean> holeList) {mHoleList = holeList;if (mHoleList != null && !mHoleList.isEmpty()) {for (HoleBean hole : mHoleList) {mBitmapRect.union(hole.getRectF());}}mStrokeWidth = Math.max(Math.max(mBitmapRect.left, mBitmapRect.top), Math.max(ScreenUtils.getScreenWidth(getContext()) -mBitmapRect.right, ScreenUtils.getScreenHeight(getContext()) - mBitmapRect.bottom));if (mBitmapRect.width() > 0 && mBitmapRect.height() > 0) {mBitmap = Bitmap.createBitmap((int) mBitmapRect.width(), (int) mBitmapRect.height(), Bitmap.Config.ARGB_8888);} else {mBitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);throw new UnsupportedOperationException("需要高亮的view尚未加载完,请调整适当的时机或者延迟");}mCanvas = new Canvas(mBitmap);mCanvas.drawColor(mBgColor);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (mHoleList != null && mHoleList.size() > 0) {mPaint.setXfermode(pdf);mPaint.setStyle(Paint.Style.FILL);for (HoleBean hole : mHoleList) {RectF rectF = hole.getRectF();rectF.offset(-mBitmapRect.left, -mBitmapRect.top);switch (hole.getType()) {case HoleBean.TYPE_CIRCLE:mCanvas.drawCircle(rectF.centerX(), rectF.centerY(), hole.getRadius(), mPaint);break;case HoleBean.TYPE_RECTANGLE:mCanvas.drawRect(rectF, mPaint);break;case HoleBean.TYPE_OVAL:mCanvas.drawOval(rectF, mPaint);break;}}canvas.drawBitmap(mBitmap, mBitmapRect.left, mBitmapRect.top, null);//绘制剩余空间的矩形mPaint.setXfermode(null);mPaint.setStyle(Paint.Style.STROKE);mPaint.setStrokeWidth(mStrokeWidth + 0.1f);canvas.drawRect(fillRect(mBitmapRect), mPaint);}}private RectF fillRect(RectF rectF) {RectF fillRect = new RectF();fillRect.left = rectF.left - mStrokeWidth / 2;fillRect.top = rectF.top - mStrokeWidth / 2;fillRect.right = rectF.right + mStrokeWidth / 2;fillRect.bottom = rectF.bottom + mStrokeWidth / 2;return fillRect;}public void recycler() {if (mBitmap != null) {mBitmap.recycle();mBitmap = null;}}}

浮层view 的一些封装的对象类

HoleBean
package com.newbieguide;import android.graphics.RectF;
import android.view.View;/*** Created by nzx on 2016/9/2.*改变原有的对象类   ,覆盖在原有层上面的表面view*/
public class HoleBean {public static final int TYPE_CIRCLE = 0; //圆public static final int TYPE_RECTANGLE = TYPE_CIRCLE + 1;   //长方形public static final int TYPE_OVAL = TYPE_RECTANGLE + 1;   //椭圆private View mHole;private int mType;public HoleBean(View hole, int type) {this.mHole = hole;this.mType = type;}//获得我们需要绘制的浮层view 宽,高public int getRadius() {return mHole != null ? Math.min(mHole.getWidth(), mHole.getHeight()) / 2 : 0;}public RectF getRectF() {RectF rectF = new RectF();if (mHole != null) {int[] location = new int[2];mHole.getLocationOnScreen(location);rectF.left = location[0];rectF.top = location[1];rectF.right = location[0] + mHole.getWidth();rectF.bottom = location[1] + mHole.getHeight();}return rectF;}public int getType() {return mType;}}

下面就是我们怎么去设置浮层view的管理者类咯,这里对于我们来说就比较重要,想要什么样式,点击事件,时间的回调,什么字的那个操作都需要在这边进行修改。

 NewbieGuide
package com.newbieguide;import android.app.Activity;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;import java.util.ArrayList;
import java.util.List;/*** Created by nzx on 2016/9/2.* 新的页面层*/
public class NewbieGuide {public static final int CENTER = 0;private boolean mEveryWhereTouchable = true;private OnGuideChangedListener mOnGuideChangedListener;private List<HoleBean> mHoleList;private Activity mActivity;private GuideView mGuideView;private FrameLayout mParentView;public NewbieGuide(Activity activity) {init(activity);}//初始化我们的整个视图private NewbieGuide init(Activity activity) {mActivity = activity;mParentView = (FrameLayout) mActivity.getWindow().getDecorView();mGuideView = new GuideView(mActivity);mHoleList = new ArrayList<>();return this;}//添加 我们高亮view的 视图  对象public NewbieGuide addHighLightView(View view, int type) {HoleBean hole = new HoleBean(view, type);mHoleList.add(hole);return this;}//蒙版提示图标public NewbieGuide addIndicateImg(int id, int offsetX, int offsetY) {ImageView arrowImg = new ImageView(mActivity);arrowImg.setImageResource(id);mGuideView.addView(arrowImg, getLp(offsetX, offsetY));return this;}//   蒙版提示的消息public NewbieGuide addMessage(String msg, int offsetX, int offsetY) {mGuideView.addView(generateMsgTv(msg), getLp(offsetX, offsetY));return this;}//蒙版提示的消息文本public NewbieGuide addKnowTv(String text, int offsetX, int offsetY) {mGuideView.addView(generateKnowTv(text), getLp(offsetX, offsetY));return this;}//蒙版提示的消息文本的显示位置public NewbieGuide addMsgAndKnowTv(String msg, int offsetY) {mGuideView.addView(generateMsgAndKnowTv(msg), getLp(CENTER, offsetY));return this;}//生成提示文本private TextView generateMsgTv(String msg) {TextView msgTv = new TextView(mActivity);msgTv.setText(msg);msgTv.setTextColor(0xffffffff);msgTv.setTextSize(15);//设置文本的行距间距msgTv.setLineSpacing(ScreenUtils.dpToPx(mActivity, 5), 1f);//文本的相对位置msgTv.setGravity(Gravity.CENTER);return msgTv;}//生成我知道了文本private TextView generateKnowTv(String text) {TextView knowTv = new TextView(mActivity);knowTv.setTextColor(0xffffffff);knowTv.setTextSize(15);knowTv.setPadding(ScreenUtils.dpToPx(mActivity, 15), ScreenUtils.dpToPx(mActivity, 5), ScreenUtils.dpToPx(mActivity, 15),ScreenUtils.dpToPx(mActivity, 5));knowTv.setBackgroundResource(R.drawable.solid_white_bg);knowTv.setText(text);knowTv.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(mActivity,"继续下一个动画",Toast.LENGTH_LONG).show();remove();}});return knowTv;}private TextView generateKnowTv1(String text) {TextView knowTv1 = new TextView(mActivity);knowTv1.setTextColor(0xffffffff);knowTv1.setTextSize(15);knowTv1.setPadding(ScreenUtils.dpToPx(mActivity, 15), ScreenUtils.dpToPx(mActivity, 5), ScreenUtils.dpToPx(mActivity, 15),ScreenUtils.dpToPx(mActivity, 5));knowTv1.setBackgroundResource(R.drawable.solid_white_bg);knowTv1.setText(text);knowTv1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {remove();}});return knowTv1;}//生成提示文本和我知道了文本private LinearLayout generateMsgAndKnowTv(String msg) {LinearLayout container = new LinearLayout(mActivity);container.setOrientation(LinearLayout.VERTICAL);container.setGravity(Gravity.CENTER_HORIZONTAL);LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);container.addView(generateMsgTv(msg), lp);lp.topMargin = ScreenUtils.dpToPx(mActivity, 10);container.addView(generateKnowTv("就你TM话多"), lp);return container;}//生成布局参数private RelativeLayout.LayoutParams getLp(int offsetX, int offsetY) {RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);//水平方向if (offsetX == CENTER) {lp.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);} else if (offsetX < 0) {lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);lp.rightMargin = -offsetX;} else {lp.leftMargin = offsetX;}//垂直方向if (offsetY == CENTER) {lp.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);} else if (offsetY < 0) {lp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);lp.bottomMargin = -offsetY;} else {lp.topMargin = offsetY;}return lp;}public void show() {int paddingTop = ScreenUtils.getStatusBarHeight(mActivity);mGuideView.setPadding(0, paddingTop, 0, 0);mGuideView.setDate(mHoleList);mParentView.addView(mGuideView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));if (mOnGuideChangedListener != null) mOnGuideChangedListener.onShowed();if (mEveryWhereTouchable) {mGuideView.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {remove();return false;}});}}public void remove() {if (mGuideView != null && mGuideView.getParent() != null) {mGuideView.recycler();((ViewGroup) mGuideView.getParent()).removeView(mGuideView);if (mOnGuideChangedListener != null) {mOnGuideChangedListener.onRemoved();}}}public NewbieGuide setEveryWhereTouchable(boolean everyWhereTouchable) {mEveryWhereTouchable = everyWhereTouchable;return this;}public void setOnGuideChangedListener(OnGuideChangedListener onGuideChangedListener) {this.mOnGuideChangedListener = onGuideChangedListener;}//浮层显示后的回调public interface OnGuideChangedListener {void onShowed();void onRemoved();}}

下面这个类 我们就实现了 一个相关的点击等时间了 比如怎么设置 高亮区,我们的按钮回调等,像是我们需要很多自定义操作都在这里可以实现

NewbieGuideManager
package com.newbieguide;import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Handler;
import android.view.View;
import android.widget.Toast;/*** Created by nzx on 2016/9/2.* 新的指引页面管理者*/
public class NewbieGuideManager {static final String TAG = "newbie_guide";public static final int TYPE_LIST = 0;// listpublic static final int TYPE_COLLECT = 1;// 收藏Activity mActivity;SharedPreferences sp;    NewbieGuide mNewbieGuide;int mType;public NewbieGuideManager(Activity activity, int type) {mNewbieGuide = new NewbieGuide(activity);sp = activity.getSharedPreferences(TAG, Activity.MODE_PRIVATE);mActivity = activity;mType = type;}//添加 我们高亮view的 视图public NewbieGuideManager addView(View view, int shape) {mNewbieGuide.addHighLightView(view, shape);return this;}public void show() {show(0);}public void show(int delayTime) {SharedPreferences.Editor editor = sp.edit();editor.putBoolean(TAG + mType, false);editor.apply();new Handler().postDelayed(new Runnable() {@Overridepublic void run() {switch (mType) {case TYPE_LIST:mNewbieGuide.setEveryWhereTouchable(false).addIndicateImg(R.drawable.left_arrow, ScreenUtils.dpToPx(mActivity,60), ScreenUtils.dpToPx(mActivity, 110)).addMsgAndKnowTv("这个listview滚动到item6后出现新手引导浮层,\n只有点击我知道啦才会想消失",-ScreenUtils.dpToPx(mActivity, 250)).show();Toast.makeText(mActivity,"辣鸡",Toast.LENGTH_LONG).show();break;case TYPE_COLLECT:mNewbieGuide.addIndicateImg(R.drawable.right, ScreenUtils.dpToPx(mActivity, -70), ScreenUtils.dpToPx(mActivity,50)).addMsgAndKnowTv("写了一个测试的,随便点击哪里都可以\n废话就不那么多了,你们看看吧", ScreenUtils.dpToPx(mActivity, 150)).show();break;}}}, delayTime);}public void showWithListener(int delayTime, NewbieGuide.OnGuideChangedListener onGuideChangedListener) {mNewbieGuide.setOnGuideChangedListener(onGuideChangedListener);show(delayTime);}/*** 判断新手引导也是否已经显示了*/public static boolean isNeverShowed(Activity activity, int type) {return activity.getSharedPreferences(TAG, Activity.MODE_PRIVATE).getBoolean(TAG + type, true);}}

下面 就开始写我们的listview列表了,这个都很熟悉了 适配器 布局item 都是轻车熟路了 布局我就不贴了 后面可以拿demo看

ListAdapter
package com.newbieguide;import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;import java.util.List;/*** Created by nzx on 2016/9/2.*/
class ListAdapter extends BaseAdapter {private List<String> mList;private LayoutInflater inflater;private Context context;public ListAdapter(List<String> list,Context context) {mList = list;this.context = context;this.inflater = LayoutInflater.from(context);}@Overridepublic int getCount() {return mList != null ? mList.size() : 0;}@Overridepublic Object getItem(int position) {return mList != null ? mList.get(position) : null;}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {final ViewHolder holder;if(convertView == null) {holder = new ViewHolder();convertView = View.inflate(context,R.layout.item, null) ;holder.logo = (ImageView) convertView.findViewById(R.id.logo);holder.item = (TextView) convertView.findViewById(R.id.details);convertView.setTag(holder);} else {holder = (ViewHolder) convertView.getTag();}holder.item.setText(mList.get(position).toString());return convertView;}
}class ViewHolder {ImageView logo;TextView item;
}

下面的MainActivity 实现的逻辑 就是第一次一进来app
我们就实现 浮层view ,还有一些关于 listview的相关操作

package com.newbieguide;import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;import java.security.KeyStore;
import java.util.ArrayList;
import java.util.List;public class MainActivity extends Activity implements AbsListView.OnScrollListener {private ImageView mCollect;private TextView mTitleTv;private ListView mListView;private List<String> mList;private boolean isShow;SharedPreferences sp;private boolean isFirst = false;//是否第一次打开Appprivate Handler handler = new Handler();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);init();initData();}private void initData(){sp= getSharedPreferences("WelcomeActivity", 0);isFirst = sp.getBoolean("isFirst",true);//判断是否第一次打开App,是的话跳转到引导页,否则跳转到主页if (isFirst) {handler.postDelayed(new Runnable() {@Overridepublic void run() {/**  if (NewbieGuideManager.isNeverShowed(MainActivity.this, NewbieGuideManager.TYPE_COLLECT)) {new NewbieGuideManager(MainActivity.this, NewbieGuideManager.TYPE_COLLECT).addView(mCollect, HoleBean.TYPE_CIRCLE).addView(mTitleTv,HoleBean.TYPE_RECTANGLE).show();}  */onWindowFocusChanged(true);}}, 550);SharedPreferences.Editor editor = sp.edit();editor.putBoolean("isFirst", false);editor.commit();} else {handler.postDelayed(new Runnable() {@Overridepublic void run() {onWindowFocusChanged(false);}}, 2000);}}private void init() {mCollect = (ImageView) findViewById(R.id.collect);mTitleTv = (TextView) findViewById(R.id.title);mListView = (ListView) findViewById(R.id.list);mList = new ArrayList<>();for (int i = 0; i < 50; i++) {mList.add("Item:" + i);}mListView.setAdapter(new ListAdapter(mList,getApplicationContext()));mListView.setOnScrollListener(this);}@Overrideprotected void onResume() {super.onResume();}/**如果刚启动Activity时就要计算这些数据,最好在 onWindowFocusChanged  函数中进行,否则得到的某些数据可能是错误的,比如,应用区域高宽的获取  */@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {}@Overridepublic void onScroll(final AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {if(firstVisibleItem >= 6 && NewbieGuideManager.isNeverShowed(this, NewbieGuideManager.TYPE_LIST) && !isShow) {isShow = true;mListView.smoothScrollToPosition(6);mListView.postDelayed(new Runnable() {@Overridepublic void run() {mListView.setSelection(6);mListView.post(new Runnable() {@Overridepublic void run() {new NewbieGuideManager(MainActivity.this, NewbieGuideManager.TYPE_LIST).addView(view.getChildAt(0).findViewById(R.id.logo), HoleBean.TYPE_RECTANGLE).show();}});}}, 200);}}@Overrideprotected void onDestroy() {super.onDestroy();//todo 下面代码需要删掉/** SharedPreferences.Editor editor = getSharedPreferences("newbie_guide", MODE_PRIVATE).edit();editor.putBoolean("newbie_guide" + NewbieGuideManager.TYPE_LIST, true);editor.putBoolean("newbie_guide" + NewbieGuideManager.TYPE_COLLECT, true);editor.apply();   */}public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if(NewbieGuideManager.isNeverShowed(this, NewbieGuideManager.TYPE_COLLECT)){
new NewbieGuideManager(this, NewbieGuideManager.TYPE_COLLECT).addView(mCollect, HoleBean.TYPE_CIRCLE).addView(mTitleTv, HoleBean.TYPE_RECTANGLE).show(); } }}

这里的逻辑都在 ui操作里面 我们操作过了app 就改变布尔值 来 通过

onWindowFocusChanged(true或者false)来决定我们是不是需要 在去拉起浮层view。
new NewbieGuideManager(this, NewbieGuideManager.TYPE_COLLECT).addView(mCollect, HoleBean.TYPE_CIRCLE).addView(mTitleTv,HoleBean.TYPE_RECTANGLE).show();

这个方法 我们可以觉得显示view的对象,样式,和我们需要显示的高亮区域等。
通过这个 能对 view 和轻量级存储,listview 像素计算 有不错的进步的。
大家有什么疑问 欢迎大家 来群 166120952 互相伤害。
demo 下载链接 :http://download.csdn.net/detail/ningzhouxu/9620324

实现app第一次安装浮层引导View!相关推荐

  1. 国行iphone第一次安装APP网络状况

    国行手机第一次安装APP,会有请求网络权限的一个弹框出现,在这期间APP是没有任何网络连接的. 想必大部分APP的需求和这个逻辑有冲突. 先推荐一个链接:http://www.cocoachina.c ...

  2. APP第一次走引导页面的方法

    很多时候APP需要在用户安装后只在第一次启动显示引导页面. 代码 在AppDelegate.m中,进行判断,在其他页面也可以判断 if (![[NSUserDefaultsstandardUserDe ...

  3. 【Android 小功能】启动 App 时实现启动页、引导页功能,并且只在第一次启动 App 时跳入引导页面

    [Android]如何实现启动APP时引导页.欢迎页功能之(一)引导页功能的实现 [Android]如何实现启动APP时引导页.欢迎页功能设置之(二)设置只在第一次启动APP时跳入引导界面

  4. MacBook Air 2014 安装NVME硬盘并纯UEFI安装和引导Win7

    前言: 本文是关于在苹果笔记本上安装NVME固态硬盘.纯UEFI安装及引导win7的实践,供电脑爱好者参考. 手里有一台MacBook Air(MBA) 2014,256G,跟现在的笔记本比较,性能肯 ...

  5. android 点击图标重启,Android应用第一次安装成功点击“打开”后Home键切出应用后再点击桌面图标返回导致应用重启问题的解决方法...

    Android应用第一次安装成功点击"打开"后Home键切出应用后再点击桌面图标返回导致应用重启问题的解决方法 if((getIntent().getFlags() & I ...

  6. Android 系统(78)---《android framework常用api源码分析》之 app应用安装流程

    <android framework常用api源码分析>之 app应用安装流程 <android framework常用api源码分析>android生态在中国已经发展非常庞大 ...

  7. 分析APP的安装流程 API29

    先总结一下安装流程,以及比较重要的类 PackageInstallerActivity.java: 在文件管理器里点击apk后就会调用该类,主要用于显示要安装的apk的一些权限信息. InstallA ...

  8. 致第一次安装RIME的你

    转载自百度RIME吧,作者:半月湾C  原帖地址:http://tieba.baidu.com/p/3288634121 序言 很喜欢小狼毫输入法,喜欢他的简洁,美观以及超强悍的个人定制功能.关于 R ...

  9. 黑苹果放html5卡,小白第一次安装黑苹果,然后卡代码,别着急,教你一个通用步骤,一个一个排查,大部分是可以解决的,毕竟安装不是最难的一个步骤...

    总所周知 如果安装黑苹果出现问题了 问题肯定是出现在EFI文件 当然也有少部分是你的电脑硬件问题 今天的教程主要针对前者 有卡代码的兄弟 打开你的EFI文件夹吧 小白今天教你如何给你的EFI治病 有病 ...

最新文章

  1. HDU4825 Xor Sum —— Trie树
  2. 矩阵的特征值、特征向量及其代码求解实现
  3. C++函数指针 学习笔记
  4. java jdbc脚本_关于java:使用MySQL和JDBC运行.sql脚本
  5. JAVA——GZIP压缩与解压缩
  6. 编写java程序的三步骤_帮助Java小白涨知识的教程(三)(运行HelloWorld程序)
  7. 爬取了BAT等一线大厂近10000+招聘需求,总结出3-5年+Java开发的高频技术需求
  8. 使用 Typescript 踩 react-redux 的坑
  9. dmol3给定关键字不在字典中_一日一技:举例说明python中的map()方法
  10. [hdu 1003] Max Sum
  11. 骑士php授权,骑士人才系统伪静态设置教程
  12. sudo su与su的区别
  13. 灌篮青春完结篇----灌篮.青春
  14. Java的长整型Long/long后面的数字什么情况下必须加L?
  15. 服务器虚拟化专用ovf模板,Vmware虚拟机备份、OVF模板
  16. 【自学编程】自己写小例子的经验
  17. Snmp学习总结系列
  18. Ubuntu 安装中文man手册
  19. el-input 输入框禁止输入特殊字符
  20. 《Java 开发手册》读后感

热门文章

  1. 活动预告 | NUC Nebula 用户大会 2021,欢迎莅临 Pulsar 展台
  2. python尼姆游戏_python实现聪明的尼姆游戏(人机对战)
  3. 人间炼狱,人性在哪儿---------------- 二十年穿铁衣取胆,母熊含泪杀子并自杀
  4. mac加密_如何加密Mac的Time Machine备份
  5. 2018(农历年)封山之作,和我一起嚼烂Git(两万字长文)
  6. 微信小程序获取用户手机号存数据库,前后端都有《Java后台版 》
  7. 逻辑回归分析实训----乳腺癌肿瘤预测
  8. 引爆5G市场,场景为王?
  9. 程序员被PUA的一天有多可怕......35 岁,真的是职场荣枯线吗?
  10. c语言源代码下载TGAM,2018年江西理工大学C语言程序设计竞赛(初级组)一