I need to make a credits screen (Activity) in my game. It would be just a vertically scrolling text lines without any images. Scrolling is to be performed automatically and no user interaction is allowed. Just like movie credits that goes from bottom to top. After the last text line has disappeared above top of the screen, it should restart.
How do I do it? It is sufficient to just use TextView and animate it somehow? Or should I put that TextView into ScrollView? What would you suggest?
I am using this :-
/**
* A TextView that scrolls it contents across the screen, in a similar fashion as movie credits roll
* across the theater screen.
*
* #author Matthias Kaeppler
*/
public class ScrollingTextView extends TextView implements Runnable {
private static final float DEFAULT_SPEED = 15.0f;
private Scroller scroller;
private float speed = DEFAULT_SPEED;
private boolean continuousScrolling = true;
public ScrollingTextView(Context context) {
super(context);
setup(context);
}
public ScrollingTextView(Context context, AttributeSet attributes) {
super(context, attributes);
setup(context);
}
private void setup(Context context) {
scroller = new Scroller(context, new LinearInterpolator());
setScroller(scroller);
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (scroller.isFinished()) {
scroll();
}
}
private void scroll() {
int viewHeight = getHeight();
int visibleHeight = viewHeight - getPaddingBottom() - getPaddingTop();
int lineHeight = getLineHeight();
int offset = -1 * visibleHeight;
int totallineHeight = getLineCount() * lineHeight;
int distance = totallineHeight + visibleHeight;
int duration = (int) (distance * speed);
if (totallineHeight > visibleHeight) {
scroller.startScroll(0, offset, 0, distance, duration);
if (continuousScrolling) {
post(this);
}
}
}
#Override
public void run() {
if (scroller.isFinished()) {
scroll();
} else {
post(this);
}
}
public void setSpeed(float speed) {
this.speed = speed;
}
public float getSpeed() {
return speed;
}
public void setContinuousScrolling(boolean continuousScrolling) {
this.continuousScrolling = continuousScrolling;
}
public boolean isContinuousScrolling() {
return continuousScrolling;
}
}
Related
I implement a custom SpinNumberView: it is square shaped (say 40x40), it has a vertical LinearLayout as a subview, within this linear layout are a bunch of 40x40 cells stacked vertically. I want to animate the cells to scroll vertically by changing offsetY of the LinearLayout.
But there is one problem: only the cell initially in bounds (the first) is rendered, the cells outside of the bounds are not drawn, so when I animate the LinearLayout to scroll, the linear layout is spinning, but only the first cell is visible, others are blank spaces. Here is my entire code for the custom View:
public class SpinNumberView extends RelativeLayout {
private int startNumber;
private int endNumber;
private int number;
private int gridsize;
private int index;
public static final double stepDuration = 0.1;
private boolean inAnimation = true;
ArrayList<Integer> numbers;
public LinearLayout container;
public SpinNumberView(Context context) {
super(context);
}
public SpinNumberView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void dispatchDraw(Canvas canvas) {
// draw the background black solid circle
float radius = (float)(this.gridsize);
Paint p = new Paint();
p.setStyle(Paint.Style.FILL);
p.setARGB(192, 0, 0, 0);
canvas.drawCircle(radius/2, radius/2, radius/2, p);
// draw 1px white border
Paint pp = new Paint();
pp.setStyle(Paint.Style.STROKE);
pp.setStrokeWidth(2.0f);
pp.setARGB(192, 255, 255, 255);
canvas.drawCircle(radius/2, radius/2, radius/2-1, pp);
// clip to the circle
Path path = new Path();
RectF r = new RectF((float)0.0, (float)0.0, radius, radius);
path.addRoundRect(r, radius/2, radius/2, Path.Direction.CW);
canvas.clipPath(path);
super.dispatchDraw(canvas);
}
#Override
protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
super.onLayout(b, i, i1, i2, i3);
}
class AniListener implements Animator.AnimatorListener {
#Override
public void onAnimationStart(Animator animator) {}
#Override
public void onAnimationEnd(Animator animator) {
SpinNumberView.this.animateStep();
}
#Override
public void onAnimationCancel(Animator animator) {}
#Override
public void onAnimationRepeat(Animator animator) {}
}
public void animateStep() {
this.container.setTranslationY(0);
float offset;
TimeInterpolator inter;
if(this.inAnimation) {
offset = (float)this.gridsize * this.numbers.size();
inter = new LinearInterpolator();
} else {
offset = (float)this.gridsize * this.index;
inter = new DecelerateInterpolator();
}
long duration = (long)(SpinNumberView.stepDuration * this.numbers.size() * 1000);
ViewPropertyAnimator ani = this.container.animate().translationYBy(-offset).setDuration(duration);
ani.setInterpolator(inter);
if(this.inAnimation) {
ani.setListener(new AniListener());
} else {
ani.setListener(null);
}
ani.start();
}
public void stopAnimation() {
this.inAnimation = false;
}
public void startAnimation() {
this.inAnimation = true;
float offset = (float)this.gridsize * this.numbers.size();
long duration = (long)(SpinNumberView.stepDuration * this.numbers.size() * 1000);
ViewPropertyAnimator ani = this.container.animate().translationYBy(-offset).setDuration(duration);
TimeInterpolator inter = new AccelerateInterpolator();
ani.setInterpolator(inter);
ani.setListener(new AniListener());
ani.start();
}
public void setup(int number, int start, int end, int gridsize) {
this.setBackgroundColor(Color.TRANSPARENT);
this.setAlpha((float) 0.5);
this.setClipChildren(false);
this.number = number;
this.startNumber = start;
this.endNumber = end;
this.gridsize = gridsize;
this.numbers = new ArrayList<>();
for(int i=start; i<=end;i++) {
this.numbers.add(i);
}
Collections.shuffle(this.numbers);
// Find index of target number within shuffled array
this.index = this.numbers.indexOf(this.number);
this.container = new LinearLayout(this.getContext());
this.container.setOrientation(LinearLayout.VERTICAL);
this.container.setGravity(Gravity.CENTER_HORIZONTAL);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(this.gridsize, this.gridsize * (this.numbers.size()+1));
this.container.setLayoutParams(params);
this.addView(this.container);
int offsety = 0;
// setup all the number views
for(int k=0;k<this.numbers.size()+1;k++) {
String txt;
if(k==this.numbers.size()) {
txt = Integer.toString(this.numbers.get(0));
} else {
txt = Integer.toString(this.numbers.get(k));
}
TextView tv = new TextView(this.getContext());
tv.setLayoutParams(new LayoutParams(this.gridsize, this.gridsize));
tv.setText(txt);
tv.setTextSize(24.0f);
tv.setTextColor(Color.WHITE);
tv.setTextAlignment(TextView.TEXT_ALIGNMENT_CENTER);
tv.setLines(1);
tv.setGravity(Gravity.CENTER_VERTICAL);
this.container.addView(tv);
offsety += this.gridsize;
}
this.invalidate();
}
}
Why is this happening?
BTW: I take a screenshot with getDrawingCache() of screen content, the cells are visible in the screenshot!
Yes! It happend when we get some view height or width of a view. Because didn't completely render the view when we call its height or width yet.
Solution:
Use this code to get Height and width
EditText edt = (EditText) findViewbyid(R.id.tv);
edt.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int height= edt.getHeight();
int width = edt.getHeight();
edt.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
To answer my own question:
When overriding onLayout() function, I need to layout the subviews myself like this:
#Override
protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
super.onLayout(b, i, i1, i2, i3);
this.container.layout(0, 0, this.gridsize, this.gridsize * (this.endNumber-this.startNumber+2));
}
Glad you solved it by yourself, in iOS, we use something like Redraw method for these scenarios. Hopefully it will help you to further optimize your code.
I have a TextView in an app, the text of which is set by a hard-coded string resource in the layout. In order to get a bulleted list in the TextView, I've used the (unofficial?) support for the <li> element. This creates properly-indented bullets, as desired, but the leftmost edge of the bullets themselves are slightly cut off, as you can see:
I have tried adding left padding to these, but it did nothing to the clipped edge - just moved the whole thing inwards.
Is there any simple solution to resolve this?
Where does the resource for that bulleted list live?
Old question but for anyone else finding this late:
I've found the built in BulletSpan class has had bugs from early android versions all the way through to marshmallow:
Bullet radius and gap width don't scale depending on dp
Bullets are sometimes cut off (should be + BULLET_RADIUS, not * BULLET_RADIUS)
Warning: I've seen a few custom BulletSpan classes out there which implement ParcelableSpan like the internal class. This WILL cause crashes and is not intended to be used externally.
Here's my BulletSpanCompat:
public class BulletSpanCompat implements LeadingMarginSpan {
private final int mGapWidth;
private final boolean mWantColor;
private final int mColor;
private static final int BULLET_RADIUS = MaterialDesignUtils.dpToPx(1.5f);
private static Path sBulletPath = null;
public static final int STANDARD_GAP_WIDTH = MaterialDesignUtils.dpToPx(8);
public BulletSpanCompat() {
mGapWidth = STANDARD_GAP_WIDTH;
mWantColor = false;
mColor = 0;
}
public BulletSpanCompat(int gapWidth) {
mGapWidth = gapWidth;
mWantColor = false;
mColor = 0;
}
public BulletSpanCompat(int gapWidth, int color) {
mGapWidth = gapWidth;
mWantColor = true;
mColor = color;
}
public BulletSpanCompat(Parcel src) {
mGapWidth = src.readInt();
mWantColor = src.readInt() != 0;
mColor = src.readInt();
}
public int getLeadingMargin(boolean first) {
return 2 * BULLET_RADIUS + mGapWidth;
}
public void drawLeadingMargin(Canvas c, Paint p, int x, int dir,
int top, int baseline, int bottom,
CharSequence text, int start, int end,
boolean first, Layout l) {
if (((Spanned) text).getSpanStart(this) == start) {
Paint.Style style = p.getStyle();
int oldcolor = 0;
if (mWantColor) {
oldcolor = p.getColor();
p.setColor(mColor);
}
p.setStyle(Paint.Style.FILL);
if (c.isHardwareAccelerated()) {
if (sBulletPath == null) {
sBulletPath = new Path();
// Bullet is slightly better to avoid aliasing artifacts on mdpi devices.
sBulletPath.addCircle(0.0f, 0.0f, 1.2f + BULLET_RADIUS, Path.Direction.CW);
}
c.save();
c.translate(x + dir + BULLET_RADIUS, (top + bottom) / 2.0f);
c.drawPath(sBulletPath, p);
c.restore();
} else {
c.drawCircle(x + dir + BULLET_RADIUS, (top + bottom) / 2.0f, BULLET_RADIUS, p);
}
if (mWantColor) {
p.setColor(oldcolor);
}
p.setStyle(style);
}
}
}
Try using the unicode character • (Unicode 2022)? Looks like you can just paste it into the XML.
http://www.fileformat.info/info/unicode/char/2022/index.htm
Please use below code:-
<CustomBulletTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Point1" />
<CustomBulletTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Point2" />
/* CustomBulletTextView.java */
public class CustomBulletTextView extends TextView {
public CustomBulletTextView(Context context) {
super(context);
addBullet();
}
public CustomBulletTextView(Context context, AttributeSet attrs) {
super(context, attrs);
addBullet();
}
public CustomBulletTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
addBullet();
}
public CustomBulletTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
addBullet();
}
private void addBullet() {
CharSequence text = getText();
if (TextUtils.isEmpty(text)) {
return;
}
SpannableString spannable = new SpannableString(text);
spannable.setSpan(new CustomBulletSpan(16), 0, text.length(), 0);
setText(spannable);
}
}
/* CustomBulletSpan.java */
public class CustomBulletSpan implements LeadingMarginSpan, ParcelableSpan {
private final int mGapWidth;
private final boolean mWantColor;
private final int mColor;
private static final int BULLET_RADIUS = 3;
private static Path sBulletPath = null;
public static final int STANDARD_GAP_WIDTH = 2;
public CustomBulletSpan(int gapWidth) {
mGapWidth = gapWidth;
mWantColor = false;
mColor = 0;
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mGapWidth);
dest.writeInt(mWantColor ? 1 : 0);
dest.writeInt(mColor);
}
public int getLeadingMargin(boolean first) {
return 2 * BULLET_RADIUS + mGapWidth;
}
public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom,
CharSequence text, int start, int end, boolean first, Layout l) {
// Here I shifted the bullets to right by the given half bullet
x += mGapWidth / 2;
if (((Spanned) text).getSpanStart(this) == start) {
Paint.Style style = p.getStyle();
int oldcolor = 0;
if (mWantColor) {
oldcolor = p.getColor();
p.setColor(mColor);
}
p.setStyle(Paint.Style.FILL);
if (c.isHardwareAccelerated()) {
if (sBulletPath == null) {
sBulletPath = new Path();
// Bullet is slightly better to avoid aliasing artifacts on
// mdpi devices.
sBulletPath.addCircle(0.0f, 0.0f, 1.2f * BULLET_RADIUS, Direction.CW);
}
c.save();
c.translate(x + dir * BULLET_RADIUS, (top + bottom) / 2.0f);
c.drawPath(sBulletPath, p);
c.restore();
} else {
c.drawCircle(x + dir * BULLET_RADIUS, (top + bottom) / 2.0f, BULLET_RADIUS, p);
}
if (mWantColor) {
p.setColor(oldcolor);
}
p.setStyle(style);
}
}
#Override
public int getSpanTypeId() {
return 0;
}
}
I have a class progress bar. Depending on the set value is partially fills the text with a different color. I want when I change the current value progress filling was going smoothly from one value to another for some time, rather than by a jump, as it is now. How can I achieve that?
Code of my TextProgressBar below:
package com.example.app.customviews;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Shader;
import android.graphics.Shader.TileMode;
import android.util.AttributeSet;
import android.widget.TextView;
import com.example.app.R;
public class TextProgressBar extends TextView {
private final int minValue = 0;
private int maxValue = 100;
private int currentValue = 0;
private float onePercentLenght = 1;
private int[] colors = {Color.WHITE, Color.BLACK};
private float[] pos = {0,1};
public TextProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.TextProgressBar,
0, 0);
try {
maxValue = a.getInt(R.styleable.TextProgressBar_MaxProgress, 100);
currentValue = a.getInteger(R.styleable.TextProgressBar_CurrentProgress, 0);
colors[0] = a.getColor(R.styleable.TextProgressBar_ProgressColor, Color.WHITE);
colors[1] = a.getColor(R.styleable.TextProgressBar_MainColor, Color.BLACK);
} finally {
a.recycle();
}
initShader();
}
public TextProgressBar(Context context) {
super(context);
initShader();
}
#Override
protected void onDraw(Canvas canvas) {
onePercentLenght = getWidth() / maxValue;
super.onDraw(canvas);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
initShader();
}
public void setProgress(int progress) {
if(progress < minValue) {
currentValue = minValue;
}
else if( progress > maxValue) {
currentValue = maxValue;
}
else {
currentValue = progress;
}
initShader();
invalidate();
}
public void setMaxProgress(int progress) {
if(progress>minValue) {
maxValue = progress;
}
else {
maxValue = minValue;
}
invalidate();
}
public int getMaxProgress() {
return maxValue;
}
public int getProgress() {
return currentValue;
}
private void initShader() {
float x = 0, dx = (currentValue+1) * onePercentLenght;
if(dx < 0) {
dx = 0;
}
if(dx - 1 < 0) {
x = 0;
}
else {
x = dx - 1;
}
Shader textShader = new LinearGradient(x, 0, dx, 0, colors, pos, TileMode.CLAMP);
getPaint().setShader(textShader);
}
}
I tested following approach triggering progress following way:
10, 30 with 150ms delay, 40 with 250ms delay, 80 with 50ms delay, and 100 with 450ms delay. One little weird thing is that it seems the drawing happens with little bit delay, although log print is on time, not sure if this is about my device. But this could give you something to start with. Adjusting the MAX_INTERVAL_TIME you can get it smoother depending how often you are settings the progress. If the callback is something you get from network, then it's nearly possible to get it all smooth since you can't predict the progress.
private static final int MAX_INTERVAL_TIME = 500;
private CountDownTimer mCountDownTimer;
public void setProgress(final int progress) {
final int startWidth = currentValue == maxValue ? 0 : currentValue;
final int endWidth = (int) (maxValue * ((float) progress / maxValue));
if (progress < minValue) {
currentValue = minValue;
} else if (progress > maxValue) {
currentValue = maxValue;
} else {
currentValue = progress;
}
if (mCountDownTimer != null) {
mCountDownTimer.cancel();
}
mCountDownTimer = new CountDownTimer(MAX_INTERVAL_TIME, 10) {
#Override
public void onTick(long millisUntilFinished) {
float interpolatedTime = 1 - ((float) millisUntilFinished / MAX_INTERVAL_TIME);
currentValue = startWidth
+ ((int) ((endWidth - startWidth) * interpolatedTime));
initShader();
invalidate();
}
#Override
public void onFinish() {
if (progress == maxValue) {
currentValue = maxValue;
initShader();
invalidate();
}
}
}.start();
}
If you know the time you wan't to animate the progress you could simply try following with your existing code:
final TextProgressBar text = (TextProgressBar) getView().findViewById(
R.id.test);
final int animTime = 1000;
new CountDownTimer(animTime, 200) {
#Override
public void onTick(long millisUntilFinished) {
float progress = (1 - ((float) millisUntilFinished / (float) animTime))
* text.getMaxProgress();
text.setProgress((int) progress);
}
#Override
public void onFinish() {
text.setProgress(text.getMaxProgress());
}
}.start();
I have some dependent scrollview means (when I scroll one view others will also scroll). I am able to do it properly, but now I want to manage the speed of scroll means (when I scroll my scrollview1 than scrollview2 should scroll +10 and scrollview3 should scroll +20 or whatever speed) same for other (scrollview2, and scrollview3) also.
I check there is a method called scrollview.scrollto(x,y). Which used to manage the scroll but when i increase scollto(x, y+scrollviews(i).getSpeed()) than it gives me stackOverflow exception.
I am attaching my code please look into this and give me some suggestion how can solve this problem.
My custom scrollView class is:
public class CustomVerticalObserveScroll extends ScrollView {
private GestureDetector mGestureDetector;
View.OnTouchListener mGestureListener;
public CustomVerticalObserveScroll(Context context, AttributeSet attrs) {
super(context, attrs);
mGestureDetector = new GestureDetector(context, new YScrollDetector());
setFadingEdgeLength(0);
// TODO Auto-generated constructor stub
}
private CustomScrollLisner scrollViewListener = null;
public CustomVerticalObserveScroll(Context context) {
super(context);
mGestureDetector = new GestureDetector(context, new YScrollDetector());
setFadingEdgeLength(0);
}
public CustomVerticalObserveScroll(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
mGestureDetector = new GestureDetector(context, new YScrollDetector());
setFadingEdgeLength(0);
}
public void setScrollViewListener(CustomScrollLisner scrollViewListener) {
this.scrollViewListener = scrollViewListener;
}
#Override
protected void onScrollChanged(int x, int y, int oldx, int oldy) {
super.onScrollChanged(x, y, oldx, oldy);
if (scrollViewListener != null) {
scrollViewListener.onScrollChanged(this, x, y, oldx, oldy);
}
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return super.onInterceptTouchEvent(ev)
&& mGestureDetector.onTouchEvent(ev);
}
// Return false if we're scrolling in the x direction
class YScrollDetector extends SimpleOnGestureListener {
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
if (Math.abs(distanceY) > Math.abs(distanceX)) {
return true;
}
if (Math.abs(distanceX) > Math.abs(distanceY)) {
return true;
}
return false;
}
}
}
and this code I am using to make scroll dependent scroll views.
public class RelativePanoFeature implements IFeaturetype, OnTouchListener {
private String type;
private FeatureCordinates locationCordinates;
private int mOrientation;
private String image;
private FeatureCordinates triggerCordinates;
private String scrollDirection;
private String scrollSpeed;
private String scrollHandler;
CustomVerticalObserveScroll vertical_scroll;
CustomHorizontalObserveScroll horizontal_scroll;
RelativeLayout vsChild;
long timeonDown, timeonUp;
Thread t;
Handler mhandler;
float downx, downy;
int touchId;
public static int scrollid = 0;
public static ArrayList<RelativePanoHandler> storePanoHandler = new ArrayList<RelativePanoHandler>();
public RelativePanoFeature(String type) {
this.type = type;
}
#Override
public void setType(String type) {
this.type = type;
}
#Override
public String getType() {
return type;
}
public void setImage(String image) {
this.image = image;
}
public String getImage() {
return image;
}
public FeatureCordinates getLocation() {
return locationCordinates;
}
public void setLocation(FeatureCordinates featureCordinates) {
this.locationCordinates = featureCordinates;
}
public void setOrientation(int mOrientation) {
this.mOrientation = mOrientation;
}
public int getOrientation() {
return mOrientation;
}
public FeatureCordinates getTrigger() {
return triggerCordinates;
}
public void setTrigger(FeatureCordinates trigger) {
this.triggerCordinates = trigger;
}
public void setScrollDirection(String scrollDirection) {
this.scrollDirection = scrollDirection;
}
public String getScrollDirection() {
return scrollDirection;
}
public void setScrollSpeed(String scrollSpeed) {
this.scrollSpeed = scrollSpeed;
}
public String getScrollSpeed() {
return scrollSpeed;
}
public void setScrollHandler(String scrollHandler) {
this.scrollHandler = scrollHandler;
}
public String getScrollHandler() {
return scrollHandler;
}
public void setTouchId(int touchid) {
this.touchId = touchid;
}
public int getTOuchId() {
return touchId;
}
/* function to draw relative pano */
public void drawRelativePano(final Context con,
final RelativeLayout parent, final Handler handle) {
/* splitting the path from images key in the string */
RelativePanoHandler panHandler = new RelativePanoHandler();
final int height;
final int width;
vsChild = new RelativeLayout(con);
mhandler = handle;
/* giving size of of vertical scroll's child */
LayoutParams imageViewLayoutParams = new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
vsChild.setLayoutParams(imageViewLayoutParams);
/* splitting the path from images key in the string */
String path[] = getImage().split("images");
try {
/* Initialise loader to load the image inside child */
BackgroundImageLoader loader = new BackgroundImageLoader(vsChild,
Property.FILEPATH + path[1], con);
try {
loader.execute();
} catch (IllegalStateException e) {
e.printStackTrace();
}
/* getting height and width of image from loader object */
height = loader.get().getHeight();
width = loader.get().getWidth();
/*
* condition for putting the child view in vertical scroll and
* implementing the multi directional scroll for event pano
*/
int locWidth = getLocation().getWidth(), locHeight = getLocation()
.getHeight();
System.out.println("Width= " + width + " Location width= "
+ locWidth);
System.out.println("Heoght= " + height + " Location Height= "
+ locHeight
);
if (width > (getLocation().getWidth())
|| height > (getLocation().getHeight())) {
vertical_scroll = new CustomVerticalObserveScroll(con);
horizontal_scroll = new CustomHorizontalObserveScroll(con);
vertical_scroll.setFillViewport(true);
horizontal_scroll.setFillViewport(true);
vertical_scroll.setId(scrollid);
horizontal_scroll.setFadingEdgeLength(0);
/*
* adding the soft later on vertical and horizontal scroll if
* the detected device is on api level 10 or more than that
*/
if (Build.VERSION.SDK_INT > 10) {
vertical_scroll
.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
horizontal_scroll.setLayerType(View.LAYER_TYPE_SOFTWARE,
null);
}
vsChild.setEnabled(true);
/*
* parameters for setting the height and width of vertical
* scroll
*/
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
getLocation().getWidth(), getLocation().getHeight());
params.leftMargin = getLocation().getX();
params.topMargin = getLocation().getY();
vertical_scroll.setLayoutParams(params);
/* adding vertical scroll child this child will hold the image */
vertical_scroll.addView(vsChild, width, height);
horizontal_scroll.setLayoutParams(params);
/*
* adding vertical scroll as a child of horizontal scroll for
* multidirectional scrolling
*/
horizontal_scroll.addView(vertical_scroll);
/*
* at last add this horizontal scroll in side parent which will
* hold the multidirectional scroll
*/
parent.setTag(getScrollHandler());
parent.addView(horizontal_scroll);
// vertical_scroll.setId(id)
panHandler.setVerticalScroll(vertical_scroll);
panHandler.setHandlerTag(getScrollHandler());
panHandler.setPanoSpeed(Integer.parseInt(getScrollSpeed()));
storePanoHandler.add(panHandler);
int size = storePanoHandler.size();
System.out.println("Vertical Scroll objec size=" + size);
}
System.out.println("TAg= " + parent.getTag());
String scdir = getScrollDirection();
System.out.println("Scroll Directoion= " + scdir);
scrollid++;
if (getScrollDirection().equalsIgnoreCase("Y")) {
vertical_scroll.setScrollViewListener(new CustomScrollLisner() {
#Override
public void onScrollChanged(
CustomHorizontalObserveScroll scrollView, int x,
int y, int oldx, int oldy) {
}
#Override
public void onScrollChanged(
CustomVerticalObserveScroll scrollView, int x,
int y, int oldx, int oldy) {
if (scrollView == storePanoHandler.get(getTOuchId())
.getVerticalScroll()) {
for (int i = 0; i < storePanoHandler.size(); i++) {
storePanoHandler.get(i).getVerticalScroll()
.scrollTo(x, y);
storePanoHandler.get(i).getVerticalScroll().
// storePanoHandler.
// .get(i)
// .getVerticalScroll()
// .scrollTo(
// x,
// oldy
// + storePanoHandler.get(
// i)
// .getPanoSpeed());
}
}
}
});
}
// if (getScrollDirection().equalsIgnoreCase("X")) {
// vertical_scroll.setScrollViewListener(new CustomScrollLisner() {
//
// #Override
// public void onScrollChanged(
// CustomHorizontalObserveScroll scrollView, int x,
// int y, int oldx, int oldy) {
// // if (scrollView == storePanoHandler.get(getTOuchId())
// // .getVerticalScroll()) {
// //
// // for (int i = 0; i < storePanoHandler.size(); i++) {
// // storePanoHandler.get(i).getVerticalScroll()
// // .smoothScrollTo(x, y);
// //
// // }
// // }
// }
//
// #Override
// public void onScrollChanged(
// CustomVerticalObserveScroll scrollView, int x,
// int y, int oldx, int oldy) {
// }
// });
// }
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
/*
* set touch listeners on vertical and horizontal scrolls it will use to
* disable the scroll for it's parent like [image or view pager when
* user interacting with any of custom scroll]
*/
horizontal_scroll.setOnTouchListener(this);
vertical_scroll.setOnTouchListener(this);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
boolean scrollingPanaroma = true;
// changing token value for getting scroll
if (v == vertical_scroll || v == horizontal_scroll) {
/*
* Disabling the parent control [list, pager] when user interacting
* with multidirectional scroll
*/
System.out.println("Pano touch Id= " + vertical_scroll.getId());
setTouchId(vertical_scroll.getId());
if (scrollingPanaroma == true) {
v.getParent().getParent().getParent()
.requestDisallowInterceptTouchEvent(true);
}
/*
* enable the parent control [list, pager] when user done with
* multidirectional scroll
*/
else {
v.getParent().getParent().getParent()
.requestDisallowInterceptTouchEvent(false);
}
}
return false;
}
}
Please help me to solve this out because I am really stucked at this point. Thnaks.
Here is the code I used to slow down the scroll speed of ScrollView programmatically,
ObjectAnimator anim = ObjectAnimator.ofInt(mScrollView, "scrollY", mScrollView.getBottom());
anim.setDuration(9000);
anim.start();
mScrollView - Your ScrollView
mScrollView = (ScrollView) findViewById(R.id.scrollView1);
anima.setDuration(int Value) - greater the value, slower the scroll
I used the code block in Switch Button OnCheckedChangedListener.
I've been working on the example from http://obviam.net/index.php/a-very-basic-the-game-loop-for-android/ In this I want to make few changes.
Speed.java
public class Speed {
public static final int DIRECTION_RIGHT = 1;
public static final int DIRECTION_LEFT = -1;
public static final int DIRECTION_UP = -1;
public static final int DIRECTION_DOWN = 1;
private float xv = 1; // velocity value on the X axis
private float yv = 1; // velocity value on the Y axis
private int xDirection = DIRECTION_RIGHT;
private int yDirection = DIRECTION_DOWN;
public Speed() {
this.xv = 1;
this.yv = 1;
}
public Speed(float xv, float yv) {
this.xv = xv;
this.yv = yv;
}
public float getXv() {
return xv;
}
public void setXv(float xv) {
this.xv = xv;
}
public float getYv() {
return yv;
}
public void setYv(float yv) {
this.yv = yv;
}
public int getxDirection() {
return xDirection;
}
public void setxDirection(int xDirection) {
this.xDirection = xDirection;
}
public int getyDirection() {
return yDirection;
}
public void setyDirection(int yDirection) {
this.yDirection = yDirection;
}
// changes the direction on the X axis
public void toggleXDirection() {
xDirection = xDirection * -1;
}
// changes the direction on the Y axis
public void toggleYDirection() {
yDirection = yDirection * -1;
}
}
Using this, the image moves in all directions. Now I just want to limit this movement from bottom to top. And the functionality for onclick is that, we can click and drag the image to required position. I want to replace that with just make the image to disappear or go to another activity. Please help me in making changes to this code. Thanks in advance.
if you have used SurfaceView then in onDraw(Canvas canvas) method the code is for moving image from bottom to top is something like this.
canvas.drawBitmap(bitmap,xPoint,yPoint,paint);
where bitmap is an image(Bitmap which you want to move),xPoint is the x coordinate,yPoint is the y coordinate and paint is a Paint which is also can be null.
and for bottom to top movement just update
yPoint = yPoint - 1;
in any thread before onDraw() call.
May this help you.