Intereting Posts
Разница между Wakelock и FLAG_KEEP_SCREEN_ON? Создать плагин для Android-приложения Gradle: Как настроить разрешения Android Manifest? Диалог со списком и сообщением EditText требуется дважды щелкнуть, чтобы открыть диалоговое окно поиска Запуск автономной библиотеки на Android L. Ошибка: поддерживаются только независимые исполняемые файлы (PIE) Виджет вкладки всегда имеет в своем роде буквы в android 4.0 Недавно выпущена «Аутентификация с сервисами Google Play», проблемы с получением токена через GoogleAuthUtil.getToken Android: Android 4.1 эмулятор, вызывающий onDateSet дважды из диалогового окна DatePicker Как остановить отладку без закрытия приложения в Android Studio 2 Миграция Android Studio 0.6.1 до 0.8: не является папкой конфигурации Android Studio или домашней установкой Программирование графического процессора на устройствах Android Target filter pathPrefix с вопросительным знаком Facebook SDK 4 для Android – как выйти из программы Использование прозрачной строки состояния в Android 4.4 KitKat

Как отобразить 2 представления, с эффектом уклонения от градиента на Android?

Я хочу, чтобы на экране отображалось 2 вида – один из них был бы предварительным просмотром камеры, а другой отображал изображение или карту google и отображался в нижней части экрана.

Я хочу, чтобы между ними был переход, подобный градиенту, – поэтому между ними нет грубой грани. Возможно ли, чтобы такой эффект был?

Изменить: эффект, который я хотел бы достичь, должен выглядеть так (верхняя часть идет из предварительного просмотра камеры, а нижняя часть должна быть картой …):

Карта, смешавшаяся с фотографией камеры

На 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; 

Solutions Collecting From Web of "Как отобразить 2 представления, с эффектом уклонения от градиента на Android?"

Это возможно, но, возможно, немного сложно. Чтобы это было просто, я поставил основной код для достижения этого в ответ. Как уже отмечалось, для этого вам нужно два вида, один «поверх другого». «Нижний» должен быть SurfaceView, управляемый API карт. «Высший» должен показать, что изображение камеры исчезло над ним.

EDIT: Как указывает mr_archano, API (теперь) определяется таким образом, что без SurfaceView камера не будет отправлять данные предварительного просмотра. Ho hum, такова природа прогресса, но это также невозможно преодолеть.

В коде представлены:

  • «Нижний» SurfaceView управляется непосредственно механизмом предварительного просмотра камеры.
  • «Средний» SurfaceView предназначен для API MAPS.
  • «Верхний» вид – это то, где данные камеры отображаются для достижения желаемого эффекта.

Таким образом, основной код дает «предварительный просмотр камеры» над «предварительным просмотром камеры», а верхняя картинка была преднамеренно искажена, поэтому она хорошо видна в верхней части, затухающей в середине и уходящей снизу.

Могу ли я предложить, чтобы лучший способ использования этого кода состоял в том, чтобы реализовать эти первые четыре шага самостоятельно и увидеть, как он работает, а затем добавить два последних шага и увидеть, что они работают, прежде чем вставлять ключевые понятия в другие, несомненно, больше и больше Комплекс, кусок кода.

Первые четыре шага:

  1. Создайте собственное представление для отображения сверху, камеры, просмотра. Этот класс отображает растровое изображение над всем, что находится под ним. Значение альфа в каждом пикселе в растровом изображении определит, сколько из нижнего представления пропускается.

     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); } } 
  2. Поместите три вида в рамку, и все они будут установлены в 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" /> 

  3. Урезанная основная активность, которая будет настраивать камеру, и отправить автоматическое изображение предварительного просмотра в (снизу) 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) { } } 

    Некоторые вещи отсутствуют:

    • Обеспечение правильной ориентации изображения камеры
    • Обеспечение оптимального размера изображения предварительного просмотра камеры

  4. Теперь добавьте две функции в представление, созданные на первом шаге. Первое гарантирует, что представление знает размер входящих данных изображения. Второй получает данные предварительного просмотра, превращает его в растровое изображение, искажая его по пути как для видимости, так и для демонстрации альфа-затухания.

     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(); } 

    Примечания по второй процедуре:

    • Он предполагает формат входящей камеры NV21. Другие могут быть доступны, этот, несомненно, будет там, даже если это боль. См. Преобразование YUV-> RGB (Обработка изображений) -> YUV во время onPreviewFrame в android? ,
    • Вероятно, это может быть сделано быстрее или лучше, с более поздними версиями Android и некоторой оптимизацией кода.

Этот код показывает основную идею. Чтобы перейти к следующему этапу:

  1. Установите надпись «Поверхность» камеры достаточно маленькой, чтобы спрятаться за не выцветшей частью верхнего окна. Т.е. изменить android:layout_height для этого, скажем, 60dp .

  2. Установите средний SurfaceView для получения информации о карте.

К сожалению, AFAIK вы не можете перекрестно перефразировать между предварительным просмотром камеры и картой, если оба компонента должны быть интерактивными / живыми. Как было сказано ранее в предыдущем комментарии, это связано с природой обоих виджетов и ограничениями компоновки Android.

Для правильной работы просмотра камеры требуется SurfaceView . Из официальных документов:

SurfaceView пробивает отверстие в своем окне, чтобы его поверхность отображалась. Иерархия представлений позаботится о правильной компоновке с Поверхностью любых братьев и сестер SurfaceView, которые обычно появляются поверх нее. Это можно использовать для размещения накладок, таких как кнопки поверх поверхности, но, тем не менее, обратите внимание, что это может повлиять на производительность, так как полный альфа-смешанный композит будет выполняться каждый раз при изменении поверхности.

Google Maps v2 тоже использует SurfaceView (смотрите здесь ), так что в основном у вас есть два экземпляра SurfaceView один поверх другого, и вы просто не можете применять маску градиента для достижения того, что вы хотите, потому что у вас нет контроля над тем, как каждый Виджет привлекает себя:

  • Предварительный просмотр камеры SurfaceView получает буфер камеры и визуализирует его изначально
  • Карты SurfaceView отображаются в другом процессе.

Кроме того, использование двух экземпляров SurfaceView вместе очень не рекомендуется, как указано здесь :

Поверхностное представление пути реализовано в том, что создается отдельная поверхность и Z-упорядочено позади его содержащего окна, а прозрачные пиксели, втянутые в прямоугольник, где SurfaceView – так, что вы можете видеть поверхность позади. Мы никогда не планировали допускать несколько видов поверхности.

Я думаю, что единственный вариант, который у вас есть, – это выбрать только один из них, чтобы быть живым / интерактивным, а другой – как статический градиент изображения поверх него.

РЕДАКТИРОВАТЬ

Чтобы еще раз подтвердить мои предыдущие заявления, ниже цитаты из официальных документов об использовании камеры :

Важно: передать полностью инициализированный SurfaceHolder в setPreviewDisplay (SurfaceHolder). Без поверхности камера не сможет запустить предварительный просмотр .

Таким образом, вы вынуждены использовать SurfaceView , чтобы получить предварительный просмотр с Camera . Всегда.
И просто повторить: у вас нет контроля над тем, как эти пиксели отображаются, потому что Camera записывает непосредственно фреймбуфер с помощью предварительного просмотра SurfaceHolder .

В заключение у вас есть два полностью непрозрачных экземпляра SurfaceView и вы просто не можете применить какой-либо причудливый рендеринг к их контенту, поэтому я думаю, что такой эффект просто непрактичен в Android.