通过不间断的公司项目发现,在Android中使用透明指示器的地方很多.
以往自己都是通过继承dialog来实现的透明指示器,当然,为了研究更多东东.这些天特意写出了另外一种实现方式.
其实也没有什么特别之处,只是在看源码时偶然想到才实现的.
还是先上效果图片吧,有道是有图有真相:
上面就是效果截图,当然了,这里只涉及到了一种效果.说好了,只是为了研究,顺便分享.
从布局开始:
<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:background="@drawable/bg_main"
android:orientation="vertical"
tools:context=".MainActivity" >
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onAction"
android:text="孤独的指示器" />
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onAction"
android:text="有背景的指示器" />
<Button
android:id="@+id/button3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onAction"
android:text="有背景,有说明书的指示器" />
<Button
android:id="@+id/button4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onAction"
android:text="没有背景,有说明书的指示器" />
<Button
android:id="@+id/button5"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onAction"
android:text="只能自动消失的指示器" />
</LinearLayout>
布局很简单,就几个button而已,添加了事件.
然后,就是最主要的了,采用单例模式实现的指示器类,通过WindowManager实现的透明指示器类,如下
package com.napoleonbai.view;
import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.napoleonbai.activity.R;
/**
* 自定义NBIndicatorView来实现弹出透明指示器
*
* @author NapoleonBai
*
*/
public class NBIndicatorView extends View {
private NBIndicatorView(Context context) {
super(context);
mContext = context;
initView();
}
private NBIndicatorView(Context context, AttributeSet attrs) {
super(context, attrs);
}
private NBIndicatorView(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/** 定义NBindicatorView单例对象 */
private static NBIndicatorView mNBIndicatorView;
private static Context mContext;
/**
* 单例方法,构建NBIndicatorView对象
*
* @param mContext
* @return
*/
private static NBIndicatorView instance(Context mContext) {
if (mNBIndicatorView == null) {
mNBIndicatorView = new NBIndicatorView(mContext);
}
return mNBIndicatorView;
}
/** 布局的内边距 */
private final int LAYOUTPADDING = 50;
/** 设置是否显示文字 缺省为false */
private static boolean NBIsShowStr = false;
/** 显示的提示文字 */
private static String NBIndicatorStr = "";
/** 指示器提示文字大小 */
private static int NBIndicatorStrSize;
/** 指示器提示文字颜色 缺省为黑色 */
private static int NBIndicatorStrColor = Color.BLACK;
/** 指示图片名称 */
private static int NBIndicatorImageName = -1;
/** 是否需要自定义指示器 缺省为false */
private static boolean NBIsCustomIndicator = false;
/** 背景资源ID */
private static int NBLayoutResID = R.drawable.indicator_layout_corner;
/** 是否允许触摸屏幕消失 */
private static boolean NBIsClick = false;
/** WindowManager对象 */
private static WindowManager NBWindowManager;
/** WindowManager.LayoutParams对象,用来设置对象参数 */
private static android.view.WindowManager.LayoutParams NBLP;
/** 指示器布局对象 */
private static LinearLayout NBLinearLayout;
/** 是否需要背景颜色 默认是需要 */
private static boolean NBIsNeedBgColor = true;
/** 定义进度条控件 */
private static ProgressBar NBProgressBar;
/** 透明指示器是否已经显示 缺省为false:没有显示 */
private static boolean isShow = false;
/** 提示文字控件 */
private static TextView NBTextView;
/** 布局参数设置对象 */
private static LayoutParams NBLayoutParams;
/**
* 初始化布局视图
*/
private void initView() {
NBWindowManager = (WindowManager) mContext
.getSystemService(Context.WINDOW_SERVICE);
// 设置布局
NBLinearLayout = new LinearLayout(mContext);
NBLinearLayout.setOrientation(LinearLayout.VERTICAL);
NBLinearLayout.setGravity(Gravity.CENTER);
// 设置内边距,这里不提供自定义内边距
NBLinearLayout.setPadding(LAYOUTPADDING, LAYOUTPADDING, LAYOUTPADDING,
LAYOUTPADDING);
NBLayoutParams = new LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
;
NBLinearLayout.setLayoutParams(NBLayoutParams);
// 创建进度条对象实例
NBProgressBar = new ProgressBar(mContext);
NBProgressBar.setLayoutParams(NBLayoutParams);
NBLinearLayout.addView(NBProgressBar);
NBTextView = new TextView(mContext);
NBTextView.setLayoutParams(NBLayoutParams);
NBTextView.setSingleLine();
NBTextView.setGravity(Gravity.CENTER_HORIZONTAL);
NBLinearLayout.addView(NBTextView);
// 如果有文字提示才设置该控件,否则不设置
if (NBIsShowStr) {
NBTextView.setVisibility(GONE);
}
// 设置WindowManager的参数
NBLP = new android.view.WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG,
WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON,
WindowManager.LayoutParams.FORMAT_CHANGED);
}
/**
* 定义的触摸事件,用于点击屏幕,指示器消失
*/
private static OnTouchListener NBOntouchListener = new OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
dismiss();
return true;
}
};
/**
* 设置其他参数
*
* @param isCustomImage
* 是否需要自定义指示器
* @param indicatorImage
* 指示器图片Res eg:R.drawable.ic_luncher,如果isCustomImage=false,就设置为-1
*/
public static void setIndicatorImage(boolean isCustomImage,
int indicatorImage) {
NBIsCustomIndicator = isCustomImage;
if (NBIndicatorImageName != indicatorImage) {
NBIndicatorImageName = indicatorImage;
}
}
/**
* 设置是否需要显示提示文字
*
* @param isShowStr
*/
public static void setIsShowStr(boolean isShowStr) {
NBIsShowStr = isShowStr;
updateTextView();
}
/**
* 设置提示文字
*
* @param str
*/
public static void setStr(String str) {
NBIndicatorStr = str;
updateTextView();
}
/**
* 更新提示文字
*/
private static void updateTextView() {
if (NBTextView != null) {
NBTextView.setText(NBIndicatorStr);
}
}
/**
* 通过传入的资源ID来获取提示文字
*
* @param strResId
*/
public static void setStr(int strResId) {
NBIndicatorStr = mContext.getResources().getString(strResId);
}
/**
* 设置提示文字大小
*
* @param strSize
*/
public static void setStrSize(int strSize) {
NBIndicatorStrSize = strSize;
}
/**
*
* @param strColor
* 颜色值,eg:Color.BLACK
*/
public static void setStrColor(int strColor) {
NBIndicatorStrColor = strColor;
}
/**
*
* 是否需要背景颜色
*
* @param isNeedBgColor
* true or false:true为需要,缺省为true
* @param bgResId
* 设置isNeedBgColor=true的时候,调用此方法 true:设置引用的drawable
* ID<drawable可参照R.drawable
* .indicator_layout_corner.xml.当然如果想自定义背景
* ,那么就传入自己写的那个,否则,使用R.drawable .indicator_layout_corner.xml>
*/
public static void setIsNeedBgColor(boolean isNeedBgColor, int bgResId) {
NBIsNeedBgColor = isNeedBgColor;
if (NBIsNeedBgColor) {
NBLayoutResID = bgResId;
}
}
/**
* 是否需要背景颜色
*
* @param isNeedBgColor
* 设置为false的时候调用
*/
public static void setIsNeedBgColor(boolean isNeedBgColor) {
NBIsNeedBgColor = isNeedBgColor;
}
/**
* 设置点击屏幕消失,设置true,点击消失,反之则不能点击消失
*
* @param isDismiss
*/
public static void setClickScreenDismiss(boolean isClick) {
NBIsClick = isClick;
}
/**
* 根据设置好的信息设置需要参数
*/
private static void setParmas() {
if (NBIsNeedBgColor) {
// 设置圆角边框,默认设置的,毋须更改,更改请移步到R.drawable.indicator_layout_corner
NBLinearLayout.setBackgroundResource(NBLayoutResID);
} else {
NBLinearLayout.setBackgroundResource(Color.TRANSPARENT);
}
if (NBIsShowStr) {
// 这里这样判断,主要是为了支持不同的显示方式之间的切换,下同
NBTextView.setVisibility(View.VISIBLE);
NBTextView.setText(NBIndicatorStr);
NBTextView.setTextColor(NBIndicatorStrColor);
} else {
NBTextView.setVisibility(View.GONE);
}
if (NBIndicatorStrSize > 0) {
NBTextView.setTextSize(NBIndicatorStrSize);
}
if (NBIsCustomIndicator) {
NBProgressBar.setIndeterminateDrawable(mContext.getResources()
.getDrawable(NBIndicatorImageName));
}
if (NBIsClick) {
NBLinearLayout.setOnTouchListener(NBOntouchListener);
}
}
/**
* 提供show()方法,设置显示指示器
*/
public static void show(Context mContext) {
if (!isShow) {
instance(mContext);
setParmas();
NBWindowManager.addView(NBLinearLayout, NBLP);
isShow = true;
}
}
/**
* 移除透明指示器方法:dismiss()
*/
public static void dismiss() {
if (isShow) {
NBWindowManager.removeView(NBLinearLayout);
NBIsShowStr = false;// 每次重置,恢复到缺省值
NBIsCustomIndicator = false;
NBIsNeedBgColor = true;
isShow = false;
}
}
}
在代码中,说明我已经指出了,所以,过多的文字叙述,我觉得就不必要了.
现在的话,应该指出上面提到的几个drawable文件,首先,是我们的自定义圆角背景:indicator_layout_corner.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<solid android:color="#77FFFFFF" />
<corners android:radius="10dp" />
</shape>
这个文件主要就是填充指示器的背景,这里设置为半透明状,可根据自身需要进行修改;
然后就是指示器,指示器采用的是ProgressBar,所以这里就很简单的进行了处理了一下:
1.nb_loading_main.xml
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="360" >
<shape
android:innerRadiusRatio="3"
android:shape="ring"
android:thicknessRatio="8"
android:useLevel="false" >
<gradient
android:centerColor="#FF00FFFF"
android:centerY="0.50"
android:endColor="#FFFFFF00"
android:startColor="#FFFF0000"
android:type="sweep"
android:useLevel="false" />
</shape>
</rotate>
上面这个文件主要是以修改进度条颜色来实现,上述图片就是采用的这个xml来实现;
2.nb_loading_main1.xml
<?xml version="1.0" encoding="utf-8"?>
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/loading_icon"
android:pivotX="50%"
android:pivotY="50%" />
main1文件主要是通过对loading_icon图片的旋转来进行实现
当然了,这里提供的两种方式皆可.
然后再看MainActivity类中的实现吧.这个类指出来怎样调用,怎样设置
package com.napoleonbai.activity;
import com.napoleonbai.view.NBIndicatorView;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.View;
/**
* 测试界面类
*
* @author NapoleonBai
*
*/
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initNBIndicatorView();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
/**
* 进行初始化设置 因为指示器采用的是单例模式,所以很多相同的设置都可以在同一个地方进行一并设置,不需要重复设置
*/
private void initNBIndicatorView() {
// 如果不设置,就采用系统的默认样式
NBIndicatorView.setIndicatorImage(true, R.drawable.nb_loading_main);
// 这是另外一种
// NBIndicatorView.setIndicatorImage(true, R.drawable.nb_loading_main1);
}
/**
* 按钮点击事件方法
*
* @param v
*/
public void onAction(View v) {
// 点击外部可以取消,如果不设置,则不能取消
NBIndicatorView.setClickScreenDismiss(true);
switch (v.getId()) {
case R.id.button1:
// 不需要显示背景颜色
NBIndicatorView.setIsNeedBgColor(false);
NBIndicatorView.show(this);
break;
case R.id.button2:
NBIndicatorView.show(this);
break;
case R.id.button3:
NBIndicatorView.setStrColor(Color.BLUE);
// 需要显示提醒文字
NBIndicatorView.setIsShowStr(true);
NBIndicatorView.setStr("关爱小白杨");
NBIndicatorView.show(this);
break;
case R.id.button4:
NBIndicatorView.setStrColor(Color.GREEN);
NBIndicatorView.setStr("爱护小白杨");
NBIndicatorView.setIsShowStr(true);
// 不需要显示背景颜色
NBIndicatorView.setIsNeedBgColor(false);
NBIndicatorView.show(this);
break;
case R.id.button5: {
// 点击外部,不能取消指示器
NBIndicatorView.setClickScreenDismiss(false);
NBIndicatorView.setStr("准备好:马上就开始了");
NBIndicatorView.setIsShowStr(true);
NBIndicatorView.setStrColor(Color.MAGENTA);
NBIndicatorView.show(this);
handler.postDelayed(runnable, TIME); // 每隔2s执行
}
break;
default:
break;
}
}
// 显示文字
private String[] strDatas = new String[] { "小白:你知道吗?", "小杨:什么?",
"小白:小白杨很可爱的", "小杨:真的吗?", "小白:我们回去养一个吧!", "小杨:小白杨=小白羊?",
"小白:喜羊羊/懒羊羊?", "小杨:......", "希望大家都能有收获", "谢谢", "马上就消失了哟", "走了,拜拜" };
// 下标
private int i = 0;
private int TIME = 2000;
Handler handler = new Handler();
Runnable runnable = new Runnable() {
@Override
public void run() {
// handler自带方法实现定时器
try {
handler.postDelayed(this, TIME);
if (i >= strDatas.length) {
NBIndicatorView.dismiss();// 移除指示器
handler.removeCallbacks(runnable);// 停止计时器
return;
}
NBIndicatorView.setStr(strDatas[i]);
i++;
} catch (Exception e) {
e.printStackTrace();
}
}
};
}
上述代码已经给出了比较详细的注释,也说明了怎样调用.因为是采用单例模式实现,所以在同一个项目中最好只采用一种颜色的指示器.