Background
I'm trying to create a dial-like GridLayout, similar to this sketch :
The problem
I'm failing to create it correctly.
The idea I had was that all cells would take the same space, spreading the size evenly, except for the backspace button on the right that would span over 3 rows.
What I tried
What I currently have is this:
private TextView generateGridTextButton(final CharSequence textToShowAndAddUponClick) {
TextView tv = (TextView) LayoutInflater.from(this).inflate(R.layout.grid_text_button, mButtonsGrid, false);
tv.setText(textToShowAndAddUponClick);
tv.setOnClickListener(new OnClickListener() {
#Override
public void onClick(final View view) {
//...
}
});
return tv;
}
private void initButtonsGrid() {
for (int i = 1; i <= 3; ++i)
mButtonsGrid.addView(generateGridTextButton(Integer.toString(i)));
final ImageView backspaceButton = new ImageView(this);
backspaceButton.setImageResource(android.R.drawable.sym_def_app_icon);
final LayoutParams backspaceButtonLayoutParams = new LayoutParams(GridLayout.spec(GridLayout.UNDEFINED, 3, 3), GridLayout.spec(GridLayout.UNDEFINED, 1, 1));
backspaceButtonLayoutParams.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL);
backspaceButtonLayoutParams.height = backspaceButtonLayoutParams.width = LayoutParams.WRAP_CONTENT;
backspaceButton.setLayoutParams(backspaceButtonLayoutParams);
backspaceButton.setBackground(...));
mButtonsGrid.addView(backspaceButton);
for (int i = 4; i <= 9; ++i)
mButtonsGrid.addView(generateGridTextButton(Integer.toString(i)));
backspaceButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(final View view) {
//...
}
});
mButtonsGrid.addView(generateGridTextButton("*"));
mButtonsGrid.addView(generateGridTextButton("0"));
mButtonsGrid.addView(generateGridTextButton("+"));
final ImageView actionButton = new ImageView(this);
actionButton.setImageResource(android.R.drawable.sym_def_app_icon);
final LayoutParams actionButtonLayoutParams = new LayoutParams(GridLayout.spec(GridLayout.UNDEFINED, 1, 1), GridLayout.spec(GridLayout.UNDEFINED, 1, 1));
actionButtonLayoutParams.setGravity(Gravity.CENTER);
actionButtonLayoutParams.height = actionButtonLayoutParams.width = LayoutParams.WRAP_CONTENT;
actionButton.setLayoutParams(actionButtonLayoutParams);
actionButton.setBackground(...);
actionButton.setClickable(true);
mButtonsGrid.addView(actionButton);
}
res/layout/grid_text_button.xml
<TextView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_rowWeight="1"
android:background="#drawable/..." android:clickable="true" android:fontFamily="..."
android:gravity="center" android:textColor="#2a373e" android:textSize="36sp" app:layout_columnWeight="1"
app:layout_gravity="fill" tools:text="1"/>
The layout file has this:
<android.support.v7.widget.GridLayout android:id="#+id/gridLayout"
... app:columnCount="4"
app:orientation="horizontal" app:rowCount="4">
This almost works but for some reason the 2 top rows of buttons take less height than the 2 bottom rows of buttons:
I tried to play with the values of the gravity, the weight, the span... but nothing I tried helped (even got worse).
The question
What is wrong here? Why do the rows take different heights?
How can I fix this ?
The reason for this was that I used android:layout_rowWeight instead of app:layout_rowWeight , so it didn't work well on old Android versions.
Now it works fine:
Related
I have a RatingBar in my app, wrapped inside of a CardView for rounded corners. I need the rating stars to fill the width of the cardview evenly to create 5 stars, not more.
Currently I have
<androidx.cardview.widget.CardView
android:id="#+id/rating_container"
android:layout_width="0dp"
android:layout_height="50dp"
app:layout_constraintTop_toBottomOf="#+id/description"
android:layout_marginHorizontal="#dimen/spacing_normal_3x"
android:layout_marginTop="#dimen/spacing_normal_2x"
android:layout_marginBottom="#dimen/spacing_normal_3x"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:cardBackgroundColor="#color/app_rating_box_color"
app:cardCornerRadius="10dp"
app:cardElevation="0dp">
<RatingBar
android:id="#+id/rating"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:numStars="5"
android:stepSize="1"
android:theme="#style/RatingBar" />
</androidx.cardview.widget.CardView>
As you can see, I have 5 stars, and this works great. But it looks like this
I want it to be like this
but without having more than 5 stars basically. Ideally, they would be spaced evenly apart to fill the width of the box. If it is a smaller screen, then they would have less space in between them. Is this possible?
As the stars are not represented as views in the class RatingBar, but customly drawn, its hard to edit the display behaviour.
You could create a custom RatingBar like this (untested example code):
public class CustomRatingBar extends LinearLayout {
private int stars;
public CustomRatingBar(Context context) {
super(context);
setOrientation(LinearLayout.HORIZONTAL);
for (int i = 0; i < 5; i++) {
ImageView star = new ImageView(context);
addView(star);
LayoutParams params = (LayoutParams) star.getLayoutParams();
params.weight = 1;
params.setMarginStart(10);
params.setMarginEnd(10);
star.setOnClickListener(v -> setStars(indexOfChild(v) + 1));
}
setStars(0);
}
public void setStars(int stars) {
this.stars = stars;
for (int i = 0; i < getChildCount(); i++) {
ImageView star = (ImageView) getChildAt(i);
star.setImageResource(stars > i ? R.drawable.star_shown : R.drawable.star_hidden);
}
}
public int getStars() {
return stars;
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
getLayoutParams().width = 0;
}
}
well i'm looking for a way to flip the button on a linear layout vertical here is a screen shot of the buttons
the xml code is
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="bottom"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:id="#+id/buttons_layout">
<ImageButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/iv_green"
android:layout_weight="1.0"
android:src="#drawable/leaf_green"
android:layout_gravity="fill_vertical"
android:scaleType="fitXY"
android:onClick="HandleClick" />
<ImageButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/iv_other"
android:layout_weight="1.0"
android:src="#drawable/leaf_other"
android:layout_gravity="fill_vertical"
android:scaleType="fitXY"
android:onClick="HandleClick" />
<ImageButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/iv_red"
android:layout_weight="1.0"
android:src="#drawable/leaf_red"
android:layout_gravity="fill_vertical"
android:scaleType="fitXY"
android:onClick="HandleClick" />
<ImageButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/iv_yellow"
android:layout_weight="1.0"
android:src="#drawable/leaf_yellow"
android:layout_gravity="fill_vertical"
android:scaleType="fitXY"
android:onClick="HandleClick" />
</LinearLayout>
what i want to do is that when i push flip button on (which is another button) i want to change the position of the current button i will explain in pics:
okay guys i used the idea that Arnab Told me about in the post below, well i want to randomly flip the image buttons so i did the following script:
public void onClick(View v) {
btnsLayout.removeAllViews();
ArrayList<Integer> a = new ArrayList<Integer>();
for(int i = 0; i < 4; i++)
{
a.add(i);
}
Collections.shuffle(a);
btnsLayout.addView(Other, a.get(0).intValue());
btnsLayout.addView(Green, a.get(1).intValue());
btnsLayout.addView(Red,a.get(2).intValue());
btnsLayout.addView(Yellow,a.get(3).intValue());
}
the application is crashing the crash reason is:
java.lang.IndexOutOfBoundsException: index=2 count=1
what does it means ?
Thank you !
You can do this inside onCLick(View view) of Flip Button:
// Get all the views
LinearLayout btnsLayout = (LinearLayout) findViewById(R.id.buttons_layout);
ImageButton ivGreen = (ImageButton) findViewById(R.id.iv_green);
ImageButton ivOther = (ImageButton) findViewById(R.id.iv_other);
ImageButton ivRed = (ImageButton) findViewById(R.id.iv_red);
ImageButton ivYellow = (ImageButton) findViewById(R.id.iv_yellow);
// Remove views
btnLayout.removeView(ivGreen);
btnLayout.removeView(ivRed);
// ReAdd views in new index[Index 0 = position 1, Index 2 = position 3]
btnLayout.addView(ivRed, 0);
btnLayout.addView(ivGreen, 2);
Similarly :
// Remove views
btnLayout.removeView(ivOther);
btnLayout.removeView(ivYellow);
// ReAdd views in new index[Index 1 = position 2, Index 3 = position 4]
btnLayout.addView(ivYellow, 1);
btnLayout.addView(ivOther, 3);
First, you should rename the ids of the ImageButtons like :
<ImageButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/first_leaf"
android:layout_weight="1.0"
android:src="#drawable/leaf_green"
android:layout_gravity="fill_vertical"
android:scaleType="fitXY"
android:onClick="HandleClick" />
<ImageButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/second_leaf"
android:layout_weight="1.0"
android:src="#drawable/leaf_other"
android:layout_gravity="fill_vertical"
android:scaleType="fitXY"
android:onClick="HandleClick" />
<ImageButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/third_leaf"
android:layout_weight="1.0"
.../>
Then find your flip button in your java class and set an OnClickListener
like this:
myFlipButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
}
}):
Then, in the onClick function, perform the changes:
myFlipButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
myFirstLeaf.setImageDrawable(getResources().getDrawable(R.drawable.leaf_red));
mySecondLeaf.setImageDrawable(getResources().getDrawable(R.drawable.leaf_yellow));
...
}
});
Hope it helps.
You can use the imgButton.setBackgroundResource(); method.
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
imgButton1.setBackgroundResource(R.drawable.image3);
imgButton3.setBackgroundResource(R.drawable.image1);
}
});
If you want to swap the views you need to use a ViewGroup and you can set the index accordingly.
How do I change the position of a view in a Linear Layout.?
Hello Using Arnab Suggestion and some tuning i found a solution: the problem was that you need to insert the index 1 2 3 4 you can't randomly add the views to the linear layout.
public void addListenerOnButton() {
Button flip = (Button) findViewById(R.id.btn_flip);
final LinearLayout btnsLayout = (LinearLayout) findViewById(R.id.buttons_layout);
final ImageView Other = (ImageView) findViewById(R.id.iv_other);
final ImageView Green = (ImageView) findViewById(R.id.iv_green);
final ImageView Red = (ImageView) findViewById(R.id.iv_red);
final ImageView Yellow = (ImageView) findViewById(R.id.iv_yellow);
flip.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
btnsLayout.removeAllViews();
ArrayList<Integer> a = new ArrayList<Integer>();
for (int i = 0; i < 4; i++) {
a.add(i);
}
Collections.shuffle(a);
for (int k = 0; k<=3 ; k++){
if (a.get(0).intValue() == k) {
btnsLayout.addView(Other, a.get(0).intValue());
}
if (a.get(1).intValue() == k) {
btnsLayout.addView(Green, a.get(1).intValue());
}
if (a.get(2).intValue() == k) {
btnsLayout.addView(Red, a.get(2).intValue());
}
if (a.get(3).intValue() == k) {
btnsLayout.addView(Yellow, a.get(3).intValue());
}
}
}
I created a layout which programmatically created buttons (see code). With this layout I have a column of buttons, but I would create something like the picture below. I tried something with linear layout but the buttons didn't go to new line automatically and didn't show, so I change it to table layout. How can I create something like the picture programmatically?
Thank you.
protected TableLayout layout;
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layout = (TableLayout) findViewById(R.id.workflows_activity_layout);
private void createButton() {
loading.setVisibility(View.VISIBLE);
layout.removeAllViews();
if (items.length == 0) {
TableRow row = new TableRow(this);
TextView no_item = new TextView(this);
no_questions.setText("there are no items");
no_questions.setTextSize(35);
row.addView(no_item);
layout.addView(row);
} else {
for (int i = 0; i < items.length; i++) {
TableRow row = new TableRow(this);
final Button btn = new Button(this);
TextView tw = new TextView(this);
tw.setText(items[i].getName());
tw.setTextSize(25);
btn.setBackgroundResource(R.drawable.button_image);
btn.setId(i);
btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
int btn_selected = btn.getId();
Intent openItempage = new Intent(MainActivity.this, ItemsActivity.class);
startActivity(openItempage);
}
});
row.addView(btn);
row.addView(tw);
layout.addView(row, params);
items_buttons.add(btn);
items_nameText.add(tw);
}
}
loading.setVisibility(View.GONE);
}
There's an easy way to achieve what you want. Look at this code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:orientation="vertical">
<TableLayout
android:id="#+id/tab_lay"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:stretchColumns="*"
android:gravity="center_vertical" />
TabLayout tab_lay = (TableLayout)view.findViewById(R.id.tab_lay);
for(int i = 1; i <= 4; ){
TableRow a = new TableRow(getActivity());
TableRow.LayoutParams param = new TableRow.LayoutParams(
TableRow.LayoutParams.FILL_PARENT,
TableRow.LayoutParams.WRAP_CONTENT, 1.0f);
a.setLayoutParams(param);
a.setGravity(Gravity.CENTER_VERTICAL);
for(int y = 0; (y < 2) && (i <= 4); y++) {
Button x = new Button(getActivity());
x.setText("Text " + i);
x.setGravity(Gravity.CENTER);
TableRow.LayoutParams par = new TableRow.LayoutParams(y);
x.setLayoutParams(par);
int ids = i;
x.setId(ids);
x.setOnClickListener(this);
a.addView(x);
i++;
}
tab_lay.addView(a);
}
If you want more buttons, then just change 4 which is compare to i to your value. Hope I help.
You can implement this using labraries, for instance
FlowLayout
Usage:
<com.wefika.flowlayout.FlowLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="start|top">
<View
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Lorem ipsum" />
</com.wefika.flowlayout.FlowLayout>
Another solution is:
AndroidFlowLayout
Usage:
<com.liangfeizc.flowlayout.FlowLayout
android:id="#+id/flow_layout"
flowlayout:vertical_spacing="10dp"
flowlayout:horizontal_spacing="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Here is a horizontal LinearLayout, I set it's gravity to center_vertical, then add two views to the LinearLayout, the height of first view is bigger the other, the result is the second view align top of the first view, not at vertical center of the LinearLayout.
How to make all child view at vertical center, any ideas?
Here is my code:
Context context = getActivity();
mPictureContainer = new LinearLayout(context);
mPictureContainer.setBackgroundColor(0xffffffff);
mPictureContainer.setGravity(Gravity.CENTER_VERTICAL);
mPictureContainer.setOrientation(LinearLayout.HORIZONTAL);
int leftRightMargin = getResources().getDimensionPixelSize(R.dimen.leftRightMargin);
mPictureContainer.setPadding(leftRightMargin, 0, leftRightMargin, 0);
//...
mAddPicBtn = new ImageView(context);
mAddPicBtn.setLayoutParams(new LinearLayout.LayoutParams(Utils.dip2px(77f), Utils.dip2px(77f)));
mAddPicBtn.setScaleType(ScaleType.CENTER_CROP);
mAddPicBtn.setImageDrawable(StateListFactory.createStateListDrawable(R.drawable.add_prs, -1, R.drawable.add));
//...
mPictureContainer.removeAllViews();
ArrayList<String> pictures = (ArrayList<String>) data.getSerializableExtra("pictures");
int size = pictures.size();
for (int i = 0; i < size; i++) {
String path = pictures.get(i);
final View view = LayoutInflater.from(getActivity()).inflate(R.layout.status_pic_item, mPictureContainer, false);
view.setTag(path);
ImageView imageView = (ImageView) view.findViewById(R.id.picture);
ImageView delPicBtn = (ImageView) view.findViewById(R.id.delPicBtn);
delPicBtn.setImageDrawable(StateListFactory.createStateListDrawable(R.drawable.del_prs, -1, R.drawable.del));
delPicBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mPictureContainer.removeView(view);
if (mPictureContainer.getChildCount() < 4 && mAddPicBtn.getParent() != mPictureContainer) {
mPictureContainer.addView(mAddPicBtn);
}
}
});
mPictureContainer.addView(view, i);
ImageLoader.loadImage(imageView, "file://" + path);
}
if (mPictureContainer.getChildCount() < 4) {
mPictureContainer.addView(mAddPicBtn);
}
And here is the layout status_pic_item :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="81dp"
android:layout_height="81dp"
android:layout_marginRight="3dp" >
<ImageView
android:id="#+id/picture"
android:layout_width="77dp"
android:layout_height="77dp"
android:layout_alignParentBottom="true"
android:scaleType="centerCrop" />
<ImageView
android:id="#+id/delPicBtn"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignParentRight="true"
android:clickable="true" />
</RelativeLayout>
And here is the screenshot:
I am creating n number of images with wordImage and assign a differnt Id.This happens on a button click add. There is another button remove when I click that all the images that I have created should be removed from the view(Head is the view). Plz help how to do that.
onclick of add button
for (int getwordcount = 0; getwordcount <5; getwordcount++) {
int i=0;
WordImage = new ImageView(this);
WordImage.setId(getwordcount);
WordImage.setBackgroundResource(alphabetsimages[getwordcount]);
RelativeLayout.LayoutParams para=new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.FILL_PARENT);
para.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
para.leftMargin=maragin+=54;
para.bottomMargin=25;
para.width=BtnNext.getWidth()/3;
para.height=BtnNext.getHeight();
WordImage.setLayoutParams(para);
WordImage.setTag(getSplitString);
Head.addView(WordImage);
}
onclick of remove button
only the last -------------> Head.removeView(WordImage);
create image is removed from view.
How do I remove all images created using wordimage.Any help would be greatly appreciated.
WordImage saves link just for the last ImageView. Previous link lost in this line:
WordImage = new ImageView(this);
This is why Head.removeView(WordImage) removes only the last image.
If you want delete all added image elements, the easiest way do this is to add RelativeLayout container like this:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<RelativeLayout android:id="#+id/Head" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="add"
android:onClick="onClickAdd"
android:id="#+id/button" android:layout_alignParentStart="true"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="remove"
android:onClick="onClickRemove"
android:layout_alignBaseline="#id/button"
android:layout_alignParentRight="true"/>
</RelativeLayout>
Then you can delete all images only by one command:
Head.removeAllViews();
In other case, if you need to remove separate images, you have to delete your items in cycle similar to your "add" block:
for (int getwordcount = 0; getwordcount <alphabetsimages.length; getwordcount++) {
Head.removeView(findViewById(getwordcount));
}
Activity class will be like this:
public class MyActivity extends Activity {
RelativeLayout Head;
int alphabetsimages[] = {android.R.drawable.arrow_down_float, android.R.drawable.btn_dropdown, android.R.drawable.btn_minus, android.R.drawable.ic_dialog_map};
ImageView WordImage;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void onClickAdd(View v){
int margin = 0;
for (int getwordcount = 0; getwordcount <alphabetsimages.length; getwordcount++) {
int i=0;
WordImage = new ImageView(this);
WordImage.setId(getwordcount);
WordImage.setBackgroundResource(alphabetsimages[getwordcount]);
RelativeLayout.LayoutParams para=new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.FILL_PARENT);
para.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
para.leftMargin=margin+=54;
para.bottomMargin=25;
para.width = 40;
para.height = 40;
WordImage.setLayoutParams(para);
Head= (RelativeLayout)findViewById(R.id.Head);
Head.addView(WordImage);
}
}
public void onClickRemove(View v){
//Head.removeAllViews();
for (int getwordcount = 0; getwordcount <alphabetsimages.length; getwordcount++) {
Head.removeView(findViewById(getwordcount));
}
}
}
I hope that's what you need!