Android Custom View always getting 0 width when calling onMeasure - java

I'm fairly new to android dev and am trying to learn ropes. In order to do that I've been messing around Custom Views in android. I am trying to build an alarm clock app and I want to make a nice spinner to select the times from. Similar to say this:
http://i47.tinypic.com/aymyjc.jpg
I have created an AndroidScollSpinner class that looks like this:
public class AndroidScrollSpinner extends View {
public AndroidScrollSpinner(Context context) {
super(context);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawBackground(canvas);
drawSomeText(canvas);
canvas.restore();
}
private void drawSomeText(Canvas canvas) {
Paint titlePaint = new Paint();
titlePaint.setColor(Color.BLUE);
canvas.drawTextOnPath("Bert", new Path(), 0.0f,0.0f, titlePaint);
}
private void drawBackground(Canvas canvas) {
Paint backgroundPaint = new Paint();
backgroundPaint.setColor(getResources().getColor(R.color.bluegrass));
backgroundPaint.setStyle(Paint.Style.FILL);
Bitmap background = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
canvas.drawBitmap(background, 0, 0, backgroundPaint);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int minw = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();
int w = Math.max(minw, MeasureSpec.getSize(widthMeasureSpec));
int h = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(w, h);
}
}
The issue I am having is in the onMeasure
The MeasureSpec.getSize(widthMeasureSpec) always returns 0. Does anyone know why? Or what I am missing here?
Here's my layout file as well.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:id="#+id/addAlarmSpinnerLayout">
</LinearLayout>
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content">
<ToggleButton android:id="#+id/sundayToggleButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.14"
android:textOn="#string/S"
android:textOff="#string/S"/>
<ToggleButton android:id="#+id/mondayToggleButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.14"
android:textOn="#string/M"
android:textOff="#string/M"/>
<ToggleButton android:id="#+id/tuesdayToggleButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.14"
android:textOn="#string/T"
android:textOff="#string/T"/>
<ToggleButton android:id="#+id/wednesdayToggleButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.14"
android:textOn="#string/W"
android:textOff="#string/W"/>
<ToggleButton android:id="#+id/thursdayToggleButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.14"
android:textOn="#string/T"
android:textOff="#string/T"/>
<ToggleButton android:id="#+id/fridayToggleButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.14"
android:textOn="#string/F"
android:textOff="#string/F"/>
<ToggleButton android:id="#+id/saturdayToggleButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.14"
android:textOn="#string/S"
android:textOff="#string/S"/>
</LinearLayout>
<Button android:id="#+id/doneButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/done"
android:onClick="onDoneClicked">
</Button>
<Switch
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hour24Clock"
android:id="#+id/hour24switch"
android:layout_gravity="center"
android:enabled="true"
android:onClick="createSpinners"/>
</LinearLayout>
If you need to know anything else about the app, have a look here under https://github.com/rdsmallwood928/NeverLate
Also I do realize that there probably third party libraries out there that I can use to get the spinner effect that I want. However, I'm really doing this as a learning exercise so it more important to me to understand why this code always returns 0 than to inject a custom component from somewhere else and get on with my life. Thanks in advance for your help!
EDIT: Here is the AddAlarmFragment class that creates the spinners
public class AddAlarmFragment extends Fragment {
private AndroidClickSpinner minuteSpinner;
private AndroidClickSpinner hourSpinner;
private AndroidClickSpinner amPmSpinner;
private ToggleButton mondayToggle;
private ToggleButton tuesdayToggle;
private ToggleButton wednesdayToggle;
private ToggleButton thursdayToggle;
private ToggleButton fridayToggle;
private ToggleButton saturdayToggle;
private ToggleButton sundayToggle;
private Switch hour24Switch = null;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.add_alarm, container, false);
}
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
createSpinners(view);
}
#Override
public void onResume() {
super.onResume();
}
public void createSpinners(View view) {
LinearLayout layout = (LinearLayout) view.findViewById(R.id.addAlarmSpinnerLayout);
hour24Switch = (Switch) view.findViewById(R.id.hour24switch);
layout.removeAllViews();
ArrayList<Object> hours = new ArrayList<>();
if(hour24Switch.isChecked()) {
for(int i=0;i<24;i++) hours.add(i);
} else {
for(int i=1;i<=12;i++) hours.add(i);
}
hourSpinner = new AndroidClickSpinner(getActivity(), hours);
layout.addView(hourSpinner);
ArrayList<Object> minutes = new ArrayList<>();
for(int i=0;i<=60;i++) minutes.add(i);
minuteSpinner = new AndroidClickSpinner(getActivity(), minutes);
layout.addView(minuteSpinner);
if(!hour24Switch.isChecked()) {
ArrayList<Object> amPm = new ArrayList<>();
amPm.add("AM");
amPm.add("PM");
amPmSpinner = new AndroidClickSpinner(getActivity(), amPm);
layout.addView(amPmSpinner);
}
mondayToggle = (ToggleButton) view.findViewById(R.id.mondayToggleButton);
tuesdayToggle = (ToggleButton) view.findViewById(R.id.tuesdayToggleButton);
wednesdayToggle = (ToggleButton) view.findViewById(R.id.wednesdayToggleButton);
thursdayToggle = (ToggleButton) view.findViewById(R.id.thursdayToggleButton);
fridayToggle = (ToggleButton) view.findViewById(R.id.fridayToggleButton);
saturdayToggle = (ToggleButton) view.findViewById(R.id.saturdayToggleButton);
sundayToggle = (ToggleButton) view.findViewById(R.id.sundayToggleButton);
//Prevent no day selected...
switch (new LocalDate().getDayOfWeek()) {
case 1:
mondayToggle.setSelected(true);
break;
case 2:
tuesdayToggle.setSelected(true);
break;
case 3:
wednesdayToggle.setSelected(true);
break;
case 4:
thursdayToggle.setSelected(true);
break;
case 5:
fridayToggle.setSelected(true);
break;
case 6:
saturdayToggle.setSelected(true);
break;
case 7:
sundayToggle.setSelected(true);
break;
}
PieChart pie = new PieChart(getActivity());
Resources res = getResources();
pie.addItem("Agamemnon", 2, res.getColor(R.color.seafoam));
pie.addItem("Bocephus", 3.5f, res.getColor(R.color.chartreuse));
pie.addItem("Calliope", 2.5f, res.getColor(R.color.emerald));
pie.addItem("Daedalus", 3, res.getColor(R.color.bluegrass));
pie.addItem("Euripides", 1, res.getColor(R.color.turquoise));
pie.addItem("Ganymede", 3, res.getColor(R.color.slate));
layout.addView(pie);
layout.addView(new AndroidScrollSpinner(getActivity()));
}
public Integer getHours() {
Integer hour = Integer.parseInt(hourSpinner.getSelectedItem().toString());
if(!hour24Switch.isChecked()) {
if(hour == 12) {
hour = 0;
}
if(amPmSpinner.getSelectedItem().equals("PM")) {
hour = hour + 12;
}
}
return hour;
}
public Integer getMinutes() {
return Integer.parseInt(minuteSpinner.getSelectedItem().toString());
}
public boolean[] getDays() {
boolean[] days = new boolean[7];
days[0] = mondayToggle.isChecked();
days[1] = tuesdayToggle.isChecked();
days[2] = wednesdayToggle.isChecked();
days[3] = thursdayToggle.isChecked();
days[4] = fridayToggle.isChecked();
days[5] = saturdayToggle.isChecked();
days[6] = sundayToggle.isChecked();
return days;
}
}

I'm sorry, but where in your layout you are using it ?
Are you adding it from code, since I couldn't see it included somewhere in your XML layout file

Related

OnClickListener on Bitmap animations in Android Studio throws NullPointerException [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
findViewByID returns null
(33 answers)
Closed 1 year ago.
I made a simple screen with two flying bird animations using SurfaceView and Bitmap. I'm now trying to add an OnClickListener to each animation, I want different sounds to be played depending on which animation is clicked using SoundPool but for now, I have just added a toast message to see if the OnClickListener works.
Im not sure how to go about this, the method I am currently trying is that I have added two different ImageButtons in the XML file and attach those ImageButtons to my Bitmaps.
I have added all the code but I think the problem lies in the draw() method.
Heres the Error I get
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ImageButton.setImageBitmap(android.graphics.Bitmap)' on a null object reference
The error message links to the following line of code
imgBtnPurple.setImageBitmap(resizedPurpleBird);
Code
public class PlayActivity extends AppCompatActivity {
surfaceView view;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
view = new surfaceView(this);
setContentView(view);
private class Anim extends Thread {
int counter = 0;
int counter2 = 0;
#Override
public void run() {
long last_updated_time = 0;
long delay = 150;
int[] purple_bird = {
R.drawable.bird1,
R.drawable.bird2
};
int[] red_bird = {
R.drawable.red1,
R.drawable.red2,
R.drawable.red3,
R.drawable.red4,
R.drawable.red5,
R.drawable.red6,
R.drawable.red7,
R.drawable.red8,
R.drawable.red9,
R.drawable.red10
};
while (true) {
boolean playing = true;
if (playing) {
long current_time = System.currentTimeMillis();
if (current_time > last_updated_time + delay) {
if (counter >= 2) {
counter = 0;
}
if (counter2 >= 4) {
counter2 = 0;
}
draw(purple_bird[counter], red_bird[counter2]);
last_updated_time = current_time;
counter++;
counter2++;
}
}
}
}
private void draw(int red_bird, int purple_bird) {
SurfaceHolder holder = getHolder();
Canvas canvas = holder.lockCanvas();
if (canvas != null) {
canvas.drawColor(Color.WHITE);
Paint paint = new Paint();
Bitmap purpleBird = BitmapFactory.decodeResource(getContext().getResources(), purple_bird);
Bitmap redBird = BitmapFactory.decodeResource(getContext().getResources(), red_bird);
Bitmap resizedRedBird = Bitmap.createScaledBitmap(redBird, (int) (redBird.getWidth() * 0.1), (int) (redBird.getHeight() * 0.1), true);
Bitmap resizedPurpleBird = Bitmap.createScaledBitmap(purpleBird, (int) (purpleBird.getWidth() * 0.4), (int) (purpleBird.getHeight() * 0.4), true);
canvas.drawBitmap(resizedRedBird, 100, 100, paint);
canvas.drawBitmap(resizedPurpleBird, 100, 600, paint);
holder.unlockCanvasAndPost(canvas);
ImageButton imgBtnPurple = (ImageButton) findViewById(R.id.imageBtnPurple);
imgBtnPurple.setImageBitmap(resizedPurpleBird);
imgBtnPurple.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(),"Hello Purple Bird", Toast.LENGTH_SHORT).show();
}
});
ImageButton imgBtnRed = (ImageButton) findViewById(R.id.imageBtnRed);
imgBtnRed.setImageBitmap(resizedRedBird);
imgBtnRed.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(),"Hello Red Bird",Toast.LENGTH_SHORT).show();
}
});
}
}
}
}
}
Layout Code
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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="match_parent"
android:layout_height="match_parent"
tools:context=".PlayActivity">
<ImageButton
android:id="#+id/imageBtnPurple"
android:layout_width="58dp"
android:layout_height="49dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.155"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.143"
app:srcCompat="#drawable/bird1" />
<ImageButton
android:id="#+id/imageBtnRed"
android:layout_width="54dp"
android:layout_height="45dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="#+id/imageBtnPurple"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="#+id/imageBtnPurple"
app:layout_constraintTop_toBottomOf="#+id/imageBtnPurple"
app:layout_constraintVertical_bias="0.332"
app:srcCompat="#drawable/red1" />
</androidx.constraintlayout.widget.ConstraintLayout>

Android Studio change background color multiple times with 1 button click

I am brand new to Android Studio and am trying to figure out how to change the background color of my start up app.
The moment the app loads, I see a button on the screen, and when I click, it goes to the color red.
What I want is when you click the button, it goes from red to green to blue than back to red.
However, I keep getting these errors:
Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
Compilation failed; see the compiler error output for details.
Error:(72, 9) error: class, interface, or enum expected
Main Activity XML File:
<?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:orientation="vertical"
android:id="#+id/layout">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Change Color"
android:onClick="onChangeColor"/>
</LinearLayout>
Test Activity Java Code:
private int colorIndex = 1;
public void onChangeColor(View view) {
int color;
if(colorIndex==0) {
color = Color.RED;
colorIndex = 1;
}else if(colorIndex==1) {
color = Color.GREEN;
colorIndex = 2;
}else {
//colorIndex = 2
color = Color.BLUE;
colorIndex = 0;
}
View layout = findViewById(R.id.layout);
layout.setBackgroundColor(color);
}
public class TestActivity extends AppCompatActivity {
View view;
//declare a string variable in java a class
//private var colour = "green";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View layout = findViewById(R.id.layout);
layout.setBackgroundColor(Color.RED);
view= this.getWindow().getDecorView();
view.setBackgroundResource(R.color.gray);
}
public void goRed(View v)
{
//if (colour == "green"){
view.setBackgroundResource(R.color.red);
//colour = "red";
//}
}
}
To give you a excellent help, it will be necessary to see you code.
Any way if i andersted you right maybe this will help you :
On your xml layout:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="#+id/layout">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Change Color"
android:onClick="onChangeColor"/>
</LinearLayout>
On your activity :
private int colorIndex = 1;
public void onChangeColor(View view) {
int color;
if(colorIndex==0) {
color = Color.RED;
colorIndex = 1;
}else if(colorIndex==1) {
color = Color.GREEN;
colorIndex = 2;
}else {
//colorIndex = 2
color = Color.BLUE;
colorIndex = 0;
}
View layout = findViewById(R.id.layout);
layout.setBackgroundColor(color);
}
On you onCreate in the activity
View layout = findViewById(R.id.layout);
layout.setBackgroundColor(Color.RED);
If I understood correctly what you want is, to transition over a series of colours over time, and each colour lasting for some 1-2 seconds. You can use Android's default CountDownTimer.
Keep Your xml layout same.
In your Activity:
public class TestActivity extends AppCompatActivity {
LinearLayout layout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
layout = (LinearLayout)findViewById(R.id.layout);
layout.setBackgroundColor(Color.RED);
}
public void onChangeColor(View view) {
// start your timer on button click
new CountDownTimer(3000, 1000) {
public void onTick(long millisUntilFinished) {
changeBackground(3-millisUntilFinished/1000);
}
}.start();
}
private void changeBackground(int colorIndex){
int color;
if(colorIndex==1) {
color = Color.GREEN;
}else if(colorIndex==2) {
color = Color.BLUE;
}else {
color = Color.RED;
}
layout.setBackgroundColor(color);
}
}
Hope this might help. If I misunderstood something please comment.
Edit: I typecasted View to LinearLayout

Invert reveal transition animation

Based from this example
I created a fab using the support design library to re create the same action. The reveal and the fab animation works well but now i've got 2 problems:
1) My fab contains an icon. When the fab start the animation (like in the gif) the icon become shelled because it change the scaleX and scaleY. So is there a way to prevent this?
2) The example creates the animation but it doesn't explain how invert the reveal.. I would that onKeyDown() the content reveled go back and appears again the fab.
This is the github project https://github.com/saulmm/Curved-Fab-Reveal-Example
and here the code i use:
For first my fab in the layout:
<FrameLayout
android:id="#+id/fab_container"
android:layout_below="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="-30dp"
android:elevation="2dp"
>
<include
android:id="#+id/voice_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
layout="#layout/voice_content_layout" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/myFAB"
android:transitionName="button_fab"
app:backgroundTint="#color/colorAccent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_mic_white_24dp"
app:elevation="2dp"
app:borderWidth="0dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
android:layout_gravity="bottom|right"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:onClick="onFabPressed" />
</FrameLayout>
Here's the rest of java code:
public void onFabPressed(View view) {
final float startX = myFab.getX();
AnimatorPath path = new AnimatorPath();
path.moveTo(0, 0);
path.curveTo(-200, 200, -400, 100, -600, 50);
final ObjectAnimator anim = ObjectAnimator.ofObject(this, "fabLoc",
new PathEvaluator(), path.getPoints().toArray());
anim.setInterpolator(new AccelerateInterpolator());
anim.setDuration(ANIMATION_DURATION);
anim.start();
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
if (Math.abs(startX - myFab.getX()) > MINIMUN_X_DISTANCE) {
if (!mRevealFlag) {
mFabContainer.setY(mFabContainer.getY() + mFabSize / 2);
myFab.animate()
.scaleXBy(SCALE_FACTOR)
.scaleYBy(SCALE_FACTOR)
.setListener(mEndRevealListener)
.setDuration(ANIMATION_DURATION);
mRevealFlag = true;
}
}
}
});
}
private AnimatorListenerAdapter mEndRevealListener = new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
myFab.setVisibility(View.INVISIBLE);
mFabContainer.setBackgroundColor(getResources().getColor(R.color.colorAccent));
for (int i = 0; i < voiceContentLayout.getChildCount(); i++) {
View v = voiceContentLayout.getChildAt(i);
ViewPropertyAnimator animator = v.animate()
.scaleX(1).scaleY(1)
.setDuration(ANIMATION_DURATION);
animator.setStartDelay(i * 50);
animator.start();
}
}
};
/**
* We need this setter to translate between the information the animator
* produces (a new "PathPoint" describing the current animated location)
* and the information that the button requires (an xy location). The
* setter will be called by the ObjectAnimator given the 'fabLoc'
* property string.
*/
public void setFabLoc(PathPoint newLoc) {
myFab.setTranslationX(newLoc.mX);
if (mRevealFlag)
myFab.setTranslationY(newLoc.mY - (mFabSize / 2));
else
myFab.setTranslationY(newLoc.mY);
}

Transition between decimal or double numbers

Imagine a number 10, then after user clicks a button it changes to 100. But how to make an efficient transition
10 -> 100,
that will display values like
12, 15, 18, ..., 97, 100 over 1 second.
I've seen something like that in "Cookie clicker" but couldn't find anything about that kind of transition in the source code.
I had an idea of a loop (for number1 < number2, do number1++), it will work fine for small numbers, but if 10 changes to 1 billion, then the loop will probably freeze the whole app.
Second idea is to get added value (100-10=90) and divide by 30 or 60 frames, and add this value with each frame. But what will happen if frame is dropped? - Probably value will not be added. What if user makes double click or the system adds values automatically?
Hope it gives an idea of what kind of number transition I need.
Maybe I overlooked and there is a simple approach? Any help is appreciated.
Hope this little demo using a ValueAnimator will inspire you to find an appropriate solution.
You can specify the duration of the animation (see code) and even adjust the frame-rate by saying mAnimator.setFrameDelay(frameDelay);.
By using animator.isRunning() or animator.isStarted() you can prevent double-click malfunction or other unwanted behaviour while the current animation is runnning.
The Main Activity:
/** ValueAnimator demo */
public class MainActivity extends Activity {
ValueAnimator mAnimator;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView tv = (TextView) findViewById(R.id.textview);
mAnimator = ValueAnimator.ofInt(1, 100).setDuration(1000);
mAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
mAnimator.addUpdateListener(new AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(final ValueAnimator animator) {
final Integer value = (Integer) animator.getAnimatedValue();
tv.setText(String.format("%04d", value));
}
});
mAnimator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animator) {
super.onAnimationEnd(animator);
final int endValue = Integer.parseInt((String) tv.getText());
mAnimator.setIntValues(endValue, endValue + 100);
}
});
}
/** Button callback */
public void onClick(final View view) {
if (!mAnimator.isStarted() && !mAnimator.isRunning()) {
mAnimator.start();
}
}
}
Simple demo layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp"
android:typeface="monospace"
android:text="0001" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Gimme +100"
android:onClick="onClick">
</Button>
Here's another demo (hope this answers your 2. question), which implements different behaviour dependent on single click or double-click on the button. Just experiment with it, you now have the basic building blocks to construct own behavour ...
/** ValueAnimator demo */
public class MainActivity extends Activity {
ValueAnimator mAnimator;
TextView mTv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTv = (TextView) findViewById(R.id.textview);
mAnimator = ValueAnimator.ofInt(1, 100).setDuration(1000);
mAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
mAnimator.addUpdateListener(new AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(final ValueAnimator animator) {
final Integer value = (Integer) animator.getAnimatedValue();
mTv.setText(String.format("%04d", value));
}
});
final Button button = (Button) findViewById(R.id.button);
final GestureDetector gestureDetector = new GestureDetector(this,
new GestureDetector.SimpleOnGestureListener() {
#Override
public boolean onDoubleTap(MotionEvent e) {
performAnimation(100);
return true;
}
#Override
public boolean onSingleTapConfirmed(MotionEvent e) {
performAnimation(0);
return true;
}
});
button.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
});
}
/** starts animation */
private void performAnimation(final int offset) {
if (!mAnimator.isStarted() && !mAnimator.isRunning()) {
final int endValue = Integer.parseInt((String) mTv.getText());
mAnimator.setIntValues(endValue + offset, endValue + 100 + offset);
mAnimator.start();
}
}
}
Don't forget to replace your layout file, since the click-attribute of the button has been removed:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp"
android:typeface="monospace"
android:text="0001" />
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Gimme +100" >
</Button>
</LinearLayout>
I guess you can do it by using different threads. Only main thread works with UI so you can divide the interval into small intervals and make a transitions in different threads.After send them to main thread and print. Hope it will help.

How to create an expandable list?

I need to create Collapse / Expand forms in Android. I am thinking about using either RelativeLayout or TableLayout for this purpose. But, what XML element make these forms expand and hide in android?
If you are not sure what I am not talking about, take an application like Sales Force for an example. There you have these expandable menus in all the forms. How can I do this?
Following is an example (taken from Sales Force)
When you expand these, it looks like below
You could do the following. create a layout that has the following:
1. A Heading or a textview with the label contacts
2. Below it a layout that has forms related to it
3. Add another textview below #2 and name it address
4. Add a lyout below #3 .
The layout 2 and 4 will have visibility gone in the first case
When the user taps on layout 1, or the first textview, make layout 2 visible and vice versa. Do the same with the second textview.
Hope that helps.!
I have had a similar problem, i want parts of my form to be hidden in sektions and created a class for this issue.
public class section extends LinearLayout{
public LinearLayout container;
public Button toggler;
public section(Context context, String section_name, String section_state) {
super(context);
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.flxsection, this);
container = (LinearLayout) this.findViewById(R.id.container);
container.setVisibility(section_state.equals("0") ? View.GONE:View.VISIBLE);
toggler = ((Button)this.findViewById(R.id.section_toggle));
toggler.setTag(section_state);
toggler.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
String tag = (String) v.getTag();
v.setTag(tag.equals("0") ? "1":"0");
if(tag.equals("0")){expand(container,false);}else{collapse(container,false);}
setImage(tag.equals("0"));
}
});
toggler.setText(" " + section_name);
setImage(section_state.equals("1"));
setTextSize();
}
public void setTextSize(){
toggler.setTextSize(GV.Style.TextSize);
}
public void setImage(boolean open){
int a = open ? R.drawable.minus_48_white: R.drawable.plus_48_white;
Drawable img = main.res.getDrawable(a);
final float scale = main.res.getDisplayMetrics().density;
int size = (int) (12 * scale + 0.5f);
img.setBounds(0,0,size,size);
toggler.setCompoundDrawables(img,null,null,null);
}
}
the xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
android:focusable="false"
android:layout_marginLeft="4dip"
android:layout_marginRight="4dip"
android:orientation="vertical" >
<Button
android:id="#+id/section_toggle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dip"
android:layout_marginTop="4dip"
android:background="#drawable/section"
android:drawableLeft="#drawable/plus_48"
android:focusable="false"
android:gravity="left|center_vertical"
android:padding="6dip"
android:textAppearance="?android:attr/textAppearanceLargeInverse"
android:textSize="22dip" />
<LinearLayout
android:id="#+id/container"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:focusable="false"
android:background="#android:color/transparent"
android:orientation="vertical" >
</LinearLayout>
Expand and collapse:
public static void expand(final View v,boolean quick) {
v.requestLayout();
v.measure(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
final int targtetHeight = v.getMeasuredHeight();
v.getLayoutParams().height = 0;
v.getLayoutParams().width = LayoutParams.FILL_PARENT;
v.setVisibility(View.VISIBLE);
if(quick){
v.getLayoutParams().height = LayoutParams.WRAP_CONTENT;
v.requestLayout();
}else{
android.view.animation.Animation a = new android.view.animation.Animation()
{
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
v.getLayoutParams().height = interpolatedTime == 1
? LayoutParams.WRAP_CONTENT
: (int)(targtetHeight * interpolatedTime);
v.requestLayout();
}
#Override
public boolean willChangeBounds() {
return true;
}
};
// 1dp/ms
int duration = (int)(targtetHeight / v.getContext().getResources().getDisplayMetrics().density);
if(duration> 500)duration=500;
a.setDuration(duration);
//(int)(targtetHeight / v.getContext().getResources().getDisplayMetrics().density)
v.startAnimation(a);
}
}
public static void collapse(final View v,boolean quick) {
v.requestLayout();
final int initialHeight = v.getMeasuredHeight();
if(quick){
v.setVisibility(View.GONE);
v.requestLayout();
}else{
android.view.animation.Animation a = new android.view.animation.Animation()
{
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
if(interpolatedTime == 1){
v.setVisibility(View.GONE);
}else{
v.getLayoutParams().height = initialHeight - (int)(initialHeight * interpolatedTime);
v.requestLayout();
}
}
#Override
public boolean willChangeBounds() {
return true;
}
};
// 1dp/ms
int duration = (int)( initialHeight/ v.getContext().getResources().getDisplayMetrics().density);
if(duration> 500)duration=500;
a.setDuration(duration);
v.startAnimation(a);
}
}
If if create a form and need a section, i create a instance of this class and add the controls.
You might need to turn the hardware acceleration on in order to get the best performance
edit:
Usage is like:
section s = new section(context, section_name, section_state);
s.container.addView([your view 1]);
s.container.addView([your view 2]);
s.container.addView([your view 3]);
//...
form.addView(s);

Categories

Resources