I'm developing an application that has an embedded chat on it.
In order to draw the bubbles* where the text is displayed, I'm using a custom view which extends from FrameLayout, just like in here:
https://github.com/florent37/ShapeOfView/blob/master/shapeofview/src/main/java/com/github/florent37/shapeofview/ShapeOfView.java
or here:
https://github.com/MasayukiSuda/BubbleLayout/blob/master/bl/src/main/java/com/daasuu/bl/BubbleLayout.java
*bubbles -> you know: the rounded corner rectangle with a little arrow at the left or right, depending on who wrote the message
The thing is that, if the message to be shown is long enough (a couple of thousands of characters depending on the phone's memory) the background drawable is not shown anymore.
I found that this is expected because I'm exceeding the maximum canvas size (the maximum height, in this case)
I know that the canvas maximum size in android depends on the phone on which you are measuring it.
For example, this is the limit for an old phone (Moto G 1st gen):
And this is the limit for a newer phone, with more memory:
Question: Is there another way you can think of, to define a view with an arbitrary shape as the background which overcomes this limitation?
PD: Yes, the code looks strange because I'm using xamarin to develop, but the question is general enough, and I don't care the language of the solution if it does exist :)
UPDATE
Added example code to reproduce this issue.
You just have to create any background in xml, let's say that we call it "bubble_background.xml":
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
And then use it as background for a TextView, like in :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/bubble"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="#+id/cell_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:autoLink="all"
android:linksClickable="true"
android:textSize="#dimen/atlas_text_size_message_item"
android:layout_marginRight="8dp"
android:layout_marginLeft="8dp"
android:background="#drawable/bubble_background" />
</LinearLayout>
Now, if your text is long enough, the background won't be visible (it is a good idea to wrap the TextView in a ScrollView...)
UPDATE
This is the result of testing the background that was suggested by #cherryBu
Of course, I've got the same result because it is exactly what I was doing, but still, I had to test it, just in case, you know how this is.... :)
The top and bottom thin rectangles with round corners and the little triangle at the right (all in blue) are part of my current solution (one which doesn't make me happy but works: I'm "drawing" the bubble by composing it using those 3 partial images and setting the background of the text to the same color). The text is white, that's why you can't really see much of it. In the current code I'm setting the background to blue (not an image, because it can't be drawn -again :) -, only a plain color; the same as you can see in the other parts of the "bubble")
bubble_background.xml:
<?xml version="1.0" encoding="utf-8" ?>
<!-- For all properties see: http://developer.android.com/guide/topics/resources/menu-resource.html -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:bottomLeftRadius="20dp"
android:bottomRightRadius="20dp"
android:topLeftRadius="20dp"
android:topRightRadius="20dp" />
<padding
android:bottom="50dp"
android:left="50dp"
android:right="50dp"
android:top="50dp" />
<stroke android:width="10dp" android:color="#B2F7FE"/>
<solid android:color="#ffffff" />
</shape>
I use this as TextView background, I add very long text in it, but the shape still exist.
Update:
In case anyone is struggling with this issue: there is no solution and the maximum canvas size cannot be changed nor exceeded if you want to display a background like in this case.
Workaround solution, for my particular case:
Each bubble is composed using 4 items and a relative layout:
an image at the top, a thin blue/green rectangle with round top corners
an image at the bottom, a thin blue/green rectangle with round bottom corners
the text itself, with the same blue/green color set as background
a little blue/green triangle located at the right or left, according to who is sending the message to complete the chat bubble
I did not find any other solution and this one is working.
Of course, this won't work for you if you want to use an image instead of a plain color or simple pattern as backgournd
I'm the one who originally posted the question and the same which suggests the hacky and ugly solution from below.
I found a better and proper solution to this issue: the canvas size limit is only a problem when you have the Hardware acceleration turned on; so once I turned it off, I was able to render bubbles of any size.
The hardware acceleration can be customized in different ways and at different levels: Application, Activity, Window, or even at the View level, with some limitations.
For more information about what can and can't be done, please refer to the Goggle's documentation about this topic: https://developer.android.com/guide/topics/graphics/hardware-accel
Related
We are making a quiz app as a school project where we are supposed to display a question and show 4 answers. For 8 seconds we are supposed to show 4 buttons with different geometric shapes of different colors(and text for the answer). Then when the timer hits zero the geometric shapes will change colors and switch positions. Then the buttons should be clickable and we can hit the correct answer.
My problem is that I can't find a way to draw these objects on a button, or anything clickable. I could have just used images of triangles, circles etc. on ImageButton, but as the objects need to change colors, it will be difficult. Here is a photo of what it is supposed to look like:
(edit) https://i.stack.imgur.com/05Far.png
Hope someone can help me with this, thanks.
Step 1
For creating geometrical shapes you will have to create a different xml file in the drawable folder for each shape. [for drawing circle you need to oval]. XML file should be like this:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="any_shape_name*" >
<stroke
//optional: for setting border.
android:dashGap="4dp"
android:dashWidth="10dp"
android:width="6dp"
android:color="#color/black" />
<solid android:color="#color/white" />
<padding
android:bottom="20dp"
android:left="20dp"
android:right="20dp"
android:top="20dp" /></shape>
Step 2
Create a button in main layout file and add this xml as the background
android:background = "#drawable/shape_file_name"
This was just a simple 2 step method.
Note:- You can also draw shapes dynamically and set them as the background of the button.
For this way please refer to this beautiful link.
Hope this helps.
Im working on an android app were you can setup your own Ring.
Now I want to give the user a preview of the ring, when they selected multiple rings.
Here a preview of how it should look like
The setup of how i thought to make it is this:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="5dp">
<ImageView
android:id="#+id/generator_ring_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#e7e7e7"/>
<FrameLayout
android:id="#+id/generator_ring_addon_frame"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
</FrameLayout>
I'm going to add the addon rings programmatically by just creating a new ImageView in the code.
Now the hard part of this is to place the image over the other ring, and have the view the same on every screen size..
Is ther anybody who can help me getting the correct code for placing the image on the correct position on every screen size?
thanks for reading
EDIT:
the moment I am selecting the addons rings the Base Rings is already visible, so I can get the height of the image
User Paint API: https://developer.android.com/reference/android/graphics/Paint.html
https://developer.android.com/reference/android/graphics/Canvas.html
Like that you can add whatever pictures you want, programatically, move them, even create animations if you want.
Also you will have just a view, which contains the canvas. So no need to have convoluted FrameLayouts into FrameLayouts.
Example on how to draw images on a canvas.
draw object/image on canvas
Using canvas you can get (x,y) coordinates of the ring.
First create canvas with ring image and than use canvas.draw() to draw another image on base image.
--> a number of circles will be drawn over a period of time but only one will be shown on screen at a time.
--> user will click on the circle when the program registers the click, it will show the next circle.
--> the position of each circle is known, only they will appear randomly at different execution.
I have considered a linear layout filled with a lot of imageview(30 of them), every imageview has the same source, a small red dot, generated and stored in the res/drawable folder. code for the dot is:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Large red circle -->
<item>
<shape
android:shape="oval">
<stroke
android:width="0dp"
android:color="#000000" />
<solid android:color="#FF0000" />
<size
android:width="30dp"
android:height="30dp"/>
</shape>
</item>
I am thinking about using isVisible() on these imageviews to hide and show them at different times. this doesn't seem very efficient to me. any suggestions?
The best way to achieve that is to create a single custom View with onDraw overridden.
Then, inside onDraw you can simply draw as many circles as you want on the Canvas object. There are thousands of threads here on StackOverflow describing how to do that. E.g. this one.
Remember that you will have to call setWillNotDraw(false) on your View to cause your custom onDraw to be executed.
When the user clicks on the circle, simply record that even and call invalidate(). onDraw will be called once again and you can draw proper number of circles for the updated state.
I am creating a small Battleship game and for the Android UI I was hoping to create a 10x10 grid of image buttons or something (anything easy).
I was following the tutorial provided at this link
My problem is that I can't get the images to display in a proper 10x10 format. Using the GridView, I set the num_columns to "10" in the XML but there is no such attribute for the number of rows.
As phone sizes differ, is there a way to have a 10x10 grid auto fit any screen?
By following the steps in the above link I can display 100 clickable images but my problem is with the formatting. Here's a screenshot of said result:
I've tried changing values in XML to scale the images down but cannot figure out how to. Apologies for lack of code snippets but I really haven't altered much from the sample given in the above link other than the vertical and horizontal spacing.
Would appreciate any enlightenment, even if it's just to say I am I going about this the wrong way completely.
You can achieve this with a table layout : http://www.mkyong.com/android/android-tablelayout-example/
GridViews, just as ListViews have been designed to contain any number of rows.
But I really doubt you want to use views in your game and not only use a canvas, draw anything and detect clicks without relying on views built-in mechanisms. It's more work but you end with something that will make you much more free to do what you want (for instance not having to deal with the number of rows of a container...)
go to this link and try 2nd example Custom Adapter example.
just change android:numColumns="auto_fit" to android:numColumns="10".
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/gridView1"
android:numColumns="10"
android:gravity="center"
android:columnWidth="100dp"
android:stretchMode="columnWidth"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
</GridView>
You can probably do what you want with a GridLayout, but not with a GridView (which automatically scrolls vertically). Using a GridLayout, set all the buttons to have 0dp layout width and height, and set their layout gravity to fill.
I am trying to create my own buttons for a calculator application.
My trouble is that , i'm finding it hard to support all the different screen sizes.
Basically i have a number of buttons, created like this
<Button android:text="Button" android:id="#+id/button1"
android:background="#drawable/test"
android:layout_height="60dip" android:layout_width="60dip" android:layout_margin="5dip"></Button>
My background is an XML drawable
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Bottom 2dp Shadow -->
<item>
<shape android:shape="rectangle">
<gradient android:startColor="#E0E0E0"
android:endColor="#373737"
android:angle="315" />
<corners android:radius="20dip" />
</shape>
</item>
<!-- White Top color -->
<item android:top="5dip" android:left="5dip" android:right="5dip"
android:bottom="5dip">
<shape android:shape="rectangle">
<gradient android:startColor="#9E9E9E" android:endColor="#C5C5C5"
android:angle="270" />
<corners android:radius="20dip" />
</shape>
</item>
Basically a background with rounded corners and what looks like a bevel , and a few gradients to make it look nice!
on 3.2 HVGA the buttons are the correct size
But when i view the buttons in 3.7 FWVGA , the aspect ratio is lost and there size is same size as 3.2 but as there are more pixels to work with on this screen the images are not the correct size.
Is there anyway to keep the consistency in this case???
The problem
As you already mentioned, the issue is that there is more screen space available. This means you have to resize your buttons according to fill the available space, e.g. fill the available width of the display with 4 buttons, and scale their height so that the aspect ratio of the graphic stays intact.
You are using dp units here, which is absolutely ok and good practice when defining layouts. But in this case it tells the layout "this thing has a fixed size of XX dp" (you can think of dp as a fixed unit, the fixed amount is just determined by the device that displays the layout). You don't want a fixed size. You want the buttons to stretch in a dynamic way.
A solution
To provide a solution for your above layout: You can use a LinearLayout and it's layout_weight attribute. Here is some short (incomplete) sample code to illustrate the principle:
<LinearLayout android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
<Button android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
<Button android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
<Button android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
</LinearLayout>
What happens here?
First we create an outer LinearLayout that fills the entire parent width (= the entire screen width) and adjusts it's height depending on the content. Standard stuff.
Then we add 4 buttons. The relevant piece here is layout_weight. This tells each button to "fill the available space as much as possible". Since every single one tries to stretch out now, we have to define how much space each button gets. Thats the number given to layout_weight. Here we have the equal number one for each button. That means each button will be the same size as any other. So how does the layout determine how much space that is? It calculates the total weight of it's children, which is 4 here and gives each children space according to the ratio child_weight/total_weight. So each button takes 1/4 of the width. (You can also assign any other number, if you give every button the weight 3, each button will get 3/12 of the width, which is still 1/4 according to math :) )
One question remains: Why layout_width="0dp"? That just prevents some unneccessary internal calculations inside as far as I know. All you have to know is use 0dp for the scaling dimension when using the layout_weight attribute. You can research a bit around if you want to know more.
Samples
Here are two screenshots of this in practice:
2.7" QVGA
3.7" FWVGA
You could use "configuration qualifiers" and declare different layouts based on resolution, just create subfolders like this:
drawable-mdpi
drawable-hdpi
So you can better align according to density.
Another solution would be extend the "Button" class and create a custom widget that aligns according to screen size by calling getWindowManager().getDefaultDisplay() and changing its size during "onCreate()" method.