Change ListView divider length based on longest Text in List - android

I've been looking at things on Stackoverflow and cannot find out how to do this.
What I want is something like this:
xxxxxxxx
--------
xxxx
--------
xx
Instead of the usual
xxxxxxxx
----------------------------------- (until end of screen)
xxxx
-----------------------------------
xx
I wonder if there is an really easy way to do it.
I figure it involves changing the right margin but that's about as far as I got.
I am creating my ListViews at run-time by the way.

You should do something like this with a custom drawable :
<ListView
android:divider="#drawable/fancy_gradient"
android:dividerHeight="#dimen/divider_height"...
Java way :
list = (ListView) findViewById(R.id.list);
int[] colors = {0, 0xFF97CF4D, 0};
ListView inner = list.getRefreshableView();
inner.setDivider(new GradientDrawable(Orientation.RIGHT_LEFT, colors));
inner.setDividerHeight(1);
But it seems that divider width is not customizable...

Since you can't directly change divider width programmatically, I suggest writing an adapter which takes your string list. Adapter will be consisting of one TextView and one ImageView(preferably).
In the adapter you can compare strings and get the longest one. Get estimated width for that longest string by;
String longestText = "longestword";
Paint paint = new Paint();
float widthValue = paint.measureText(longestText);
(that will give you the result in pixels) And after getting this value, you can simply put an imageview of (height=x , width=widthValue) under the textview.
Then remove the divider from your listview in xml by;
android:divider="#android:color/transparent"
and your view as you desire is ready to use.

Got it to work I think. It seems to work.
Here is how I did it.
ListAdapter listAdapter = posList.getAdapter();
//base case
int longestWidth = listAdapter.getView(0, null, posList).getMeasuredWidth();
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, posList);
listItem.measure(0, 0);
//check if the items in the list are longer than base case
if (listItem.getMeasuredWidth() > longestWidth)
{
longestWidth = listItem.getMeasuredWidth();
}
}
ViewGroup.LayoutParams params = posList.getLayoutParams();
//assign width of textview to longest item in the list
params.width = longestWidth;

Related

Regenarate location if (X,Y) already contains ImageView there

I have an ImageViewArray and I am randomizing their locations, I want to check if the current location already contains an ImageView without keeping a lot of values of x,y for every ImageView in the array.
Here is my code:
ImageView[] imageViewArray = new ImageView[40];
for (int i = 0; i < 40; i++) {
imageViewArray[i] = new ImageView(this);
imageViewArray[i].setTag(i);
imageViewArray[i].setImageResource(R.mipmap.enemy);
rlt.addView(imageViewArray[i]);
imageViewArray[i].setX(rand.nextInt(rlt.getWidth()));
imageViewArray[i].setY(rand.nextInt(rlt.getHeight()));
if(imageViewArray[i].getX()=) // here I want to check if it already contains an ImageView.
}
Possible Solution
Creating IntArray and adding X value to it and also every Y value for it, then compare between them, is it the best solution?
Problem with the solution - nothing happens, the imageview doesn't change the place and the Toast is not executed.
code:
ImageView[] imageViewArray = new ImageView[20];
ArrayList<Float> xarray = new ArrayList<>();
ArrayList<Float> yarray = new ArrayList<>();
for (int i = 0; i < 20; i++) {
imageViewArray[i] = new ImageView(this);
imageViewArray[i].setTag(i);
imageViewArray[i].setImageResource(R.mipmap.enemy);
imageViewArray[i].setX((float)rand.nextInt(1 + layoutwidth));
imageViewArray[i].setY((float)rand.nextInt(1 + layoutheight));
xarray.add(imageViewArray[i].getX());
yarray.add(imageViewArray[i].getY());
rlt.addView(imageViewArray[i]);
Toast.makeText(MainActivity.this,imageViewArray[i].getX() +"blabla",Toast.LENGTH_LONG);
}
EDIT
layoutwidth is zero :
private int layoutwidth, layoutheight, randx, randy;
private RelativeLayout rlt;
....
rlt = (RelativeLayout) findViewById(R.id.layout);
rlt.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
rlt.getViewTreeObserver().removeOnGlobalLayoutListener(this);
layoutwidth = rlt.getWidth();
layoutheight = rlt.getHeight();
}
});
Yes, that is the best solution. You need to load the rectangles from somewhere. You might merge rectangles if one contains the other, but then you would over-complicate your task and in your quest of writing a more performant and a clearer code, you would end up with a slow and complicated code. Write your code with storing pairs of X, Y points where X is the let-top corner position and Y is the right-bottom corner position.
Note, that I have assumed that the pictures are not rotated. If the images might be rotated, then you need a more general solution, using the inequalities defining the rectangles to see where a point set of a rectangle intersects the point set of the other rectangle. If the intersection is empty set, then the "space is not used up".

Position ImageViews with an offset programmatically

I have to create a stack of images programmatically (because they have to be dynamic).
I want to stack ImageViews like this:
I've tried this, but the images all land up on top of each other:
for(int i=0; i<limit; i++){
dynamicButtons[i] = new ImageView(contextSosFragment);
int offsetLeft = 15 * i;
int offsetTop = 15 * i;
layoutParamsDynamicButton.setMargins(offsetLeft, offsetTop, 0, 0);
dynamicButtons[i].setAdjustViewBounds(true);
dynamicButtons[i].setScaleType(ScaleType.FIT_CENTER);
dynamicButtons[i].setImageResource(R.drawable.img_badge_dynamic_loading);
dynamicButtons[i].setTag(id);
containerDynamicButtons.addView(dynamicButtons[i], layoutParamsDynamicButton);
}
I've even removed the android:gravity="center" from my xml layout file.
I've also tried to add the layout params on the ImageView after setting the margins (dynamicButtons[i].setLayoutParams(layoutParamsDynamicButton);), but I read that that this might not take effect, because the layout params are for the parent and not the child of the container to which I add the ImageViews, that's why I tried to use addView(view, layoutParams).
How can I position the ImageViews like this, programmatically?
SOLUTION:
The solution was that I had to create a new layout params instance for each image - just like Devunwired suggested. However, I also found that I had to change the LinearLayout.LayoutParams to be RelativeLayout.LayoutParams. Only then did the change take effect.
The final for loop looks like this:
for(int i=0; i<limit; i++){
RelativeLayout.LayoutParams layoutParamsDynamicButton = new RelativeLayout.LayoutParams(width, height);
layoutParamsDynamicButton.bottomMargin = (int) getActivity().getResources().getDimension(R.dimen.margin_badges);
int offsetLeft = AppConstants.dynamic_button_offset_multiplier * i;
int offsetTop = AppConstants.dynamic_button_offset_multiplier * i;
layoutParamsDynamicButton.setMargins(offsetLeft, offsetTop, 0, 0);
Log.d(TAG, "offset = "+offsetLeft);
dynamicButtons[i] = new ImageView(contextSosFragment);
dynamicButtons[i].setAdjustViewBounds(true);
dynamicButtons[i].setScaleType(ScaleType.FIT_CENTER);
dynamicButtons[i].setImageResource(R.drawable.img_badge_dynamic_loading);
dynamicButtons[i].setTag(id);
containerDynamicButtons.addView(dynamicButtons[i], layoutParamsDynamicButton);
}
Each view needs its own LayoutParams object. It looks like your code just updates the same LayoutParams instance each time and passes it to addView(). If this is the case, all your views are pointing to the same params when it comes time to do layout...and their margins will all be the last value set.
As a performance optimization, if you are just placing several static images on top of each other, you could achieve the same effect (including the offsets) with a LayerDrawable (docs link) inside a single ImageView. This is the object created by <layer-list> in XML, but since you need to dynamically set the offset you could create one in code as well. Fewer views typically leads to cleaner UI.

Change Color of cell of grid

I want to change the color of the grid cell using the number of grid position . e.g. I have 5X6 grid means 30 gridItems so i want to change the color of 21st position. Please tell me how can i do this Without clicking on the Grid View.
You will need to define a custom adapter for this.
In the getView() method of adapter you'll have to check the position parameter if is equal with 21. If it's equal with 21, then change the background for currently cell.
If you did not had the experience to define a custom adapter yet, then it will make more sense to pass through an example first.
Here's an example of a GridView that uses a custom adapter to display images.
In order to set color in grid cell while inflating grid cell's layout, in your baseadapter class create a cell's array then set the color as you wish.
Like
LayoutInflater li = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
grd = li.inflate(R.layout.grid_item, null);
FrameLayout dgcl = (FrameLayout) grd.findViewById(R.id.grditm);
parent_l[position] = dgcl;
then
parent_l[21].setBackgroundColor(Color.RED);
here griditm is the id of the layout grid_item
First you must decide the order of the grid, where are columns, and where are lines. For example:
1 2 3 4 5
6 7 8 9 10
etc..
then just do a multiplication
i = Y*numberOfColums + X;
grid[i].myColor = Color(R,G,B);
I'm assuming 0 based index, that simply means:
if there are 6 columns:
0 <= X <= 5
if there are 5 rows
0 <= Y <=4
0 based index allows you to iterate the whole grid in a very simple manner
for(int x = 0; x < numberOfColumns; x++)
{
for(int y = 0; y < numberOfRows; y++)
{
i = Y*numberOfColums + X;
}
}

get width of textview in characters

I think this is the opposite of
Set width of TextView in terms of characters
I have a TextView where I'm showing some report data. I use a monospace TypefaceSpan for a portion of it because I want columns to line up.
I used my test Android device to figure out how many columns I could fit, but the Android emulator seems to have exactly one less column, which makes things wrap in an ugly way in portrait mode.
Is there a way to find out how many characters should fit on 1 line?
The answer would be to use the breakText() of your textView's Paint Object. Here is a Sample ,
int totalCharstoFit= textView.getPaint().breakText(fullString, 0, fullString.length(),
true, textView.getWidth(), null);
Now totalCharstoFit contains the exact characters that can be fit into one line. And now you can make a sub string of your full string and append it to the TextView like this,
String subString=fullString.substring(0,totalCharstoFit);
textView.append(substring);
And to calculate the remaining string, you can do this,
fullString=fullString.substring(subString.length(),fullString.length());
Now the full code,
Do this in a while loop,
while(fullstirng.length>0)
{
int totalCharstoFit= textView.getPaint().breakText(fullString, 0, fullString.length(),
true, textView.getWidth(), null);
String subString=fullString.substring(0,totalCharstoFit);
textView.append(substring);
fullString=fullString.substring(subString.length(),fullString.length());
}
Well you could do math to find this out, find the width of the character, divide the width of the screen by this, and you'd have what you're looking for.
But is it not possible to design it better? Are there any columns you can group together? Display as a graphic, or even exclude completely?
Another possible solution is to use something like a viewpager. (Find out how many columns' width fit on the first page, and then split the remaining tables onto the second page).
You can get total line of Textview and get string for each characters by below code.Then you can set style to each line whichever you want.
I set first line bold.
private void setLayoutListner( final TextView textView ) {
textView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
textView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
final Layout layout = textView.getLayout();
// Loop over all the lines and do whatever you need with
// the width of the line
for (int i = 0; i < layout.getLineCount(); i++) {
int end = layout.getLineEnd(0);
SpannableString content = new SpannableString( textView.getText().toString() );
content.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0, end, 0);
content.setSpan(new StyleSpan(android.graphics.Typeface.NORMAL), end, content.length(), 0);
textView.setText( content );
}
}
});
}
Try this way.You can apply multiple style this way.
You can also get width of textview by:
for (int i = 0; i < layout.getLineCount(); i++) {
maxLineWidth = Math.max(maxLineWidth, layout.getLineWidth(i));
}

Android - ImageView margins not appearing in LinearLayout

Right now, I'm struggling to accomplish something as simple as adding margin space between my child ImageViews within a custom LinearLayout (modified RadioGroup that is designed to take in a custom ImageView that implements Checkable, didn't override onMesarue). Long story short, these images are of a fixed dimension (60x60dip), and since they are dynamic (from the web), I had to add them dynamically like so:
for(int i = 0; i < num; i++){
ImageViewRadioButton childImage = new ImageViewRadioButton(mContext);
float imagehWidthHeight = getResources().getDimension(R.dimen.image_width_and_height);
LinearLayout.LayoutParams imageParams = new LinearLayout.LayoutParams((int) imageWidthHeight, (int) imageWidthHeight);
int imageSpacing = Utils.dipsToPixels(10, mContext);
int innerPadding = Utils.dipsToPixels(5, mContext);
imageParams.leftMargin = imageSpacing;
imageParams.rightMargin = imageSpacing;
childImage.setAdjustViewBounds(true);
childImage.setLayoutParams(imageParams);
childImage.setBackgroundDrawable(getResources().getDrawable(R.drawable.blue_pressed));
childImage.setPadding(innerPadding, innerPadding, innerPadding, innerPadding);
childImage.setClickable(true);
//other non-image properties...
imageContainer.addView(childImage);
}
The only thing that does work is the padding, which it spaces it out properly. However, I am not seeing any space between the padding of each child (margins). Am I doing this correctly, or is there a better way of doing it short of overriding onMeasure to factor in each child's margins?
You had create imageParams but you are not using that parameters in your code instead of imageParams you are using swatchParams parameter. And you had not put a code of swatchParams parameter.

Categories

Resources