Screenshot of Mapbox map without displaying it - kotlin

I need to display a few previews of addresses on the map on the same screen. To do that I'm going to display ImageViews with bitmaps instead of making multiple instances of MapView. But for that I need to find a way to capture these bitmaps.
I found snapshot function in MapboxMap (https://github.com/mapbox/mapbox-gl-native/issues/6062), but it requires displaying of the map.
val position = CameraPosition.Builder()
.target(addressLatLng)
.zoom(zoom)
.build()
mapboxMap.cameraPosition = position
mapboxMap.snapshot { bitmap: Bitmap ->
imageView.setImageBitmap(bitmap)
}
So, can I take a snapshot of the map without displaying it on the screen?

I've finally found the solution! The class I needed to use was MapSnapshotter.
val width = imageView.width
val height = imageView.height
val location = CameraPosition.Builder()
.target(LatLng(55.7558, 37.6173))
.zoom(16.0)
.build()
val options = MapSnapshotter.Options(width, height)
.withCameraPosition(location)
MapSnapshotter(context, options).start { snapshot ->
imageView.setImageBitmap(snapshot.bitmap)
}

Related

howTo get Image Resource of a ImageButton in kotlin

i want change the ImageResource of a ImageButton that i have find by id.
Motivation
a ImageButton(bottom) works as a reminder/backup of the last click of a ImageButton(top) .
setup:
some ImageButton (at the top of the app).
a ImageButton (at the bottom of the app).
example without errors, but don't find ImageResource of idR1
findViewById<ImageButton>(idR1).setOnClickListener {
findViewById<ImageButton>(idR5_oppCiv).setImageResource(R.drawable.athen_cavalry_swordsman);
not working examples
findViewById<ImageButton>(idR1).setOnClickListener {
findViewById<ImageButton>(idR5_oppCiv).setImageResource(it.resources.getDrawable());
findViewById<ImageButton>(idR1).setOnClickListener {
findViewById<ImageButton>(idR5_oppCiv).setImageResource(it.getImageResource());
try to get and set Drawable
following causes the app to crash when i click on an ImageButton.
Here i use a defType "res" to get the resource (the image hopefully).
val resR1: Int = resources.getIdentifier("r1col$i", "res", this.packageName)
findViewById<ImageButton>(idR1).setOnClickListener {
findViewById<ImageButton>(idR5_oppCiv).setImageDrawable(getDrawable(resR1))
How could i get this image resource of it ? And use it for the other ImageButton?
You should be setting the image like using setImageDrawable like this.
val image = findViewById<ImageButton>(R.id.your_view_id)
image.setOnClickListener {
findViewById<ImageButton>(idR5_oppCiv).setImageDrawable(image.drawable)
}

Custom CollapsingTopAppBar Jetpack Compose

The essence of the problem is that I want to write my own version of the AppBar that would include content as another Compose function. After looking at the source code of the current CollapsingTopAppBar implementation, I saw the following lines:
#Composable
private fun TwoRowsTopAppBar(
...
scrollBehavior: TopAppBarScrollBehavior?
) {
...
val pinnedHeightPx: Float = 64.dp
val maxHeightPx: Float = 152.dp
LocalDensity.current.run {
pinnedHeightPx = pinnedHeight.toPx()
maxHeightPx = maxHeight.toPx()
}
// Sets the app bar's height offset limit to hide just the bottom title area and keep top title
// visible when collapsed.
SideEffect {
if (scrollBehavior?.state?.heightOffsetLimit != pinnedHeightPx - maxHeightPx) {
scrollBehavior?.state?.heightOffsetLimit = pinnedHeightPx - maxHeightPx
}
}
...
Surface(...) {
Column {
TopAppBarLayout(
...
heightPx = pinnedHeightPx
...
)
TopAppBarLayout(
...
heightPx = maxHeightPx - pinnedHeightPx + (scrollBehavior?.state?.heightOffset
?: 0f),
...
)
}
}
}
As I understand it, scrollBehavior is used to handle the collapse and expansion behavior. In the current implementation, just constant values are put in heightOffsetLimit. And since I need my appbar implementation to be able to contain content of any size, I need to somehow know the size of this content in advance and put this value in heightOffsetLimit.
I have already written the code for my AppBar, so that it also contains content. But since I can't pass the height value of the content to scrollBehavior, the AppBar doesn't collapse to the end.
you need to calculate the height that the appbar will have before drawing it into the screen. I have followed this issue and solved my problem with the last solution. hope it helps:
Get height of element Jetpack Compose
use the content you can put (ex. an image or a huge text) as the MainContent
use your appbar as the DependentContent and use the size given in lambda to give the height to your appbar
finally set placeMainContent false as I believe you don't need to draw the image (or any other composable) directly in a box
and you will good to go

ImageView is not respecting the size of the CardView

I am trying to make some sort of gallery app. I would like to display images inside of a ScrollView inside a GridLayout so I used CardView for this and it looks like this:
But when I put ImageView inside each CardView, the CardView spreads and fills the whole ScrollView. Here's a preview:
The CardView is created programatically. Here's the code
fun CreateCardView(ItemCount: Int){
for (i in 1 until ItemCount){
/////////////////////CARD VIEW//////////////////////////////
val card_view = CardView(this)
card_view.radius = 8F
card_view.setContentPadding(8,8,8,8)
card_view.setCardBackgroundColor(Color.LTGRAY)
card_view.cardElevation = 8F
val param = GridLayout.LayoutParams()
param.rowSpec = GridLayout.spec(GridLayout.UNDEFINED, 1f)
param.columnSpec = GridLayout.spec(GridLayout.UNDEFINED, 1f)
card_view.layoutParams = param
val param2 = card_view.layoutParams as GridLayout.LayoutParams
param2.setMargins(10,10,10,10)
card_view.layoutParams = param2
subLayoutGrid?.addView(card_view)
////////////////////////END//////////////////////////////////////
///////////////////////IMAGEVIEW////////////////////////////////
val img = ImageView(this)
val imageparams = WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT
)
img.layoutParams = imageparams
img.scaleType = ImageView.ScaleType.CENTER_CROP
img.setImageResource(R.drawable.animaleight)
card_view.addView(img)
////////////////////////END///////////////////////////
}
}
How can I put ImageView inside the CardView without filling the whole ScrollView?
I've already fixed my problem. I've tried to use a 40px x 40px Picture then it worked the way I want to. See the image:
It seems like when you use high resolution Picture, the app cant handle the populating of ImageView in GridLayout.

Override width to the half of the screen

I am developing a chat and i use Recyclerview to show the messages. When the message is an image i use Glide to display it. Using glide i use the override function to show the image with specific dimensions. However this does not work very good because not all the phones have the same resolution and size.
bitmap?.let {
//meaning the image is landscape view
if (bitmap.width > bitmap.height)
Glide.with(Application.instance)
.load(fileInfo.localUri)
.apply(RequestOptions().override(500, 250))
.into(holder.sntImageView)
else
Glide.with(Application.instance)
.load(fileInfo.localUri)
.apply(RequestOptions().override(250, 500))
.into(holder.sntImageView)
holder.sendingProgress.visibility = View.GONE
holder.sntBubble.visibility = View.GONE
holder.sntImageView.visibility = View.VISIBLE
} ?: run {
holder.sntImageView.visibility = View.GONE
holder.sendingProgress.visibility = View.GONE
holder.sntBody.text = "Unable to decode image"
}
So my question is how to use Glide so that the image has almost the half of the screen instead of 500, 250...?
You can start by knowing the with of your container, like recyclerviews width:
container.width
This will give you the width in pixels. After that you can apply a division to get the pixels at half:
val yourViewWidth = container.width / 2
That's how you make it to half of the container.
And then you just have to pass that value to Glide.
If you want to get total device width, you can get the pixels like this accepted answer and then apply the same division criteria.
Note that if you are in a recyclerview and want to know the size of a child view, you may need to wait the layout to be ready in order to have access to its parameters. That can be done with the ViewTreeObserver.OnGlobalLayoutListener, And do your operations inside onGlobalLayout. It will be triggered when the view is ready and you'll be able to operate there.
Hope it helps, happy coding!

Kotlin read variable and post yes or no answer

I use Java and Kotlin for personal projects with little experience and I might use your help with this one. What I am trying to do is to read telemetry data (temperature, pressure, light level) from Estimote beacon. I have already managed to put & update values into textviews.
Now I would like to get IF conditions at this point (later I will try to save & upload them to Firebase database). Basically I want to check if one of the telemetry values is higher or less than Double number. Eg. if the light level is below 6 lux, write "Less then 6!", if more "More than 6!"
val scanner = EstimoteBluetoothScannerFactory(applicationContext).getSimpleScanner()
val scanHandler = scanner.estimoteTelemetryFullScan()
.withBalancedPowerMode()
.withOnPacketFoundAction {
var temperature: TextView = findViewById<TextView>(R.id.temperature)
temperature.setText("Temperature: ${it.temperatureInCelsiusDegrees}")
var magnetometer: TextView = findViewById<TextView>(R.id.magnetometer)
magnetometer.setText("Magnetometer: ${it.magnetometer}")
var pressure: TextView = findViewById<TextView>(R.id.pressure)
pressure.setText("Pressure: ${it.pressure}")
var ambientLight: TextView = findViewById<TextView>(R.id.ambientLight)
ambientLight.setText("Ambient Light: ${it.ambientLightInLux}")
var motionState: TextView = findViewById<TextView>(R.id.motionState)
motionState.setText("Motion State: ${it.motionState}")
}
.start()
if(ambientLight > 6) {
var checkLight: TextView = findViewById<TextView>(R.id.checkLight)
checkLight.setText("More than 6!")
}else{
var checkLight: TextView = findViewById<TextView>(R.id.checkLight)
checkLight.setText("Less than 6!")
}
This code does not update the textview value