I'm struggling with a kind of feedback given progress bar.
I have an app that controls a measurement device that gives back signal data as numbers and on a run there is tens of signals. In the app I have a progress dialog that shows the progress of a run and the signals as plain text. I'd like to add a kind of a progress bar that would have increment steps with different colors depending of the signal. For example the higher the signal the redder the increment step.
Is it possible to use progress dialog/bar to do that?
Solved by creating a progress bar of my own from blank LinearLayout
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
for(int k=0; k<bar+1; k++) {
View v = new View(this);
v.setBackgroundColor(Color.GRAY);
params.weight = 1;
v.setLayoutParams(params);
progress_bar.addView(v, k);
}
Which can then be updated with
progress_bar.getChildAt(check).setBackgroundColor(Color.rgb(r,g,b));
where check is first 0 and is increased by 1 every time
You could try this:
pBar.getIndeterminateDrawable().setColorFilter(0xFFFF0000,PorterDuff.Mode.Multiply);
You can also try:
pBar.getProgressDrawable().setColorFilter(0xFFFF0000,PorterDuff.Mode.Multiply);
Source: Change progressbar color through CODE ONLY in Android
Related
I've been trying to write some dynamically generated layout code for a simple app I came up with. I want to display a vertical row of cards, each on containing an undefined number of vertically aligned text boxes.
I wrote the code to generate these and populate the text, but it doesn't appear to be working and I can't figure it out for the life of me.
I'm new to Android Studio, and Java is still relatively fresh to me as well, so I could well be missing something quite obvious here.
I've tried using a few different types of View in A. Studio, and so far most work by themselves, but none can be contained within a card which would be ideal for me. Dynamically creating and editing properties of textViews works fine, but once I include the card view they no longer appear using the exact same code.
//Define Params
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(left,top,right,bottom);
//Add a card for each ingredient
for (Ingredient ing : ingredients)
{
CardView card = new CardView(this);
CardView.LayoutParams cardParams = new CardView.LayoutParams(CardView.LayoutParams.WRAP_CONTENT, 200);
card.setLayoutParams(cardParams);
card.setRadius(15);
card.setPadding(25,25,25,25);
card.setElevation(10);
card.setMaxCardElevation(30);
card.setBackgroundColor(Color.DKGRAY);
//Make a grid for each card, text on the left, image on the right
LinearLayout linearLayoutInCard = new LinearLayout(card.getContext());
LinearLayout.LayoutParams layoutParamsInCard = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
linearLayoutInCard.setLayoutParams(layoutParamsInCard);
card.addView(linearLayoutInCard);
for(int x = 0; x < 3; x++)
{
TextView textView = new TextView(this);
textView.setLayoutParams(params);
textView.setPadding(left, top, right, bottom);
textView.setTextSize(15);
textView.setElevation(11);
textView.setTextColor(Color.WHITE);
linearLayoutInCard.addView(textView);
switch (x)
{
case 0:
textView.setText(ing.name);
break;
case 1:
textView.setText(ing.price);
break;
case 2:
//textView.setText(ing.calories);
break;
}
}
I'm expecting a vertical row of cards with text boxes vertically aligned withing them, each with their own content (this whole script will only make one card for now, but that's a data driven thing) yet when I run the application, I get nothing but a blank screen.
Before venturing much further...this could be an example of the XY Problem.
Maybe have a look at the RecyclerView option?
RecyclerViews are entirely designed to manage the UI look and responsiveness of changing/scrolling data sets.
They can be a bit "what the heck" at first...but once writing them a few times, your UI look and code base is a lot more efficient and clean.
RecyclerView example Youtube
So I'm trying to add a RelativeLayout to a RelativeLayout however, when I run my app, it's an IllegalStateException that shows this error: The specified child already has a parent. You must call removeView() on the child's parent first. I'm sure you guys have seen this before. My question is how do I properly nest two relative layouts together?
Here is the code snippet that produces the exception:
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
RelativeLayout newFrame = new RelativeLayout(vidRipperService.getBaseContext());
newFrame.setLayoutParams(layoutParams);
// configure image view constraints...
// have the frame be right in the center of the layout.
ImageView editedFrame = new ImageView(vidRipperService.getBaseContext());
// Note: when doing padding the height and the width must be a multiple of two. A nice example is 70+30 = 100/2 = 50, but 80+30 = 110/2 = 55 <- not a multiple of two. Keep this in mind.
editedFrame.setId(View.generateViewId());
editedFrame.setPadding(30,30,30,0); // padding of 30 around the whole view.
editedFrame.setImageBitmap(frame); // set the frame to be that of the actual background.
RelativeLayout.LayoutParams frameLayoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
frameLayoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL); // place frames in center of the view.
editedFrame.setLayoutParams(frameLayoutParams);
newFrame.addView(breakingNewsLayout); // add the breaking news layout to this view!
newFrame.addView(editedFrame);
The problem is specifically triggered from the second to last line newFrame.addView(breakingNewsLayout) That line triggers the exception. The breakingNewsLayout is another relative layout that I would like to add to newFrame. I would appreciate any knowledge on how to get this to work. I never ran into a problem when nesting layouts before, but for some reason, this is really not playing nice.
Here is the code that creates the breakingNewsLayout:
private void createBreakingNewsLayout()
{
breakingNewsLayout = new RelativeLayout(vidRipperService.getBaseContext()); // create the new breaking new layout.
breakingNewsLayout.setElevation(5);
breakingNewsLayout.setPadding(0,0,0,15);
breakingNewsLayout.setBackgroundColor(ContextCompat.getColor(vidRipperService, R.color.transparent)); // ensure that the background is transparent.
// MATCH_PARENT for both width and height so that banner is shown on the frame for the video.
RelativeLayout.LayoutParams breakingNewsParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
breakingNewsParams.setMargins(0,50,0,0); // todo: ensure that the margin is 50dp not pixels!
breakingNewsParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
breakingNewsLayout.setLayoutParams(breakingNewsParams); // set the layout params for the breaking news layout.
// set all of the text view attributes.
TextView liveBannerText = getLiveBannerText();
TextView breakingNewsTime = getBreakingNewsTime();
TextView breakingNewsHeadline = getBreakingNewsHeadline(breakingNewsTime.getId()); // headline goes about the breaking news time.
TextView breakingNewsBanner = getBreakingNewsBanner(breakingNewsHeadline.getId()); // banner goes above the breaking news headline
TextView viddyWatermarkText = getViddyWatermarkText(breakingNewsHeadline.getId()); // viddy watermark goes above the breaking news headline.
TextView breakingNewsDescription = getBreakingNewsDescription(breakingNewsTime.getId()); // breaking news description goes to the end of the breaking news time
// Add all of the views for the breaking news layout.
breakingNewsLayout.addView(liveBannerText);
breakingNewsLayout.addView(breakingNewsBanner);
breakingNewsLayout.addView(viddyWatermarkText);
breakingNewsLayout.addView(breakingNewsHeadline);
breakingNewsLayout.addView(breakingNewsTime);
breakingNewsLayout.addView(breakingNewsDescription);
}
maybe you should remove breakingNewsLayout before you add it:
((ViewGroup) breakingNewsLayout.getParent()).removeView(breakingNewsLayout);
I figured it out! After extensive researching and testing the reason I was getting this issue was because I was attempting to reuse the breakingNewsLayout when creating a new frame. I have x amount of frames and I needed to generate the breakingNewsLayout every single time I wanted to apply the layout to the frame. Since I was trying to reuse the layout that I have already added, the layout already has a parent and thus the exception above was called.
Apologies for the question and any lack of details.
I am working on an android server-client application. There is a connection between the android application and the server.
Based on the first message from the server, a number of buttons is created and displayed on the screen. This number usually is between 1 and 10.
I don't want to initialise 10 buttons in my activity, as maybe, in the future, the number of buttons will increase to 20.
This is the way I initialise buttons and show them on the screen:
actionButtons = server.getActionButtons();
TableLayout buttonLayout =
(TableLayout) rootView.findViewById(R.id.tblLayoutButtons);
for(int i=0; i< actionButtons.length; i++)
{
btnAction.setWidth(100);
btnAction.setHeight(50);
btnAction.setTag(actionButtons[i]);
btnAction.setText(actionButtons[i].getName());
btnAction.setOnClickListener(btnActionClick);
buttonLayout.addView(btnAction);
}
This all works well. But my problem is that the server sends statusupdates for the buttons, every 3 seconds. Each button stands for a light, that can be on or off. A button that is 'ON' should have another background than a button that is 'OFF'. The buttons should be updated every time an update from the server is received.
How could this be done?
I would make it like this:
public void createButtons() {
actionButtons = server.getActionButtons();
TableLayout buttonLayout = (TableLayout) rootView.findViewById(R.id.tblLayoutButtons);
for(int i=0; i< actionButtons.length; i++)
{
btnAction.setWidth(100);
btnAction.setHeight(50);
btnAction.setTag(actionButtons[i]);
btnAction.setText(actionButtons[i].getName());
btnAction.setOnClickListener(btnActionClick);
btnAction.setId(i);
buttonLayout.addView(btnAction);
}
}
public void updateButton() {
//Get the ID of the button to toggle from the server and get the related view
ToggleButton buttonToToggle = (ToggleButton) findViewById(Integer.parseInt(server.getMessage()));
if (buttonToToggle.isChecked()) {
buttonToToggle.setChecked(false);
buttonToToggle.setBackground(R.drawable.offImage)
}
else {
buttonToToggle.setChecked(true);
buttonToToggle.setBackground(R.drawable.onImage)
}
}
This has the advantage, that you just have to send the ID of the Button and it gets toggled.
Alternatively you could send the binary value off all buttons, so you have to send also just a few bytes... In this case, you can assign the buttons their value in a for loop, almost like you create them.
Hope I helped ;)
If you want to change status of an already created Button then while creating them at run time assign them unique Id's using setID(int) method from the View class.
So for your button1 you can,
button1.setId(100);
and when you want to change thngs you can fetch the ID for the button and change it appropriately.
if(toChangeButton.getID() == 100){
//Change button1
}
Hope this helps.
Try to use the listview to add the buttons.When you get the data from the server,just update the adapter of the listview.
Hope this helps.
I am trying to change the button size dynamically, but after using setWidth() and setHeight() nothing happens.
This is my code...
GridLayout grid = (GridLayout)findViewById(R.id.grid);
grid.setColumnCount(10);
grid.setRowCount(10);
cells = new Button[100];
for (int i = 0; i < cells.length; i++) {
cells[i] = new Button(this);
cells[i].setWidth(grid.getWidth()/10);
cells[i].setHeight(grid.getHeight()/10);
grid.addView(cells[i]);
}
Any ideas/solutions?
LayoutParams should solve the issue:
This in an example of how it should work taken from another stackOverflow post:
ViewGroup.LayoutParams params = myButton.getLayoutParams();
params.width = 400;
myButton.setLayoutParams(params);
I figured this out on my own and it was very simple, I feel stupid for overlooking it.
grid.addView(cells[i], display.getWidth()/grid.getColumnCount(), display.getWidth()/grid.getColumnCount());
In this line of code I add the button to the layout with the "cells[i]" while the trailing two parameters tell the view what size I want the button to be.
Another example:
addView(myButton, 100, 200);
Above the addView is adding myButton with 100 pixel width by 200 pixel height.
Maybe try to call invalidate method. If the view is visible, onDraw(android.graphics.Canvas) will be called at some point in the future. This must be called from a UI thread. To call from a non-UI thread, call postInvalidate().
Source: http://developer.android.com/reference/android/view/View.html#invalidate%28%29
I have been steaming over this one a few days now. I try to have a selector for a big range of numbers... within int-limits. You ought to hold down a button and the value should change slow and the longer you press the more rapid it changes. You all know that kind of button, don't you?! :D
It has to be precise, yet fast to enter the number. I use a OnTouchListener. The event allows to .getDownTime().
I tried a lot, but always only got it to skip numbers (not really but too fast to use) or not repeatingly increase the value while holding down the button. If run without changes it is pretty fast, but it would be nice, if it starts to make 10 100 or 1000-jumps if it is held down long enough.
I prepared a little SSCCE looking like this:
public class ValueChangerSSCCE extends Activity implements OnTouchListener {
Button plusButton;
TextView valueView;
Button minusButton;
int value;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
plusButton = new Button(this);
plusButton.setText("+");
plusButton.setTextSize(120f);
plusButton.setOnTouchListener(this);
layout.addView(plusButton);
valueView = new TextView(this);
valueView.setGravity(Gravity.CENTER_HORIZONTAL);
valueView.setTextColor(Color.WHITE);
valueView.setText(value + "");
valueView.setTextSize(120f);
layout.addView(valueView);
minusButton = new Button(this);
minusButton.setText("-");
minusButton.setTextSize(120f);
minusButton.setOnTouchListener(this);
layout.addView(minusButton);
setContentView(layout);
}
/*
* Called when a button is pressed
*/
#Override
public boolean onTouch(View v, MotionEvent event) {
if (v == plusButton) {
value++;
} else if (v == minusButton) {
value--;
}
valueView.setText(value + "");
return false;
}
}
For devices with low resolution one might have to decrease the text-sizes.
Thanks in advance!
Have a look at the NumberPicker source code. This is a widget from the SDK that does exactly what you are describing, except without the acceleration. Using post calls to a Handler as is done here is the best way to handle the timing events. The only addition you would need to make to this class is to vary the mSpeed value in the post callbacks (and perhaps the increment) based on the down time.
HTH.
The way I might try and tackle this is as follows:
Pressing + or - will start a Thread. The thread updates the number at a set interval by an offset value, if the number has changed more than 20 times then decrease the interval so the number updates faster, if the number is still changing a lot then the offset value would be made larger to skip numbers. Remember all this is happening in a thread.
When the user lifts their finger the thread is killed and the offset, interval is reset.
Use the value of getDownTime() to compute how big the counter increment should be.
First, design the response curve you would like. (That is, determine a function that defines how the value should change as a function of touch time and, perhaps, starting value. It does not — should not, from the way you describe it — be a straight line function.)
Then just make your increment follow the curve. It will probably help to store the button value and down time at the last event.