Custom ProgressBar widget - iphone

I am trying to do something similar to this but in Android.
In Android I can extend the ProgressBar but I am doubting of how to add the TextViews on top. In iphone it was easy because I can use absolute positions, but not here.
Any ideas?
EDIT:
I decided to use SeekBar instead of ProgressBar to add the thumb drawable. I commented below. Some points to notice:
I am using hardcoded values, actually three but it can be more or less.
When the thumb is moved it moves to 50 but it should move to the different options.
I am using pixels instead of dpi. I should fix that.
I need to solve the lack of animation when the thumb moves.
My progress so far:
public class SliderFrameLayout extends FrameLayout implements OnSeekBarChangeListener {
private SeekBar mSlider;
private Context mContext;
private int mSize = 3;
private TextView[] mTextViews;
private String[] mTexts = {"Nafta", "Gas", "Gasoil"};
public SliderFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
setWillNotDraw(false);
mTextViews = new TextView[mSize];
addSlider();
addTextViews();
}
private void addTextViews() {
for ( int i=0 ; i < mSize ; i++ ) {
TextView tv;
tv = new TextView(mContext);
tv.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
tv.setText(mTexts[i]);
mTextViews[i] = tv;
addView(tv);
}
}
private void addSlider() {
FrameLayout fl = new FrameLayout(mContext, null);
LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
fl.setLayoutParams(params);
fl.setPadding(30, 30, 30, 0);
mSlider = new SeekBar(mContext, null);
LayoutParams lp = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
//lp.setMargins(30, 30, 30, 0);
//mSlider.setPadding(30, 30, 30, 0);
mSlider.setLayoutParams(lp);
//mSlider.setMax(mSize-1);
mSlider.setThumbOffset(30);
//mSlider.setProgressDrawable(mContext.getResources().getDrawable(R.drawable.slider_track));
//mSlider.setThumb(mContext.getResources().getDrawable(R.drawable.slider_thumb));
mSlider.setOnSeekBarChangeListener(this);
//addView(mSlider);
fl.addView(mSlider);
addView(fl);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Rect rectf = new Rect();
mSlider.getLocalVisibleRect(rectf);
Log.d("WIDTH :",String.valueOf(rectf.width()));
Log.d("HEIGHT :",String.valueOf(rectf.height()));
Log.d("left :",String.valueOf(rectf.left));
Log.d("right :",String.valueOf(rectf.right));
Log.d("top :",String.valueOf(rectf.top));
Log.d("bottom :",String.valueOf(rectf.bottom));
int sliderWidth = mSlider.getWidth();
int padding = sliderWidth / (mSize-1);
for ( int i=0 ; i < mSize ; i++ ) {
TextView tv = mTextViews[i];
tv.setPadding(i* padding, 0, 0, 0);
}
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
Log.d("SEEK", "value: " + seekBar.getProgress());
seekBar.setProgress(50);
}
}

You're already overriding onDraw, why not just draw the text strings yourself? Rather than go through the overhead of adding TextViews and messing with the padding, just use canvas.drawText to physically draw the text strings in the right place.
You can specify the style and color of the text using a Paint object:
Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setColor(r.getColor(R.color.text_color));
textPaint.setFakeBoldText(true);
textPaint.setSubpixelText(true);
textPaint.setTextAlign(Align.LEFT);
And get the exact positioning by using the measureText method on that Paint object to find what width a particular string would be when drawn on a canvas:
textWidth = (int)textPaint.measureText(mTexts[i]);
Then you can iterate over your array of text strings and draw each string in the right place.
#Override
protected void onDraw(Canvas canvas) {
int myWidth = getMeasuredWidth()-LEFT_PADDING-RIGHT_PADDING;
int separation = myWidth / (mSize-1);
for (int i = 0; i++; i < mSize) {
int textWidth = (int)textPaint.measureText(mTexts[i]);
canvas.drawText(mTexts[i],
LEFT_PADDING+(i*separation)-(int)(textWidth/2),
TOP_PADDING,
textPaint);
}
}
You'll probably want to do the measurements in onMeasure instead of onDraw, and you should probably only measure the width of each string when you change the text or the paint, but I've put it all in one place to (hopefully) make it easier to follow.

Just a try. You could put your custom progressBar inside a FrameLayout then, inside this layout, you have to add three TextViews with fill_parent as width.
Then you can align the three texts in this way: left, center and right. Your texts shouldn't overwrite and you can adjust a little their position using margins.

You can use this... not exact what you looking for... but really easy to set up and customize...

You can set the TextViews to have:
android:layout_width="0dp"
android:layout_weight="1"
This will let the android framework take care of the placing of the TextViews and save you from manually calculating the padding of each one.

Related

Image flickers for split-second during FadeTransition - Javafx

I'm currently trying to build a game, and I have an intro sequence of images with accompanying text for the background story of the game. In the beginning, I fade in an image with accompanying text, and then fade both out. Then, I begin the next image-text pairing once the previous fade is complete, and I do this until the background story is complete, but when I do that the image and text flicker for a split-second before the fade in begins for every image and text. I've tried a number of things but can't seem to get rid of the flicker, can anyone help?
This is the function I use for this part in the intro:
private void backgroundStory (Stage stage, MediaPlayer mediaPlayer, String nameEntry, int width, int height, Color color) {
Group backstoryRoot = changeScene(stage, width, height, color);
GridPane backstoryPane = new GridPane();
backstoryRoot.getChildren().add(backstoryPane);
Label storyLabel1 = createLabel("Sometimes, life can get monotonous...");
backstoryPane.getColumnConstraints().add(new ColumnConstraints(width));
RowConstraints initialConstraint = new RowConstraints ((height/2)+20);
backstoryPane.getRowConstraints().add(initialConstraint);
int fadeDuration = 4000;
FadeTransition storyTextTransition1 = storyTextFade(storyLabel1, fadeDuration);
backstoryPane.getChildren().add(storyLabel1);
GridPane.setValignment(storyLabel1, VPos.BOTTOM);
GridPane.setHalignment(storyLabel1, HPos.CENTER);
storyTextTransition1.setOnFinished(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
backstoryPane.getChildren().remove(storyLabel1);
backstoryPane.getRowConstraints().remove(initialConstraint);
backstoryPane.getRowConstraints().add(new RowConstraints(25));
VBox vbox = new VBox (10);
backstoryPane.add(vbox, 0, 1);
vbox.setAlignment(Pos.TOP_CENTER);
ImageView dayAndNight = createImage ("Images/Day_And_Night.jpg");
Label storyLabel2 = createLabel("I was living in the city, following the same routine day and night.");
vbox.getChildren().add(dayAndNight);
vbox.getChildren().add(storyLabel2);
storyImageFade(dayAndNight, fadeDuration);
FadeTransition storyTextTransition2 = storyTextFade(storyLabel2, fadeDuration);
String officeReception = "Images/Office_Reception.jpg";
String receptionText = "Seeing the same faces every morning.";
FadeTransition storyTextTransition3 = nextPicture (storyTextTransition2, officeReception, receptionText, fadeDuration, vbox);
String office = "Images/Office.jpg";
String officeText = "Doing the same work every day.";
FadeTransition storyTextTransition4 = nextPicture (storyTextTransition3, office, officeText, fadeDuration, vbox);
}
});
//mediaPlayer.stop();
//introExplanation (stage, nameEntry, width, height, color);
}
These are the functions that are called within it:
private Label createLabel(String labelText) {
Label storyLabel = new Label(labelText);
Font storyFont = Font.font( "Blackadder ITC", 25 );
storyLabel.setTextFill(Color.INDIANRED);
storyLabel.setFont(storyFont);
return storyLabel;
}
private FadeTransition storyTextFade(Label label, int duration) {
FadeTransition storyTransition = new FadeTransition(Duration.millis(duration), label);
storyTransition.setFromValue(0);
storyTransition.setToValue(1);
storyTransition.setCycleCount(2);
storyTransition.setAutoReverse(true);
storyTransition.play();
return storyTransition;
}
private void storyImageFade(ImageView image, int duration) {
FadeTransition imageTransition = new FadeTransition(Duration.millis(duration), image);
imageTransition.setFromValue(0);
imageTransition.setToValue(1);
imageTransition.setCycleCount(2);
imageTransition.setAutoReverse(true);
imageTransition.play();
}
private ImageView createImage (String imageName) {
Image image = new Image(imageName);
ImageView imageview = new ImageView(image);
imageview.setFitWidth(500);
imageview.setFitHeight(500);
//imageview.setPreserveRatio(true);
imageview.setSmooth(true);
imageview.setCache(true);
return imageview;
}
private FadeTransition nextPicture (FadeTransition transition, String image, String imageLabel, int fadeDuration, VBox vbox) {
ArrayList<FadeTransition> transitionList = new ArrayList<FadeTransition>();
transition.setOnFinished(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
vbox.getChildren().clear();
ImageView imageview = createImage (image);
storyImageFade(imageview, fadeDuration);
Label storyLabel = createLabel(imageLabel);
FadeTransition storyTextTransition = storyTextFade(storyLabel, fadeDuration);
transitionList.add(storyTextTransition);
vbox.getChildren().add(imageview);
vbox.getChildren().add(storyLabel);
}
});
return transitionList.get(0);
}
Thanks!
This is my first response, so I do apologize if I'm not responding appropriately.
I was facing the same issue when transitioning between scenes. My solution was to set the node opacity to 0 before adding the node to the container.
For your case, it appears as though all of your labels and images are created in the createLabel and createImage methods, and the resulting values are what are being faded in.
private Label createLabel(String labelText) {
Label storyLabel = new Label(labelText);
Font storyFont = Font.font( "Blackadder ITC", 25 );
storyLabel.setTextFill(Color.INDIANRED);
storyLabel.setFont(storyFont);
// Set the opacity before returning the object
storyLabel.setOpacity(0);
return storyLabel;
}
private ImageView createImage (String imageName) {
Image image = new Image(imageName);
ImageView imageview = new ImageView(image);
imageview.setFitWidth(500);
imageview.setFitHeight(500);
//imageview.setPreserveRatio(true);
imageview.setSmooth(true);
imageview.setCache(true);
// Set the opacity before returning the object
imageview.setOpacity(0);
return imageview;
}
I hope this helps.

MonoGame - WinForm for homescreen?

I'm starting a project with monogame. I've made games with MonoGame before, but I felt the switching between multiple forms and monogame was clunky. For example I had a homescreen with buttons to Play, Hiscores & Quit. So I had forms for the homescreen and the hiscores. And then when you clicked Play the actualy MonoGame game would open.
Am I supposed to create everything in MonoGame? Or do I use panels in a single Form?
What I did to make it easier for myself is to make a class called "Screen", and just make a List<Screen> that holds all the different screens, so now, all I have to do to switch screen is set "Visible" to false or true on the screens I want to show or hide.
Here is part of how that class looks
public class Screen
{
public int ID;
public string Name;
public List<Form> Forms = new List<Form>();
public List<Label> Labels = new List<Label>();
public List<Button> Buttons = new List<Button>();
public List<Textbox> Textboxes = new List<Textbox>();
public List<EViewport> Viewports = new List<EViewport>();
public bool Visible;
// and a bunch of functions to add forms, buttons, do events, etc
// when adding a control, it's important that it is set to the right viewport
public Button AddButton(int _ID, string _Name, Texture2D _Sprite, int _Width, int _Height, Vector2 _Position, EViewport _Viewport, string _Text = "", bool _Visible = false)
{
Buttons.Add(new Button(_ID, _Name, _Sprite, _Width, _Height, new Vector2(_Position.X, _Position.Y), _Text, _Visible));
Button getButton = Buttons[Buttons.Count - 1];
getButton.ParentScreen = this;
getButton.ParentViewport = _Viewport;
return getButton;
}
public void Draw(SpriteBatch _spriteBatch, SpriteFont font, GameTime gameTime, Textbox focusedTextbox)
{
if (Visible)
{
// Draw only if screen is visible (this is not the full Draw function btw)
for(int j = 0; j < Viewports.Count; j++)
{
for(int i = 0; i < Buttons.Count; i++)
{
if(Buttons[i].ParentViewport.ID == Viewports[j].ID) // then draw
}
}
}
}
}
So basically all I do is add buttons, forms and viewports (because on my main menu I only need one viewport, but in-game I need 3 different viewports (one for game screen, one for UI and one for the chat) and then change their visibility like this:
storage.GetScreenByName("GameScreen").Visible = true;
(storage is just a singleton class that holds the sprite objects and screens in my game)
Oh, by the way, here's my EViewport class:
public class EViewport
{
/* Extended Viewport */
public Viewport _Viewport;
public Screen ParentScreen = new Screen();
public int ID;
public string Name;
public bool AllowResize;
public int MaxWidth;
public int MaxHeight;
public int MinHeight;
public float AspectRatio { get { return (float)MaxWidth / (float)MaxHeight; } }
public EViewport()
{
ID = -1;
}
public EViewport(int _ID, string _Name, int x, int y, int width, int height, bool _AllowResize = false, int _MinHeight = 0)
{
ID = _ID;
Name = _Name;
_Viewport = new Viewport(x, y, width, height);
AllowResize = _AllowResize;
MinHeight = _MinHeight;
MaxWidth = width;
MaxHeight = height;
}
public bool HasParentScreen()
{
return (ParentScreen.ID != -1);
}
}
I hope this helps, feel free to ask questions regarding how to implement such a system.

Is there any way to find a string's position and click on it using robotium?

I have the following list appearing on UI of an android application which tells about the date and the temperature on that date.
temp degree
11/01 --.-- c
11/02 21.7 c
11/03 22.5 c
Here I want to find the position of string "--.--" and then click on it, so that I can update the list. Is there any way to find the position of string? I know that solo.searchText() will tell whether the string is present or not, but what about the position?
// i think it will help you
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, final View view,
int position, long id) {
// TODO Auto-generated method stub
if(yourliststring.trim().equals("--.--"))
{
//your condition
}
else
{
//your condition
}
}
});
I got a simple way to find and click on the string
if(solo.searchText("--.--")){
solo.clickLongOnText("--.--");
}
All I need is to click on the string "--.--".
I'm not sure what position you need, however if you need position on screen you can simple do:
TextView textView = solo.getText("--.--"); // or solo.getText(Pattern.quote("--.--")); if needed
int[] xy = new int[2];
textView.getLocationOnScreen(xy);
final int viewWidth = textView.getWidth();
final int viewHeight = textView.getHeight();
final float x = xy[0] + (viewWidth / 2.0f);
final float y = xy[1] + (viewHeight / 2.0f);
this way you have central point of view (x, y).
If you need position of text in list, you can do:
private int getPosition(ListView listView, String text) {
for (int i = 0; i < listView.getAdapter().getCount(); i++) {
Object o = listView.getAdapter.getItemAtPosition(i);
if (o instanceof TextView) {
if (((TextView)o).getText().toString().equals(text)) {
return i;
}
}
}
return -1; // not found
}
you can call it for instance this way (set proper parameters):
int position = getPosition((ListView) solo.getView(ListView.class, 0), "--.--");
Everything written without testing and even compiling, however main idea should be fine.

How to get the index of an item at a specific offset from the top in Android ListView

Is there a simple way for getting the index of a list item which is in a specific offset from the top?
For example, get the index of an item which appears 150 pixels from the top.
Since your goal is to find which list item is in the center of the screen, you could try something like the following:
(Make a custom class that extends ListView, such as MyListView.java)
public class MyListView extends ListView implements OnScrollListener {
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
setOnScrollListener(this);
}
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// Center the child currently closest to the center of the ListView when
// the ListView stops scrolling.
if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) {
int listViewCenterX = getWidth() / 2;
int listViewCenterY = getHeight() / 2;
Rect rect = new Rect();
// Iterate the children and find which one is currently the most
// centered.
for (int i = 0; i < getChildCount(); ++i) {
View child = getChildAt(i);
child.getHitRect(rect);
if (rect.contains(listViewCenterX, listViewCenterY)) {
// this listitem is in the "center" of the listview
// do what you want with it.
final int position = getPositionForView(child);
final int offset = listViewCenterY - (child.getHeight() / 2);
break;
}
}
}
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
}
You can iterate through children and check each ones hit rectangle against the point you have.

How to draw faster? SurfaceView, SurfaceHolder dirty rect

I have a problem with SurfaceView.
Function DrawWave is call by a timer Interval 5ms, BUT actually it needs more than 30ms between two calls, (I tried delete drawColor, drawPath).
I tried as "Mode 1" and "Mode 2", by using Dirty rect, hope it can run faster. The Interval is the same, both more than 30ms, (The width of this is 800px, and eScrX-sScrX<20px)
Question 1: Is it something I do wrong, using SurfaceView/SurfaceHolder?
Question 2: What can I do to improve the drawing speed? I hope that it can finish drawing in 10 ms.
My code:
public class VS_VChannel extends SurfaceView
{//Wave Show Class
//-------------------------------------------------------------------------------
private Paint paint = new Paint();
private SurfaceHolder sHolder = null;
private Canvas cvs = null;
private Path P = new Path();
//Data source of the wave point Y
protected VSChannel Channel = null;
private float drawY;
//-------------------------------------------------------------------------------
public VS_VChannel(Context context)
{
super(context);
}
//------------------------------------------------------------------------------
public VS_VChannel(Context context, AttributeSet attrs)
{
super(context, attrs);
//Bind the wave data source whith AttributeSet name:vs_wave
String vsName = attrs.getAttributeValue(null, "vs_wave");
Channel = (VSChannel)VS.GetItem(vsName);//Find the wave data source from collection with name
//
paint.setAntiAlias(true);
paint.setDither(true);
paint.setColor(Channel.getColor());
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
//
sHolder = this.getHolder();
this.setZOrderOnTop(true);
sHolder.setFormat(PixelFormat.TRANSPARENT);
}
//------------------------------------------------------------------------------
/** DrawWave is Call by a timer Interval 5ms,
* BUT actually it need more than 30ms between twice call,(tried delete drawColor, drawPath)
* I try as "Mode 1" and "Mode 2", by using Dirty rect, hope it can run faster
* The Interval is the same, both more than 30ms,
* (The width of this is 800px, and eScrX-sScrX<20px)
*/
protected void DrawWave(int sScrX, int eScrX)
{
Rect rect = new Rect(sScrX, 0, eScrX+8, getHeight()); //Mode 1
//Rect rect = new Rect(0, 0, getWidth(), getHeight()); //Mode 2
//
cvs = sHolder.lockCanvas(rect);
cvs.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
cvs.drawPath(P, paint);
sHolder.unlockCanvasAndPost(cvs);
}
//-------------------------------------------------------------------------------
protected void GetWaveY()
{
drawY = Channel.GetWaveY(getHeight());
}
//-------------------------------------------------------------------------------
protected void MoveTo(float x)
{
P.moveTo(x, drawY);
}
//-------------------------------------------------------------------------------
protected void LineTo(float x)
{
P.lineTo(x, drawY);
}
//-------------------------------------------------------------------------------
protected void DrawReturn()
{
P.reset();//Clear
P.moveTo(0, drawY);
}
//-------------------------------------------------------------------------------
}
//-------------------------------------------------------------------------------
If you are running on top of the display thread, you can only process and draw as fast as that thread allows. I might suggest drawing to a bitmap in another thread and then using the surface holder to unlock, draw the bitmap, and post.