ken*_*der 11 android android-layout google-maps-android-api-2
我想在屏幕上显示2个视图 - 一个是相机预览,在顶部,而另一个将显示图像或谷歌地图 - 并且生活在屏幕的底部.
我希望它们之间有一个类似渐变的过渡 - 所以它们之间没有粗糙的边缘.这有可能产生这样的效果吗?
编辑:我想要实现的效果应该是这样的(顶部来自相机预览,而底部应该是地图......):

在iOS上我得到了类似的效果,CameraOverlay显示地图并将图层masp设置为渐变:
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = self.map.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithWhite: 1.0 alpha: 0.0] CGColor], (id)[[UIColor colorWithWhite: 1.0 alpha: 1.0] CGColor], nil];
gradient.startPoint = CGPointMake(0.5f, 0.0f);
gradient.endPoint = CGPointMake(0.5f, 0.5f);
self.map.layer.mask = gradient;
Run Code Online (Sandbox Code Playgroud)
这是可能的,但可能有点复杂。为了简单起见,我将实现此目的的核心代码放在答案中。正如已经指出的,您需要两个视图来执行此操作,一个“位于”另一个视图之上。“较低”的应该是 SurfaceView,由地图 API 驱动。“较高”的应该显示相机图像在其上淡出。
编辑:正如 mr_archano 指出的那样,API(现在)已定义为如果没有 SurfaceView,相机将不会发送预览数据。呵呵,这就是进步的本质,不过,这也是可以克服的。
代码呈现:
因此,核心代码提供了“相机预览”而不是“相机预览”,并且上面的图片已被故意扭曲,因此它在顶部完全清晰可见,在中间褪色并在底部消失。
我可以建议使用此代码的最佳方法是自己实现前四个步骤并查看其工作原理,然后添加最后两个步骤并查看其工作原理,然后将关键概念插入到另一个(无疑更大更多)中复杂的,一段代码。
前四个步骤:
创建自定义视图以显示到顶部、相机、视图。此类在其下方的任何内容上呈现位图。位图中每个像素的 Alpha 值将决定下部视图的透过量。
public class CameraOverlayView extends View {
private Paint paint;
private Size incomingSize;
private Bitmap bitmap = null;
public CameraOverlayView(Context context) {
super(context);
init();
}
public CameraOverlayView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
paint = new Paint();
paint.setStyle(Style.FILL_AND_STROKE);
paint.setColor(0xffffffff);
paint.setTextSize((float) 20.0);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = canvas.getWidth();
int height = canvas.getHeight();
canvas.drawBitmap(bitmap, 0.0f, 0.0f, paint);
}
}
Run Code Online (Sandbox Code Playgroud)将三个视图放入一个框架中,并将它们全部设置fill_parent为两个方向。第一个将位于“下方”(SurfaceView,以便相机预览有效)。第二个“在中间”(地图或其他内容的表面视图)。第三个“在顶部”(褪色的相机图像的视图)。
<SurfaceView
android:id="@+id/beneathSurfaceView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<SurfaceView
android:id="@+id/middleSurfaceView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<com.blah.blah.blah.CameraOverlayView
android:id="@+id/aboveCameraView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
Run Code Online (Sandbox Code Playgroud)
一个精简的主 Activity,它将设置相机,并将自动预览图像发送到(底部)SurfaceView,并将预览图像数据发送到处理例程。它设置一个回调来捕获预览数据。这两者并行运行。
public class CameraOverlay extends Activity implements SurfaceHolder.Callback2 {
private SurfaceView backSV;
private CameraOverlayView cameraV;
private SurfaceHolder cameraH;
private Camera camera=null;
private Camera.PreviewCallback cameraCPCB;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.camera_overlay);
// Get the two views
backSV = (SurfaceView) findViewById(R.id.beneathSurfaceView);
cameraV = (CameraOverlayView) findViewById(R.id.aboveCameraView);
// BACK: Putting the camera on the back SV (replace with whatever is driving that SV)
cameraH = backSV.getHolder();
cameraH.addCallback(this);
// FRONT: For getting the data from the camera (for the front view)
cameraCPCB = new Camera.PreviewCallback () {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
cameraV.acceptCameraData(data, camera);
}
};
}
// Making the camera run and stop with state changes
@Override
public void onResume() {
super.onResume();
camera = Camera.open();
camera.startPreview();
}
@Override
public void onPause() {
super.onPause();
camera.setPreviewCallback(null);
camera.stopPreview();
camera.release();
camera=null;
}
private void cameraImageToViewOn() {
// FRONT
cameraV.setIncomingSize(camera.getParameters().getPreviewSize());
camera.setPreviewCallback(cameraCPCB);
}
private void cameraImageToViewOff() {
// FRONT
camera.setPreviewCallback(null);
}
// The callbacks which mean that the Camera does stuff ...
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (holder == null) return;
// stop preview before making changes
try {
cameraImageToViewOff(); // FRONT
camera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or reformatting changes here
// start preview with new settings
try {
camera.setPreviewDisplay(holder); //BACK
camera.startPreview();
cameraImageToViewOn(); // FRONT
} catch (Exception e){
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
camera.setPreviewDisplay(holder); //BACK
camera.startPreview();
cameraImageToViewOn(); // FRONT
} catch (IOException e) {
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
@Override
public void surfaceRedrawNeeded(SurfaceHolder holder) {
}
}
Run Code Online (Sandbox Code Playgroud)
有些东西缺失了:
现在,将两个函数添加到第一步中创建的视图中。第一个确保视图知道传入图像数据的大小。第二个接收预览图像数据,将其转换为位图,并沿途扭曲它以提高可见性并演示 Alpha 淡入淡出。
public void setIncomingSize(Size size) {
incomingSize = size;
if (bitmap != null) bitmap.recycle();
bitmap = Bitmap.createBitmap(size.width, size.height, Bitmap.Config.ARGB_8888);
}
public void acceptCameraData(byte[] data, Camera camera) {
int width = incomingSize.width;
int height = incomingSize.height;
// the bitmap we want to fill with the image
int numPixels = width*height;
// the buffer we fill up which we then fill the bitmap with
IntBuffer intBuffer = IntBuffer.allocate(width*height);
// If you're reusing a buffer, next line imperative to refill from the start, - if not good practice
intBuffer.position(0);
// Get each pixel, one at a time
int Y;
int xby2, yby2;
int R, G, B, alpha;
float U, V, Yf;
for (int y = 0; y < height; y++) {
// Set the transparency based on how far down the image we are:
if (y<200) alpha = 255; // This image only at the top
else if (y<455) alpha = 455-y; // Fade over the next 255 lines
else alpha = 0; // nothing after that
// For speed's sake, you should probably break out of this loop once alpha is zero ...
for (int x = 0; x < width; x++) {
// Get the Y value, stored in the first block of data
// The logical "AND 0xff" is needed to deal with the signed issue
Y = data[y*width + x] & 0xff;
// Get U and V values, stored after Y values, one per 2x2 block
// of pixels, interleaved. Prepare them as floats with correct range
// ready for calculation later.
xby2 = x/2;
yby2 = y/2;
U = (float)(data[numPixels + 2*xby2 + yby2*width] & 0xff) - 128.0f;
V = (float)(data[numPixels + 2*xby2 + 1 + yby2*width] & 0xff) - 128.0f;
// Do the YUV -> RGB conversion
Yf = 1.164f*((float)Y) - 16.0f;
R = (int)(Yf + 1.596f*V);
G = 2*(int)(Yf - 0.813f*V - 0.391f*U); // Distorted to show effect
B = (int)(Yf + 2.018f*U);
// Clip rgb values to 0-255
R = R < 0 ? 0 : R > 255 ? 255 : R;
G = G < 0 ? 0 : G > 255 ? 255 : G;
B = B < 0 ? 0 : B > 255 ? 255 : B;
// Put that pixel in the buffer
intBuffer.put(Color.argb(alpha, R, G, B));
}
}
// Get buffer ready to be read
intBuffer.flip();
// Push the pixel information from the buffer onto the bitmap.
bitmap.copyPixelsFromBuffer(intBuffer);
this.invalidate();
}
Run Code Online (Sandbox Code Playgroud)
第二个例程的注意事项:
该代码显示了基本思想。然后进入下一阶段:
将相机表面视图设置得足够小,以隐藏在顶部视图的非褪色部分后面。即,将android:layout_height其更改为,比如说60dp。
设置中间的SurfaceView来接收地图信息。
| 归档时间: |
|
| 查看次数: |
1532 次 |
| 最近记录: |