一款App首次安装启动以后一半会有引导用户使用的提示,下面是一个简单的引导界面,此功能实现效果如图,点击屏幕时候引导界面结束,之后每次启动不会出现,除非重新安装。
实现原理:两个Activity,两个自定义View控件
MainActivity
package com.example.bezierdemo;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
public class MainActivity extends Activity {
private SharedPreferences sharedPreferences;
private Boolean isFirstInstall;// 用来纪录用户是否安装后的首次启动
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sharedPreferences = this.getSharedPreferences("lidan", Context.MODE_PRIVATE);
SharedPreferences.Editor s = sharedPreferences.edit();
isFirstInstall=sharedPreferences.getBoolean("isFirstInstall", false);
if(!isFirstInstall){
Toast.makeText(this, "安装后首次启动", 50000).show();
startActivity(new Intent(MainActivity.this, GuidanceActivity.class));
s.putBoolean("isFirstInstall", true);
s.commit();
}else{
Toast.makeText(this, "启动", 50000).show();
}
}
}
其布局只有一个按钮
GuidanceActivity引导界面
package com.example.bezierdemo;
import android.R.bool;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.RelativeLayout;
/*
* 引导界面,一般用于App安装后首次启动引导用户操作的提示
* 此界面由自定义的贝塞尔曲线辅助完成
* 一定要记得注册
* <activity
android:name=".GuidanceActivity"
android:theme="@android:style/Theme.Translucent" />
* */
public class GuidanceActivity extends Activity implements OnClickListener{
private RelativeLayout relativiveLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.guidance_layout);
relativiveLayout=(RelativeLayout)findViewById(R.id.relativiveLayout);
relativiveLayout.setOnClickListener(this);
}
@Override
public void onClick(View v) {
finish();
}
}
布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.example.bezierdemo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id= "@+id/relativiveLayout"
android:background="#b0000000"
>
<!--xmlns:app="http://schemas.android.com/apk/res/com.example.bezierdemo"一定要记得声明,
因为BezierCircleView和BezierView都用到了自定义的属性,如果不声明自定义属性就会报错
设置半透明背景,否则看不到圆形的效果-->
<com.example.bezierdemo.BezierCircleView
xmlns:aa="http://schemas.android.com/apk/res/com.example.bezierdemo"
android:id="@+id/bezierCircleView1"
android:layout_width="100dip"
android:layout_height="150dip"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_launcher" />
<!--BezierView的属性使用:app:center_point="true"设置曲线突出如果是false凹陷
app:end_point="2"线的起始点,0-9 对应九个不同起始方位
line:start_point="3"线的终点位置 0-9 同样对应九个不同方位-->
<com.example.bezierdemo.BezierView
xmlns:line="http://schemas.android.com/apk/res/com.example.bezierdemo"
android:id="@+id/bezierView1"
android:layout_width="30dip"
android:layout_height="50dip"
android:layout_alignRight="@+id/bezierCircleView1"
android:layout_alignTop="@+id/bezierCircleView1"
android:layout_marginRight="85dp"
android:layout_marginTop="81dp"
app:center_point="true"
app:end_point="2"
line:start_point="3" />
<TextView
android:id="@+id/remain_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="@+id/bezierCircleView1"
android:layout_below="@+id/bezierView1"
android:layout_marginRight="41dp"
android:text="点击按钮分享给好友" />
</RelativeLayout>
自定义的View 带箭头的贝塞尔曲线
<span style="font-size:18px;">package com.example.bezierdemo;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
/*
* 自定义的贝塞尔曲线包含箭头
* paint1绘制贝塞尔曲线
* paint2绘制的是箭头
* 绘制原理是九个方位
* */
public class BezierView extends View{
private Paint paint1,paint2;
public static final int LEFT_TOP = 1;
public static final int RIGHT_TOP = 2;
public static final int LEFT_BOTTOM = 3;
public static final int RIGHT_BOTTOM = 4;
public static final int LEFT_CENTER = 5;
public static final int TOP_CENTER = 6;
public static final int RIGHT_CENTER = 7;
public static final int BOTTOM_CENTER = 8;
public static final int CENTER = 9;
private int startPoint = LEFT_TOP;
private int endPiont = RIGHT_BOTTOM;
private boolean centerPoint = true;// 默认向上凸起
public BezierView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView(context, attrs);
}
public BezierView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BezierView(Context context) {
this(context, null, 0);
}
public void initView(Context context, AttributeSet attrs) {
if (attrs != null) {
// 设置自定义的属,在values下建立了attr.xml文件在其中设置属性,BezierView_start_point是起始点方位,
// BezierView_end_point是终点方位,BezierView_center_point是曲线的凹凸设置
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BezierView);
startPoint = a.getInteger(R.styleable.BezierView_start_point, startPoint);
centerPoint = a.getBoolean(R.styleable.BezierView_center_point, centerPoint);
endPiont = a.getInteger(R.styleable.BezierView_end_point, endPiont);
}else{}
paint1 = new Paint();
paint1.setAntiAlias(true);
paint1.setColor(Color.BLACK);
paint2 = new Paint();
paint2.setAntiAlias(true);
paint2.setColor(Color.BLACK);
}
@Override
public void draw(Canvas canvas) {
if(canvas==null)
return;
// 画线-----------
paint1.setStyle(Paint.Style.STROKE);
paint1.setColor(Color.BLACK);
Path path = new Path();
Path path2 = new Path();
changerStartPoint(path, path2);// 起点
changerEndPoint(path, path2);// 终点
canvas.drawPath(path, paint1);// 画出贝塞尔曲线
canvas.drawPath(path2, paint2);
}
/**
* 设置Path的起点
*
* @param path
*/
private void changerStartPoint(Path path, Path path2) {
switch (startPoint) {
case LEFT_TOP:
path.moveTo(0, 0);
if (centerPoint) {
path2.moveTo(getWidth() - getWidth() / 7, getHeight() - getHeight() / 5);
} else {
path2.moveTo(getWidth() - getWidth() / 5, getHeight() - getHeight() / 7 * 2);
}
break;
case LEFT_BOTTOM:
path.moveTo(0, getHeight());
if (centerPoint) {
path2.moveTo(getWidth() - getWidth() / 5, getHeight() / 10);
} else {
path2.moveTo(getWidth() - getWidth() / 5, getHeight() / 3);
}
break;
case LEFT_CENTER:
path.moveTo(0, getHeight() / 2);
break;
case RIGHT_TOP:
path.moveTo(getWidth(), 0);
if (centerPoint) {
path2.moveTo(getWidth() / 10, getHeight() - getHeight() / 5);
} else {
path2.moveTo(getWidth() / 5, getHeight() - getHeight() / 3);
}
break;
case RIGHT_BOTTOM:
path.moveTo(getWidth(), getHeight());
break;
case RIGHT_CENTER:
path.moveTo(getWidth(), getHeight() / 2);
break;
case TOP_CENTER:
path.moveTo(getWidth() / 2, 0);
break;
case BOTTOM_CENTER:
path.moveTo(getWidth() / 2, getHeight());
break;
case CENTER:
path.moveTo(getWidth() / 2, getHeight() / 2);
break;
}
}
/**
* 设置贝塞尔曲线的控制点坐标和终点坐标
*
* @param path
*/
private void changerEndPoint(Path path, Path path2) {
Log.e("", startPoint + " " + endPiont);
switch (endPiont) {
case LEFT_TOP:
if (centerPoint) {
path.quadTo(getWidth() / 4, getHeight() / 2, getWidth(), getHeight() / 2);
} else {
}
break;
case LEFT_BOTTOM:
if (centerPoint) {
// 画曲线
path.quadTo(getWidth() / 2 - getWidth() / 3, getHeight() / 2 - getHeight() / 3, getWidth() / 5, getHeight() - getHeight() / 14);
// 画箭头
path2.quadTo(getWidth() / 5, getHeight(), getWidth() / 5 + getWidth() / 12, getHeight() - getHeight() / 5);
} else {
// 画曲线
path.quadTo(getWidth() / 2 + getWidth() / 3, getHeight() / 2 + getHeight() / 3, getWidth() / 10, getHeight() - getHeight() / 5);
// 画箭头
path2.quadTo(0, getHeight() - getHeight() / 5, getWidth() / 5, getHeight() - getHeight() / 8);
}
break;
case LEFT_CENTER:
path.moveTo(0, getHeight() / 2);
break;
case RIGHT_TOP:
if (centerPoint) {
// 画曲线
path.quadTo(getWidth() / 2 - getWidth() / 3, getHeight() / 2 - getHeight() / 3, getWidth() - getWidth() / 12, getHeight() / 5);
// 画箭头
path2.quadTo(getWidth(), getHeight() / 5, getWidth() - getWidth() / 5, getHeight() / 5 + getHeight() / 10);
} else {
// 画曲线
path.quadTo(getWidth() / 2 + getWidth() / 3, getHeight() / 2 + getHeight() / 3, getWidth() - getWidth() / 12, getHeight() / 5);
// 画箭头
path2.quadTo(getWidth() - getWidth() / 12, 0, getWidth(), getHeight() / 5 * 2);
}
break;
case RIGHT_BOTTOM:
if (centerPoint) {
// 画曲线
path.quadTo(getWidth() / 2 + getWidth() / 3, getHeight() / 2 - getHeight() / 3, getWidth() - getWidth() / 5, getHeight()
- getHeight() / 14);
// 画箭头
path2.quadTo(getWidth() - getWidth() / 5, getHeight(), getWidth() - getWidth() / 5 - getWidth() / 14, getHeight() - getHeight() / 5);
} else {
// 画曲线
path.quadTo(getWidth() / 2 - getWidth() / 3, getHeight() / 2 + getHeight() / 3, getWidth() - getWidth() / 12, getHeight()
- getHeight() / 5);
// 画箭头
path2.quadTo(getWidth(), getHeight() - getHeight() / 5, getWidth() - getWidth() / 5, getHeight() - getHeight() / 8);
}
break;
case RIGHT_CENTER:
path.moveTo(getWidth(), getHeight() / 2);
break;
case TOP_CENTER:
path.moveTo(getWidth() / 2, 0);
break;
case BOTTOM_CENTER:
path.moveTo(getWidth() / 2, getHeight());
break;
case CENTER:
path.moveTo(getWidth() / 2, getHeight() / 2);
break;
}
}
}
</span>
圆形的贝塞尔曲线
<span style="font-size:18px;">package com.example.bezierdemo;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.PorterDuff.Mode;
import android.util.AttributeSet;
import android.view.View;
public class BezierCircleView extends View{
private Paint paint;
private boolean isCircle = true;
private static final int LAYER_FLAGS = Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG
| Canvas.FULL_COLOR_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG;
public BezierCircleView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView(context, attrs);
}
public BezierCircleView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BezierCircleView(Context context) {
this(context, null, 0);
}
public void initView(Context context, AttributeSet attrs) {
if (attrs != null) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BezierCircleView);
isCircle = a.getBoolean(R.styleable.BezierCircleView_is_circle, isCircle);
}
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.BLUE);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
}
@Override
public void draw(Canvas canvas) {
if (canvas == null) {
return;
}
if (isCircle) {
int r = getWidth() > getHeight() ? getHeight() / 2 : getWidth() / 2;
canvas.drawCircle(getWidth() / 2, getHeight() / 2, r, paint);
canvas.saveLayerAlpha(0, 0, 200, 200, 0x20, LAYER_FLAGS);// 新建图层并指定透明度,图层位于栈顶,所以直到restore以前的操作都只作用于此图层
canvas.restore();// 将新建的图层合并到画布上
} else {
canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
}
}
}
</span>
自定义属性 attrr.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 向导箭头属性 -->
<declare-styleable name="BezierView">
<attr name="start_point" format="integer"></attr>
<attr name="center_point" format="boolean"></attr>
<attr name="end_point" format="integer"></attr>
</declare-styleable>
<!-- 向导圆的半径 -->
<declare-styleable name="BezierCircleView">
<attr name="is_circle" format="boolean"></attr>
</declare-styleable>
</resources>