In my app I have a horizontal scrollview of 6 duck images, while the horizontal scrollview can work properly, now I would like to add a SeekBar underneath the horizontal scrollview such that moving the seekbar will positioning the horizontal scrollview to the proper item.
I have written the codes as follows:
Seekbar:
seekBar1.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
{
#Override
public void onStopTrackingTouch(SeekBar seekBar)
{
// TODO Auto-generated method stub
}
#Override
public void onStartTrackingTouch(SeekBar seekBar)
{
// TODO Auto-generated method stub
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
seekBar.setProgress(progress);
if (progress ==5) {mLinearLayout.scrollTo(R.drawable.d_duck400_5, 0);}
if (progress ==4) {mLinearLayout.scrollTo(R.drawable.d_duck400_4, 0);}
if (progress ==3) {mLinearLayout.scrollTo(R.drawable.d_duck400_3, 0);}
if (progress ==2) {mLinearLayout.scrollTo(R.drawable.d_duck400_2, 0);}
if (progress ==1) {mLinearLayout.scrollTo(R.drawable.d_duck400_1, 0);}
if (progress ==0) {mLinearLayout.scrollTo(R.drawable.d_duck400_0, 0);}
}
});
}
Horizontal Scrollview:
private void getDeviceWidth()
{
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
mWidth = dm.widthPixels;
}
private void initView()
{
int[] imageArray = { R.drawable.d_duck400_0, R.drawable.d_duck400_1, R.drawable.d_duck400_2,
R.drawable.d_duck400_3, R.drawable.d_duck400_4, R.drawable.d_duck400_5};
// int[] imageArray = { R.drawable.d_duck1_400, R.drawable.d_duck1_400, R.drawable.d_duck1_400,
// R.drawable.d_duck1_400, R.drawable.d_duck1_400, R.drawable.d_duck1_400};
mLinearLayout = (LinearLayout) findViewById(R.id.scrollview_layout);
mLinearLayout.removeAllViews();
for (int i = 0; i < 6; i++)
{// Place 6 items into horizontalscrollview
int width = mWidth /1;
LinearLayout itemLayout = (LinearLayout) LinearLayout.inflate(Duck.this, R.layout.d_scrollview_item, null);
itemLayout.setLayoutParams(new LayoutParams(width, LayoutParams.MATCH_PARENT));// set the width as 1 screen showing 3 items
itemLayout.setGravity(Gravity.CENTER_VERTICAL);
ImageView mImageView = (ImageView) itemLayout.findViewById(R.id.imageview);
TextView mTextView = (TextView) itemLayout.findViewById(R.id.textview);
final String page = "The" + (i + 1) + "th page";
mTextView.setText(page);
mImageView.setBackgroundResource(imageArray[i]);
mLinearLayout.addView(itemLayout);
itemLayout.setOnTouchListener(new OnTouchListener()
{
public boolean onTouch(View v, MotionEvent event)
{
// Toast.makeText(Duck.this, "Click" + page, Toast.LENGTH_SHORT).show();
return false;
}
});
}
}
Question:
Once I move the seekbar, the pictures in the horizontal Scrollview all gone.
What is happening? Thanks in advance for your advice!
if (progress ==5) {mLinearLayout.scrollTo(R.drawable.d_duck400_5, 0);
scrollTo expects x,y coordinates to scroll to a new position. But you give it R.drawable.d_duck400_5 as x value. This will be just a random integer produced by compiler. It is not the x coordinate you want to scroll.
Try something like this:
if (progress ==5) {mLinearLayout.scrollTo(200, 0);
if (progress ==5) {mLinearLayout.scrollTo(400, 0);
....
If you want to find the position of a view, you can go with getLocationInWindow or getLocationOnScreen methods.
int[] location = new int[2];
yourView.getLocationOnScreen(location);
int x = location[0];
int y = location[1];
Related
Here is the problem I am facing. On a empty relative layout, when touched textview is instantiated at the touched x y position. I got this far correct, but the problem is that when I touch on the empty space near already instantiated view, previous view and currently placed views are overlapped. I tried by the getting the child views of the layout and checking the current view and already placed view using rect data that if they intersect. How to solve this problem?
Here is the code:
public class MainActivity extends AppCompatActivity
{
private int id = 0;
private RelativeLayout root;
private RelativeLayout.LayoutParams params;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_designer);
root = (RelativeLayout) findViewById(R.id.rootlayout);
root.setOnTouchListener(new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN:
instantiateView(v, event);
break;
}
return true;
}
});
}
private void instantiateView(View v, MotionEvent event)
{
int x = (int) event.getX();
int y = (int) event.getY();
TextView bt = new TextView(DesignerActivity.this);
bt.setText("1");
bt.setId(++id);
bt.setBackgroundColor(Color.BLACK);
bt.setTextColor(Color.WHITE);
bt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
showDialog();
}
});
params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(x, y, 0, 0);
bt.setLayoutParams(params);
//((ViewGroup) v).addView(bt);
if(root.getChildCount() <= 0)
{
((ViewGroup) v).addView(bt);
}
else
{
for (int i = 0; i < root.getChildCount(); i++)
{
if (!checkCollision(bt, root.getChildAt(i)))
{
if(bt != root.getChildAt(i))
{
((ViewGroup) v).addView(bt);
}
}
}
}
}
private void showDialog()
{
final Dialog dialog = new Dialog(this);
dialog.setContentView(R.layout.dialog_layout);
Button editBtn = (Button) dialog.findViewById(R.id.button1);
Button deleteBtn = (Button) dialog.findViewById(R.id.button2);
editBtn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View arg0)
{
dialog.dismiss();
}
});
deleteBtn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View arg0)
{
dialog.dismiss();
}
});
dialog.show();
}
private boolean checkCollision(View v1, View v2)
{
Rect r1 = new Rect(v1.getLeft(), v1.getTop(), v1.getRight(), v1.getBottom());
Rect r2 = new Rect(v2.getLeft(), v2.getTop(), v2.getRight(), v2.getBottom());
return r1.intersect(r2);
}
}
You are using Relative Layout that's why your Textviews are overlapping.
If you don't want the overlapping and want to place it next or somewhere else to the overlapped view , it is your decision. Just check if they intersect and take appropriate decision based on your requirement.
Below line is the problem in your code.
Rect r1 = new Rect(v1.getLeft(), v1.getTop(), v1.getRight(), v1.getBottom());
You set the params' Margin does not mean that you will get desired left,top,right, bottom values.You will get these values right after the inflation of your view hierarchy.
You can use this function:
private boolean checkCollision(View v1, View v2)
{
int leftMargin = ((RelativeLayout.LayoutParams) v1.getLayoutParams()).leftMargin;
int topMargin = ((RelativeLayout.LayoutParams) v1.getLayoutParams()).topMargin;
Rect r1 = new Rect(root.getPaddingLeft() + leftMargin, root.getPaddingTop() + topMargin,
root.getPaddingLeft() + leftMargin + v2.getWidth(), root.getPaddingTop() + topMargin + v2.getHeight());
Rect r2 = new Rect(v2.getLeft(), v2.getTop(), v2.getRight(), v2.getBottom());
return r1.intersect(r2);
}
After that use
params.addRule(); according to your requirement where you want to place your overlapping view.
i found this code in a post that used on touch listener for linear layout.
in linear layout there is some child layout and each one play same sound but with pitch . now how can i use each child to play a different sound .
the other word how can i access to each child?
public class MainActivity extends Activity {
LinearLayout pianoKeysContainer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
pianoKeysContainer = (LinearLayout) findViewById(R.id.key_container);
pianoKeysContainer.setOnTouchListener(onYourViewTouchListener);
}
//Here we load the view positions after render it and fill the array with the positions
private List<Integer> positionsLeft_whiteKeys = new ArrayList<Integer>();
private List<Integer> positionsRight_whiteKeys = new ArrayList<Integer>();
public void onWindowFocusChanged(boolean hasFocus)
{
super.onWindowFocusChanged(hasFocus);
for (int i = 0; i < pianoKeysContainer.getChildCount(); i++)
{
//positionsLeft_whiteKeys holds the start x of each view.
positionsLeft_whiteKeys.add(pianoKeysContainer.getChildAt(i).getLeft());
//positionsRight_whiteKeys holds the end x of each view.
positionsRight_whiteKeys.add(pianoKeysContainer.getChildAt(i).getRight());
}
}
public View.OnTouchListener onYourViewTouchListener = new View.OnTouchListener()
{
float positionX;
FrameLayout pianoKey;
FrameLayout lastPlayedKey;
ArrayList<FrameLayout> pressedKeys = new ArrayList<FrameLayout>();
#Override
public boolean onTouch(View view, MotionEvent motionEvent)
{
positionX = motionEvent.getX();
float pitch;
//Looping on the child of the layout which contains the piano keys
for (int x = 0; x < ((LinearLayout) view).getChildCount(); x++)
{
// Calculating the pitch to get good chords
pitch = (float) Math.pow(Math.pow(2.0, 1 / 12.0), (float) x);
pianoKey = (FrameLayout) ((LinearLayout) view).getChildAt(x);
if (positionsLeft_whiteKeys.size() >= 0 && positionsRight_whiteKeys.size() >= 0)
{
if (positionX > positionsLeft_whiteKeys.get(x) && positionX < positionsRight_whiteKeys.get(x))
{
pianoKey = (FrameLayout) ((LinearLayout) view).getChildAt(x);
if (pianoKey != null)
{
pianoKey.setBackgroundResource(R.drawable.dinger14);
pressedKeys.add(pianoKey);
}
if (lastPlayedKey != pianoKey)
playKey(pitch);
lastPlayedKey = pianoKey;
break;
}
if (lastPlayedKey != null)
{
pianoKey.setBackgroundResource(R.drawable.dinger14);
lastPlayedKey.setBackgroundResource(R.drawable.dinger14);
}
}
}
if (motionEvent.getAction() == MotionEvent.ACTION_UP)
{
lastPlayedKey = null;
for (FrameLayout pressedKey : pressedKeys)
{
pressedKey.setBackgroundResource(R.drawable.dinger14);
}
}
return false;
}
};
//This is sound play method
SoundPool sp = new SoundPool(1, AudioManager.STREAM_MUSIC, 1);
public void playKey(final float pitch)
{
//here you should store your piano sound at res/raw then load it
sp.load(this, R.raw.chitare3, 1);
sp.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener()
{
#Override
public void onLoadComplete(SoundPool soundPool, int i, int i2)
{
soundPool.play(i, 0.99f, 0.99f, 1, 0, pitch);
}
});
}
}
If you have no need of parent on touch event then directly apply this same event on each child...
pianoKeysContainer1 = (LinearLayout) findViewById(R.id.key_child1);
pianoKeysContainer2 = (LinearLayout) findViewById(R.id.key_child2);
pianoKeysContainer1.setOnTouchListener(onYourViewTouchListener);
pianoKeysContainer2.setOnTouchListener(onYourViewTouchListener);
You can apply onYourViewTouchListener onTouchListener on each child as shown above.
Then in View.onTouchListener check which child listener is called by checking view id.
public View.OnTouchListener onYourViewTouchListener = new View.OnTouchListener()
{
float positionX;
FrameLayout pianoKey;
FrameLayout lastPlayedKey;
ArrayList<FrameLayout> pressedKeys = new ArrayList<FrameLayout>();
#Override
public boolean onTouch(View view, MotionEvent motionEvent)
{
// Check **view id** here and apply required action based on this view id.
.............
.............
I am trying to create a ProgresBar that looks like the following:
So far, I have created an object which extends ProgressBar, and now I am trying to figure out what my next step is.
I know that I need to override onDraw() with some logic that will decide how many squares to color in. This is trivial.
What I don't know how to do is get these squares in the first place. How can I replace the default drawable, so when I add my custom bar in the layout I can see something like my image?
try this custom Drawable:
class ProgressDrawable extends Drawable {
private static final int NUM_RECTS = 10;
Paint mPaint = new Paint();
#Override
protected boolean onLevelChange(int level) {
invalidateSelf();
return true;
}
#Override
public void draw(Canvas canvas) {
int level = getLevel();
Rect b = getBounds();
float width = b.width();
for (int i = 0; i < NUM_RECTS; i++) {
float left = width * i / NUM_RECTS;
float right = left + 0.9f * width / NUM_RECTS;
mPaint.setColor((i + 1) * 10000 / NUM_RECTS <= level? 0xff888888 : 0xffbbbbbb);
canvas.drawRect(left, b.top, right, b.bottom, mPaint);
}
}
#Override
public void setAlpha(int alpha) {
}
#Override
public void setColorFilter(ColorFilter cf) {
}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}
and test it with the following in onCreate:
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.VERTICAL);
final ProgressBar pb = new ProgressBar(this, null, android.R.attr.progressBarStyleHorizontal);
Drawable d = new ProgressDrawable();
pb.setProgressDrawable(d);
pb.setPadding(20, 20, 20, 0);
ll.addView(pb);
OnSeekBarChangeListener l = new OnSeekBarChangeListener() {
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
int newProgress = pb.getMax() * progress / seekBar.getMax();
Log.d(TAG, "onProgressChanged " + newProgress);
pb.setProgress(newProgress);
}
};
int[] maxs = {4, 10, 60, 110};
for (int i = 0; i < maxs.length; i++) {
SeekBar sb = new SeekBar(this);
sb.setMax(maxs[i]);
sb.setOnSeekBarChangeListener(l);
sb.setPadding(20, 20, 20, 0);
ll.addView(sb);
}
setContentView(ll);
I want to create android custom SeekBar having thumb with text inside it to show current seek position.
Here is my code:
SeekBar sb;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.custom_seek_bar_activity);
sb = (SeekBar)findViewById(R.id.slider);
sb.setMax(100);
sb.setProgress(10);
BitmapDrawable bd = writeOnDrawable(R.drawable.star2, Double.toString(50));
sb.setThumb(bd);
sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener(){
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
int pos = sb.getProgress();
double star = pos/(20.0);
TextView tv = (TextView)findViewById(R.id.percent);
tv.setText(Double.toString(star)+"%");
BitmapDrawable bd = writeOnDrawable(R.drawable.star2, Double.toString(star));
bd.setBounds(new Rect(0,0,
bd.getIntrinsicWidth(),
bd.getIntrinsicHeight()
));
seekBar.setThumb(bd);
}
#Override
public void onStartTrackingTouch(SeekBar arg0) {
// TODO Auto-generated method stub
}
#Override
public void onStopTrackingTouch(SeekBar arg0) {
// TODO Auto-generated method stub
}
});
}
public BitmapDrawable writeOnDrawable(int drawableId, String text){
Bitmap bm = BitmapFactory.decodeResource(getResources(), drawableId).copy(Bitmap.Config.ARGB_8888, true);
Paint paint = new Paint();
paint.setStyle(Style.FILL);
paint.setColor(Color.BLACK);
paint.setTextSize(10);
Canvas canvas = new Canvas(bm);
canvas.drawText(text, 0, bm.getHeight()/2, paint);
return new BitmapDrawable(bm);
}
but when I move thumb it goes to the beginning of the seek bar.
Does anyone have solution to move custom thumb with seekbar position?
I use SeekBar to display a timer countdown in my app. Inside the timer thumb I show the current SeekBar progress number using the below code:
SeekBar timerBar = (SeekBar) findViewById(R.id.seekBarTimer);
if (timerBar != null) {
timerBar.setMax((int) (Settings.countdownSeconds + 1));
timerBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
#Override
public void onStopTrackingTouch(SeekBar arg0) {
}
#Override
public void onStartTrackingTouch(SeekBar arg0) {
}
#Override
public void onProgressChanged(SeekBar timerBar, int arg1, boolean arg2) {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.seek_thumb);
Bitmap bmp = bitmap.copy(Bitmap.Config.ARGB_8888, true);
Canvas c = new Canvas(bmp);
String text = Integer.toString(timerBar.getProgress());
Paint p = new Paint();
p.setTypeface(Typeface.DEFAULT_BOLD);
p.setTextSize(14);
p.setColor(0xFFFFFFFF);
int width = (int) p.measureText(text);
int yPos = (int) ((c.getHeight() / 2) - ((p.descent() + p.ascent()) / 2));
c.drawText(text, (bmp.getWidth()-width)/2, yPos, p);
timerBar.setThumb(new BitmapDrawable(getResources(), bmp));
}
});
timerBar.setProgress(0);
}
The R.drawable.seek_thumb drawable is my thumb drawable.
I got solution now, in setBound() method I was passing top left as 0, that's why it is showing seek bar at beginning. After doing following change I got it works.
Call setThumbPos() method in onProgressChanged() event
public void setThumbPosition(SeekBar seekBar){
int max = seekBar.getMax();
int available = seekBar.getWidth() - seekBar.getPaddingLeft() - seekBar.getPaddingRight();
float scale = max > 0 ? (float) seekBar.getProgress() / (float) max : 0;
//scale = 1;
int pos = sb.getProgress();
double star = pos/(20.0);
BitmapDrawable bd = writeOnDrawable(R.drawable.star2, Double.toString(star));
int thumbWidth = bd.getIntrinsicWidth();
int thumbHeight = bd.getIntrinsicHeight();
//available -= thumbWidth;
int thumbPos = (int) (scale * available);
if(thumbPos <= 0+thumbWidth){
thumbPos += (thumbWidth/2);
}else if(thumbPos >= seekBar.getWidth()-thumbWidth){
thumbPos -= (thumbWidth/2);
}
bd.setBounds(new Rect(thumbPos,0,
thumbPos+bd.getIntrinsicWidth(),
bd.getIntrinsicHeight()
));
seekBar.setThumb(bd);
TextView tv = (TextView)findViewById(R.id.percent);
tv.setText(Double.toString(star)+"%");
}
I ended up using this simple solution. Its probably not as high-performance as say a proper custom SeekBar, however its really easy to plug into an existing layout, and use any label or other view on top of the SeekBar thumb.
protected void positionThumbLabel(SeekBar seekBar, TextView label)
{
Rect tr = seekBar.getThumb().getBounds();
label.setWidth(tr.width());
label.setX(tr.left + seekBar.getPaddingLeft());
}
With some minor changes you can position an overlay relative to the center of the thumb:
protected void positionThumbOverlayCenter(SeekBar seekBar, View overlay)
{
Rect tr = seekBar.getThumb().getBounds();
overlay.setX(tr.centerX() - (overlay.getWidth() * 0.5f) + seekBar.getPaddingLeft());
}
Pick a solution that match your situation here: http://www.helptouser.com/code/10722746-add-dynamic-text-over-android-seekbar-thumb.html
public class UnitConverterActivity extends Activity implements OnTouchListener {
/** Called when the activity is first created. */
LinearLayout mLinearLayout;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLinearLayout = new LinearLayout(this);
ImageView i = new ImageView(this);
i.setImageResource(R.drawable.mainmenu);
//i.setAdjustViewBounds(false);
i.setScaleType(ScaleType.FIT_XY);
i.setLayoutParams(new Gallery.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
mLinearLayout.addView(i);
setContentView(mLinearLayout);
//setContentView(R.layout.main);
}
#Override
public boolean onTouch(View arg0, MotionEvent arg1) {
// TODO Auto-generated method stub
return false;
}
}
I have used the above method to load an image for the main menu I am trying to create. The image has four areas and each will be used to call a particular function of the app. Now I am trying to implement touch interface on those areas. I know how to define the range of pixels for that purpose but I am at loss on how to implement OnTouchListner on the image. Please help me in this regard.
If your image was split into four rectangular quarters (say)
then in onCreate have:
i.setOnTouchListener(this);
and for your listener, something like this (illustrates the principle only):
#Override
public boolean onTouch(View v, MotionEvent mev) {
int width = v.getWidth();
int height = v.getHeight();
float x = mev.getX();
float y = mev.getY();
String msg;
if (x < width / 2) {
if (y < height / 2)
msg = "Top left quarter";
else
msg = "Bottom left quarter";
} else {
if (y < height / 2)
msg = "Top right quarter";
else
msg = "Bottom right quarter";
}
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
return false;
}
Just put this code in onCreate().
i.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//your code
}
}