欧亿体育
工作动态
我的位置: 首页 > 工作动态
Android之 双屏异显控制
发布时间:2024-01-13 11:02
  |  
阅读量:
  |  
作者:
欧亿体育

一 简介

1.1 我们用的手机基本上只有一个屏幕,那这里的双屏指的什么呢?其实现在手机都是支持双屏的,我们可以在开发者选项里面来打开这个控制,来看下什么是双屏。

可以打开设置 -> 开发者选项 -> 模拟辅助显示设备来开启副屏显示,还可以选择显示尺寸

 1.2 不过手机上使用双屏场景比较少,更多的用在一些人脸识别支付,或者扫码,刷卡支付这些设备设备上。

主屏用于人脸,扫码,刷卡。

副屏有键盘输入,用于输入金额,查询交易记录这些工作。

比如下面这种团餐机就是典型的双屏支持

 二,双屏程序的实现

2.1 主屏,即扫码屏不用多说,正常的Activity页面。副屏(带键盘)需要借助原生API中的Presentation类

2.2 Presentation是一个特殊的 dialog ,主要的目的是在辅助显示屏上显示内容,Presentation 在创建的时候需要和特定的 Display 相关联。既是Dialog所以在构造函数中传递的 context 必须是一个 activity 的 context。

如下源码可以看出是继承于Dialog的

 2.3 理解了Presentation,那后面开发就容易了,只需要用Activity控制Dialog就可以了。

但到后面你会发现还是想简单了,因为副屏是不能触摸的,这也就造成输入框不能获取焦点,软键盘不能弹出,包括返回键这些都需要通过外设设备来控制。

那这个外设设备就是小数字键盘,其实就是普通键盘的数字区域

2.4 那怎样来监听数字键盘区域的输入呢,这个时候就需要一个key的映射关系。键盘上的按键都是由标准协议的,所以我们只需要找个找个标准的映射关系就可以了。如下图

android原生api提供有键盘事件的类KeyEvent.java,里面是全部的键盘点击事件

 然后我们可以在事件分发里面来监听点击的键盘哪个按键

 再对照下面的code和key关系映射,就可以知道我们按的哪个键了

 三,源码示例

3.1 设置权限,也可以不设置。如果想要Presentation不随主Activity退出,必须加上系统弹框权限


 
 

3.2 自定义Presentation

public class SecondLoginPresentation extends Presentation {

	public SecondLoginPresentation(Context outerContext, Display display) {
		super(outerContext,display);

	}
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.second_screen);

	}
}

3.3 在Acitivty里面显示这个副屏,注意这个地方要先判断是否有副屏

//显示副屏幕
SecondLoginPresentation mPresentation;

private void showDisplay() {
	DisplayManager displayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
	Display[] presentationDisplays = displayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION);
	if (presentationDisplays.length > 0) {
        //判断是否有双屏
        // displays[0] 主屏
        // displays[1] 副屏
		Display display = presentationDisplays[0];

		if (mPresentation == null) {
			mPresentation = new SecondLoginPresentation(this, display);
			try {
				mPresentation.show();
			} catch (WindowManager.InvalidDisplayException e) {
				mPresentation = null;
			}
		}
	}
}

3.4 监听键盘输入,注意这个也只能在Activity里面才能监听到

只需要监听我们需要的按键即可

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
	if (keyListener != null) {
		int action = event.getAction();
		switch (action) {
			case KeyEvent.ACTION_DOWN:

				if (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP) {
					return super.dispatchKeyEvent(event);
				}
				if (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN) {
					return super.dispatchKeyEvent(event);
				}
				if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
					return super.dispatchKeyEvent(event);
				}
				if (event.getKeyCode() == KeyEvent.KEYCODE_MENU) {
					return super.dispatchKeyEvent(event);
				}
				if (event.getKeyCode() == KeyEvent.KEYCODE_HOME) {
					return super.dispatchKeyEvent(event);
				}
				if (event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
					return super.dispatchKeyEvent(event);
				}

				if (event.getKeyCode() == KeyEvent.KEYCODE_F1) {
					keyListener.textSure("功能");
					return true;
				} else if (event.getKeyCode() == KeyEvent.KEYCODE_F2) {
					keyListener.textSure("设置");
					return true;
				} else if (event.getKeyCode() == 111 || event.getKeyCode() == 4) {
					keyListener.textSure("取消");
					return true;
				} else if (event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
					keyListener.textSure("删除");
					return true;
				} else if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
					keyListener.textSure("确认");
					return true;
				} else if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP) {
					keyListener.textSure("上箭头");
					return true;
				} else if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN) {
					keyListener.textSure("下箭头");
					return true;
				} else {
					int unicodeChar = event.getUnicodeChar();
					keyListener.textChange(String.valueOf((char) unicodeChar));
					return true;
				}

		}
	}
	return super.dispatchKeyEvent(event);
}

3.5 SecondLoginPresentation处理键盘事件

@Override
public void textChange(String text) {
    //数字输入
	addTextValue(text);
}

@Override
public void textSure(String value) {
    //除数字之外按键
	switch (value) {
		case "功能":
			break;
		case "设置":
			break;
		case "删除":
			popTextValue();
			break;
		case "取消":
		   
			break;
		case "确认":
		   
			//开始支付逻辑
			//....................................
			break;
		case "上箭头":
			break;
		case "下箭头":
			break;
	}
}

//输入键盘监听-添加
private Stack mNumberStack = new Stack<>();


public void addTextValue(String value) {
	//限制输入数字或者小数点
	if (!Utils.isNumeric(value)) {
		return;
	}

	String moneyString = etInputContent.getText().toString();
	//确保第一位不是.和+
	if ((value.equals(".") || value.equals("+")) && moneyString.length() <= 0) {
		return;
	}
	//确保不输入连续的+
	if (value.equals("+") && moneyString.endsWith("+")) {
		return;
	}
	//确保不是连续小数点
	if (value.equals(".") && moneyString.endsWith(".")) {
		return;
	}
	//确保一个小数点,后面两位
	//获取最后一个加号的索引
	String lastPartString="";
	if (moneyString.length() > 0 && moneyString.contains("+")) {
		lastPartString = moneyString.substring(moneyString.lastIndexOf("+"));
	}else {
		//如果长度小于0表示还没输入过加号,那最后一段就是完整内容
		lastPartString = moneyString;
	}
	if (!value.equals("+") && lastPartString.contains(".") && lastPartString.substring(lastPartString.indexOf(".")).length() > 2) {
		return;
	}
	//确保当前段不包含两个小数点
	if (value.equals(".") && lastPartString.contains(".")) {
		return;
	}

	//限制最大金额-7位
//        if (!TextUtils.isEmpty(moneyString) && moneyString.length() >= 7) {
//            return;
//        }


	//确保第一位不为0
	if (moneyString.length() == 1 && moneyString.startsWith("0") && !value.equals(".")) {
		mNumberStack.clear();
	}

	mNumberStack.push(value);

	showTextValue();
}

//输入键盘监听-删除
public void popTextValue() {
	if (mNumberStack.empty()) {
		return;
	}
	mNumberStack.pop();
	showTextValue();
}

//显示输入内容
public void showTextValue() {
	StringBuilder codeBuilder = new StringBuilder();
	for (String value : mNumberStack) {
		codeBuilder.append(value);
	}
	etInputContent.setText(codeBuilder.toString());

	moneyInputResult();
}

//计算总金额
public void moneyInputResult() {
	String inputString = etInputContent.getText().toString();
	String moneyResult = "";
	if (!TextUtils.isEmpty(inputString)) {
		if (inputString.contains("+")) {
			String[] stringsArray = inputString.split("\\+");
			for (String ss : stringsArray) {
				moneyResult = add(TextUtils.isEmpty(moneyResult) ? "0" : moneyResult, ss);
			}
		} else {
			moneyResult = inputString;
		}
	}
	etMoney.setText(moneyResult);
}

/**
 * 加减法精确计算类
 */

/**
 * 加法
 */
public static String add(String parms1, String param2) {
	return new BigDecimal(parms1).add(new BigDecimal(param2)).toString();
}

四 总结

4.1 Presentation是一个不能触摸的Dialog,所以所有事件要监听外部设备来处理

4.2 Presentation正常情况是随Activity退出的,想要不随Activity退出,需要添加系统弹框权限

4.3 大多情况跟dialog用法没什么区别,主要能了解键盘的映射关系即可,用键盘俩操作页面