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.
Related
I want to animate some text's visibility to not just appear/disappear but to slide in/out in Jetpack Compose Android app that I'm building.
I just literally copy-pasted that little code snippet from developer.android.com/jetpack/compose/animation and it does not work:
var visible by remember { mutableStateOf(true) }
val density = LocalDensity.current
AnimatedVisibility(
visible = visible,
enter = slideInVertically {
// Slide in from 40 dp from the top.
with(density) { -40.dp.roundToPx() }
} + expandVertically(
// Expand from the top.
expandFrom = Alignment.Top
) + fadeIn(
// Fade in with the initial alpha of 0.3f.
initialAlpha = 0.3f
),
exit = slideOutVertically() + shrinkVertically() + fadeOut()
) {
Text("Hello", Modifier.fillMaxWidth().height(200.dp))
}
It simply does not animate, the text gets shown/hidden without any animation.
Any ideas what can be the problem?
I guess I can't paste my whole app here, as it would be silly, it would be nice of Google to give us a Jetpack Compose Playground of sorts, to be able to practice and test code there...
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
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!
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)
}
I am implementing an application displaying images and messages obtained from .net server. For that I'm adding LinearLayout's with TextView and ImageView dynamically by using for loop.
At first I am getting messages and I'm adding them to the TextView with dummy images placed in ImageView:
for(int i = 0; i < messages.size(); i++) {
FrameLayout f1 = new FrameLayout(this);
LinearLayout l1 = new LinearLayout(this);
LinearLayout l2 = new LinearLayout(this);
im = new ImageView(this);
TextView tv = new TextView(this);
tv.setText(messages.get(i).getmessage());
im.setImageResource(R.drawable.person);
l1.addView(tv);
l2.addView(im);
f1.addView(l1);
f1.addView(l2);
((LinearLayout)findViewById(R.id.LinearlayoutMessage)).addView(f1);
}
After some time I am getting original images. My intention is to replace the dummy images with original ones. To achieve this I'm using imageview.getid() unfortunately I'm getting last id of the imageview. But I need to get each individual imageview id's.
What is the best way of changing dummy images with real ones?
Looks like you need to store each imageView id in a map from each message -> imageView like so:
Map<Message, Long> messageMapping = new HashMap<Message, Long>();
for(int i = 0; i < messages.size(); i++) {
FrameLayout f1 = new FrameLayout(this);
LinearLayout l1 = new LinearLayout(this);
LinearLayout l2 = new LinearLayout(this);
im = new ImageView(this);
TextView tv = new TextView(this);
//add mapping
messageMapping.put(messages.get(i), im.getId());
tv.setText(messages.get(i).getmessage());
im.setImageResource(R.drawable.person);
l1.addView(tv);
l2.addView(im);
f1.addView(l1);
f1.addView(l2);
((LinearLayout)findViewById(R.id.LinearlayoutMessage)).addView(f1);
}
Then when it comes time to lazy load your images into the existing imageViews you simply need to look up the imageView id reference by message mapping:
(Total guess of what your code could look like)
for(int i = 0; i < messages.size(); i++){
Image image = queryServerForImage(messages.get(i).getImageId());
ImageView imageView = ((ImageView)findViewById(messageMapping.get(messages.get(i))));
//some conversion & seteup may be needed to get image into proper format
imageView.setImageBitmap(image);
}
You may be able to do something similar with async tasks. You could span each one in the message ImageView creation loop with the associated resource id and having each asyc task update the ui from the network response.