Android - basic gesture detection in TableLayout - android

I am new to android development, so please excuse the naivety of the post. I have a table layout in which i am dynamically adding text view to each cell. I wish to add a swipe detection on the cells and perform an action on the basis of which cell was swiped. I tried adding a onSwipeTouchListener on each of the cell.
TextView txtviewCell = new TextView(getActivity());
TableRow.LayoutParams paramsExample = new TableRow.LayoutParams(60, 60);
txtviewCell.setBackgroundColor(0xfffaf8ef);
txtviewCell.setGravity(Gravity.CENTER);
paramsExample.setMargins(5, 5, 5, 5);
txtviewCell.setLayoutParams(paramsExample);
final int currRow = i;
final int currCol = j;
txtviewCell.setOnTouchListener(new OnSwipeTouchListener(
getActivity()) {
public void onSwipeTop() {
handleSwipe(currRow, currCol);
}
public void onSwipeRight() {
handleSwipe(currRow, currCol);
}
public void onSwipeLeft() {
handleSwipe(currRow, currCol);
}
public void onSwipeBottom() {
handleSwipe(currRow, currCol);
}
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
});
allCells[i][j] = txtviewCell;
Now when i swipe i get the control in onSwipe function, but i do not get the correct row number and col number. Is there a specific way to attach a swipe event on a textview and get the row number and col number of that cell?

I guess every textview has different ID, so try getting the id and making a control flow with it.

Related

How to open a new activity which has list of item at specific position in android [duplicate]

How can I programmatically scroll to a specific position in a ListView?
For example, I have a String[] {A,B,C,D....}, and I need to set the top visible item of the ListView to the index 21 of my String[].
For a direct scroll:
getListView().setSelection(21);
For a smooth scroll:
getListView().smoothScrollToPosition(21);
For a SmoothScroll with Scroll duration:
getListView().smoothScrollToPositionFromTop(position,offset,duration);
Parameters
position -> Position to scroll to
offset ---->Desired distance in pixels of position from the top of the view when scrolling is finished
duration-> Number of milliseconds to use for the scroll
Note: From API 11.
HandlerExploit's answer was what I was looking for, but My listview is quite lengthy and also with alphabet scroller. Then I found that the same function can take other parameters as well :)
Edit:(From AFDs suggestion)
To position the current selection:
int h1 = mListView.getHeight();
int h2 = listViewRow.getHeight();
mListView.smoothScrollToPositionFromTop(position, h1/2 - h2/2, duration);
Put your code in handler as follows,
public void timerDelayRunForScroll(long time) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
try {
lstView.smoothScrollToPosition(YOUR_POSITION);
} catch (Exception e) {}
}
}, time);
}
and then call this method like,
timerDelayRunForScroll(100);
CHEERS!!!
The Listview scroll will be positioned to top by default, but want to scroll if not visible then use this:
if (listView1.getFirstVisiblePosition() > position || listView1.getLastVisiblePosition() < position)
listView1.setSelection(position);
I have set OnGroupExpandListener and override onGroupExpand() as:
and use setSelectionFromTop() method which
Sets the selected item and positions the selection y pixels from the top edge of the ListView. (If in touch mode, the item will not be selected but it will still be positioned appropriately.) (android docs)
yourlist.setOnGroupExpandListener (new ExpandableListView.OnGroupExpandListener()
{
#Override
public void onGroupExpand(int groupPosition) {
expList.setSelectionFromTop(groupPosition, 0);
//your other code
}
});
If someone looking for a similar functionality like Gmail app,
The Listview scroll will be positioned to top by default. Thanks for the hint.
amalBit.
Just subtract it. That's it.
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
int h1 = mDrawerList.getHeight();
int h2 = header.getHeight();
mDrawerList.smoothScrollToPosition(h2-h1);
}
}, 1000);
If you want to jump directly to the desired position in a listView just use
listView.setSelection(int position);
and if you want to jump smoothly to the desired position in listView just use
listView.smoothScrollToPosition(int position);
Handling listView scrolling using UP/ Down using.button
If someone is interested in handling listView one row up/down using button. then.
public View.OnClickListener onChk = new View.OnClickListener() {
public void onClick(View v) {
int index = list.getFirstVisiblePosition();
getListView().smoothScrollToPosition(index+1); // For increment.
}
});
This is what worked for me. Combination of answers by amalBit & Melbourne Lopes
public void timerDelayRunForScroll(long time) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
try {
int h1 = mListView.getHeight();
int h2 = v.getHeight();
mListView.smoothScrollToPositionFromTop(YOUR_POSITION, h1/2 - h2/2, 500);
} catch (Exception e) {}
}
}, time);
}
and then call this method like:
timerDelayRunForScroll(400);
-If you just want the list to scroll up\dawn to a specific position:
myListView.smoothScrollToPosition(i);
-if you want to get the position of a specific item in myListView:
myListView.getItemAtPosition(i);
-also this myListView.getVerticalScrollbarPosition(i);can helps you.
Good Luck :)
You need two things to precisely define the scroll position of a listView:
To get the current listView Scroll position:
int firstVisiblePosition = listView.getFirstVisiblePosition();
int topEdge=listView.getChildAt(0).getTop(); //This gives how much the top view has been scrolled.
To set the listView Scroll position:
listView.setSelectionFromTop(firstVisiblePosition,0);
// Note the '-' sign for scrollTo..
listView.scrollTo(0,-topEdge);
it is easy
list-view.set selection(you pos);
or you can save your position with SharedPreference and when you start activity
it get preferences and setSeletion to that int
I found this solution to allow the scroll up and down using two different buttons.
As suggested by #Nepster I implement the scroll programmatically using the getFirstVisiblePosition() and getLastVisiblePosition() to get the current position.
final ListView lwresult = (ListView) findViewById(R.id.rds_rdi_mat_list);
.....
if (list.size() > 0) {
ImageButton bnt = (ImageButton) findViewById(R.id.down_action);
bnt.setVisibility(View.VISIBLE);
bnt.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(lwresult.getLastVisiblePosition()<lwresult.getAdapter().getCount()){
lwresult.smoothScrollToPosition(lwresult.getLastVisiblePosition()+5);
}else{
lwresult.smoothScrollToPosition(lwresult.getAdapter().getCount());
}
}
});
bnt = (ImageButton) findViewById(R.id.up_action);
bnt.setVisibility(View.VISIBLE);
bnt.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(lwresult.getFirstVisiblePosition()>0){
lwresult.smoothScrollToPosition(lwresult.getFirstVisiblePosition()-5);
}else{
lwresult.smoothScrollToPosition(0);
}
}
});
}

ANDROID onTouchListener on button array

I have put a lot of buttons (16*16) in a button array.
The buttons numbers are directly related to changes they should do in another array (e.g. button[12][7] sets the value of stat[12][7] to 1)
So I thought it's possible to put on single line in the onTouch method that reacts to every button.
Example (of course, not working)
public boolean onTouch(View arg0, MotionEvent arg1) {
if (arg1.getAction() == MotionEvent.ACTION_DOWN) {
if(arg0 == button[int a][int b]){stat[a][b]=1};
In this pseudocode, the button would create 2 ints that describe the 2 dimensions of the array which get passed to the stat array.
If anyone had a solution for this, he would save me a few hours this night.
Thanks for your answers.
I think HasMap is a better solution
private HashMap<Integer,Button> btnMap = new HashMap<Integer, Button>();
private void init(){
Button yourFirstBtn = (Button) findViewById(R.id.yourFirstBtn);
btnMap.put(yourFirstBtn.getId(), yourFirstBtn);
for(Button tempBtn: btnMap.values()){
tempBtn.setOnClickListener(this);
}
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Button clickedBtn = btnMap.get(v.getId());
}
Are you adding the onTouchListener to the buttons' container?
Your best bet is to add an onTouchListener to each button, and then arg0 will correspond to the specific button.
Another option would be to use a GridView, which has an setOnItemClickListener you can use. http://developer.android.com/reference/android/widget/GridView.html
As you add each button to the array, set a tag that indicates its indices. Tags are there for adding properties to a view without having to resort to another data structure.
For example:
button[12][7].setTag("12|7");
If your button were pre-defined in XML, you could do the same with:
android:tag="12|7"
Then in the touch listener (I assume the same one is attached to all the buttons), get the tag from the view that was touched:
String tag = (String) view.getTag();
Then substring out and use the two indexes as required:
String indx1 = tag.substring(0, tag.indexOf("|"));
String indx2 = tag.substring(tag.indexOf("|")+1);
stat[Integer.parseInt(indx1)][Integer.parseInt(indx2)] = 1;
Try something like this:
Button[][] myButtonMatrix = new Button[] {
new Button[] { button11, button12, button13, button 14 },
new Button[] { button21, button22, button23, button24 }
};
public class MatrixButtonListener implements View.OnClickListener {
private int x;
private int y;
public MatrixButtonListener(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() { return x; }
public int getY() { return y; }
#Override
public void onClick(View v) {
stat[x][y] = x-y; // changes were made only in relation to x and y, nothing else
// for example:
if(x == 0) {
// button in first row
// do something
}
}
};
// to apply to each button in matrix:
for(int i=0; i<myButtonMatrix.length; i++) {
for(int j=0; j<myButtonMatrix[i].length; j++) {
myButtonMatrix[i][j].setOnClickListener(new MatrixButtonListener(i,j));
}
}
What this is supposed to do:
Create a generic OnClickListener class, which takes the x and y position as parameter, so each onClickListener has the same behaviour, but differnet x and y positions, depending on the button itself.
Note: This is not tested.
EDIT:
Another way would be a custom button class, which you use, which contains the X/Y coordinates as well. Simply add onClickListener to each button, cast it back to your custom view, and ask for x/y.

Cursor behind the hint

I have a problem with an EditText where gravity is set to center. Because of that I had to put the attribute android:ellipsize="start" for the hint to appear in the center.
However, the hint appears before the cursor, which gives a rather ugly appearance to the application:
What I want to do is display the cursor before the text. Any suggestions for this?
I have 3 solution,infact that are 2 way.One side when text is empty that need to dispay hint,we hide the hint either show,Another side is adjust cursor(widgit) location.precondition is EditText put in a layout,adjust edittext's layout gravity not it's self gravity.But my demand is before hint,you just gravity to right.
like this pic:
enter image description here
#Override
public void onFocusChange(View v, boolean hasFocus) {
adjustCursorPosition(etInput.getText());
}
#Override
public void afterTextChanged(Editable s) {
adjustCursorPosition(etInput.getText());
}
private void adjustCursorPosition(CharSequence text){
if (!TextUtils.isEmpty(etInput.getHint())){
adjustGravityForCursor(text);
//adjustCursorVisible(text);
//adjustHintContent(hasFocus(),text);
}
}
private void adjustHintContent(boolean hasFocus, CharSequence text){
if (TextUtils.isEmpty(text)) {
etInput.setHint(hasFocus ? "" : mHint);
}
}
private void adjustCursorVisible(CharSequence text){
etInput.setCursorVisible(!TextUtils.isEmpty(text));
}
private void adjustGravityForCursor(CharSequence text) {
LayoutParams lp = (LayoutParams) etInput.getLayoutParams();
if (mSpaceWidth <= 0) mSpaceWidth = lp.width;
if (!TextUtils.isEmpty(text)) {
etInput.setGravity(Gravity.CENTER);
lp.leftMargin = 0;
} else {
etInput.setGravity(Gravity.LEFT);
lp.leftMargin = (mSpaceWidth - measureText(etInput,mHint)) / 2;
}
etInput.setLayoutParams(lp);
}
I think you can use the setSelection method of the EditText, as per this thread.
The quickest solution will be to clear hint on editText Touch: (I have assumed this edittext to be MYET).
First, set an onTouch listener for MYET.
Then , onTouch, return TRUE(instread of false).
After that, onTouch, use MYET.setHint(""); This will clear the hint.
Here is the code :
MYET.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View arg0, MotionEvent arg1) {
MYET.setHint("");
return true;
}
});
note:
If the setHint("") does not work, you can use MYET.setText("");

set click listeners for dynamically created imageviews

I have an activity in my app which displays rss feeds and next to each rss feed arrow image is attached.
I am new to android any help will be appreciated.
i shall explain what i am doing to display rss news ...
i have a seperate dummy xml layout for a single rss.. i have set id for arrow image (which will navigate to the next activity) in it as iv_arrow_img i am iterating over the news feeds i get and for each news feed i am adding the dummy view again and again...my question is how will i distinguish between different image arrow's ids .. because for now all are having the same id...i have set onclick listeners to them below in my code
i have wrote the code
Iterator itr = data.iterator();
int i =0; while (itr.hasNext()) { NewsPostDTO newspostdto = itr.next();
view = inflater.inflate(R.layout.rl_news_item, null);
lnContentView.addView(view, LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT);
ivArrowfwd = (ImageView) view.findViewById(R.id.iv_arrowfwd);
tvNewsHeading.setText(newspostdto.getFeaturedDesc());
tvNewsContent.setText(newspostdto.getDate() + " - " + newspostdto.getTitle());
ivArrowfwd.setId(id);
ivArrowfwd.setTag(newspostdto);
ivArrowfwd.setOnTouchListener(new OnTouchListener(){
#Override
public boolean onTouch(View arg0, MotionEvent arg1) {
System.out.println("sdfsdf" +(ImageView) view.findViewById(id).getTag());
return false;
}
});
id++;
}
but i am not getting different tags for different news though they are different .. can any one tell me what i am doing wrong... ?
asuming that view is final(in other case, i think, you couldn't compile this) so it's pointing to last view that you create ... there is no need for using findViewById ... in event you got image view which couse it so try smthing like this:
ivArrowfwd.setOnTouchListener(new OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent me) {
ImageView iv = (ImageView)v;
System.out.println("sdfsdf" + iv.getTag());
return false;
}
});
anyway ... you should consider using ListView instead
What you probably want is something like the following. You will have to find your Views by their id you gave them in the .xml file with android:id="+#id/XXXXXXX".
Your code will look something like this:
String id;
int resID;
ImageView views[] = new ImageView[NUM_OF_VIEWS];
for(int i = o; i < NUM_OF_VIEWS; i++){
id = "ImageViewIdentifier" + i; // Do name their id's in the .xml file so that you can easily loop over them.
resID = getResources().getIdentifier(resID, "defType", "defPackage"); // see here: http://developer.android.com/reference/android/content/res/Resources.html#getIdentifier(java.lang.String, java.lang.String, java.lang.String)
views[NUM_OF_VIEWS-1] = (ImageView) findViewById(resID);
views[NUM_OF_VIEWS-1].setOnTouchListener(new OnTouchListener(){
// DO Stuff here
}
}
}

Control onclicklistener in autolink enabled textview

I am using a TextView for which I have set autolink="web" property in XML file. I have also implemented the onClickListener for this TextView. The problem is, when the text in TextView contains a hyperlink, and if I touch that link, the link opens in browser but simultaneously the onClickListener triggers too. I don't want that.
What I want is, if I touch the hyperlink the clickListener should not fire. It should only fire if I touch the part of the text that is not hyperlinked. Any suggestion?
You can achieve this using a work around in getSelectionStart() and getSelectionEnd() functions of the Textview class,
tv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ClassroomLog.log(TAG, "Textview Click listener ");
if (tv.getSelectionStart() == -1 && tv.getSelectionEnd() == -1) {
//This condition will satisfy only when it is not an autolinked text
//Fired only when you touch the part of the text that is not hyperlinked
}
}
});
It may be a late reply, but may be useful to those who are searching for a solution.
one of the #CommonsWare post helps to intercept autolink OnClick event.
private void fixTextView(TextView tv) {
SpannableString current = (SpannableString) tv.getText();
URLSpan[] spans =
current.getSpans(0, current.length(), URLSpan.class);
for (URLSpan span : spans) {
int start = current.getSpanStart(span);
int end = current.getSpanEnd(span);
current.removeSpan(span);
current.setSpan(new DefensiveURLSpan(span.getURL()), start, end,
0);
}
}
public static class DefensiveURLSpan extends URLSpan {
private String mUrl;
public DefensiveURLSpan(String url) {
super(url);
mUrl = url;
}
#Override
public void onClick(View widget) {
// openInWebView(widget.getContext(), mUrl); // intercept click event and do something.
// super.onClick(widget); // or it will do as it is.
}
}
Apply above code simply as below. It will go through all linkable texts and replace click events to above event handler.
fixTextView(textViewContent);
You can set the property android:linksClickable="false" in your TextView, in conjuction with android:autoLink="web"; this makes the links visible, but not clickable.
if you wish, you can use the next code which allows to customize the clickable links within the string ( based on this post ) :
usage:
final TextView textView = (TextView) findViewById(R.id.textView);
final Spanned text = Html.fromHtml(getString(...));
textView.setText(text);
textView.setMovementMethod(new LinkMovementMethodExt());
LinkMovementMethodExt.java
public class LinkMovementMethodExt extends LinkMovementMethod {
private static LinkMovementMethod sInstance;
public static MovementMethod getInstance() {
if (sInstance == null)
sInstance = new LinkMovementMethodExt();
return sInstance;
}
#Override
public boolean onTouchEvent(final TextView widget, final Spannable buffer, final MotionEvent event) {
final int action = event.getAction();
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
final int x = (int) event.getX() - widget.getTotalPaddingLeft() + widget.getScrollX();
final int y = (int) event.getY() - widget.getTotalPaddingTop() + widget.getScrollY();
final Layout layout = widget.getLayout();
final int line = layout.getLineForVertical(y);
final int off = layout.getOffsetForHorizontal(line, x);
final ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
if (link.length != 0) {
//do something with the clicked item...
return true;
}
}
return super.onTouchEvent(widget, buffer, event);
}
}
Kotlin version:
Similar to older answers in Java. Simply:
In Layout Editor/XML, add the types of things you'd like to hyperlink via the autoLink property.
<TextView
...
android:autoLink="web|phone|email" />
Add an onClickListener to your TextView in Kotlin code to handle clicks on the plain text part. Check to make sure the person didn't click on a link by checking selectionStart and selectionEnd.
binding.messageText.setOnClickListener { view ->
if (binding.messageText.selectionStart == -1 && binding.messageText.selectionEnd == -1) {
// do whatever you want when they click on the plain text part
}
}
Use textView.getSelectionStart() and textView.getSelectionEnd().If u click any text other than link textView.getSelectionStart() and textView.getSelectionEnd() will be -1 .So by using a if condition in onClickListner you can block the onClick action when link is clicked .
//inside onClickListner
if(textView.getSelectionStart()==-1&&textView.getSlectionEnd==-1){
//onClick action
}
private void fixTextView(TextView tv) {
SpannableString current = (SpannableString) tv.getText();
URLSpan[] spans =
current.getSpans(0, current.length(), URLSpan.class);
for (URLSpan span : spans) {
int start = current.getSpanStart(span);
int end = current.getSpanEnd(span);
current.removeSpan(span);
current.setSpan(new DefensiveURLSpan(span.getURL()), start, end,
0);
}
}
public static class DefensiveURLSpan extends URLSpan {
public final static Parcelable.Creator<DefensiveURLSpan> CREATOR =
new Parcelable.Creator<DefensiveURLSpan>() {
#Override
public DefensiveURLSpan createFromParcel(Parcel source) {
return new DefensiveURLSpan(source.readString());
}
#Override
public DefensiveURLSpan[] newArray(int size) {
return new DefensiveURLSpan[size];
}
};
private String mUrl;
public DefensiveURLSpan(String url) {
super(url);
mUrl = url;
}
#Override
public void onClick(View widget) {
// openInWebView(widget.getContext(), mUrl); // intercept click event and do something.
// super.onClick(widget); // or it will do as it is.
}
}
You would then call fixTextView(textViewContent); on the view after it is declared (via inflation or findViewById) or added to the window (via addView)
This includes the missing requirement to set a CREATOR when extending a Parcelable.
It was proposed as an edit, but rejected. Unfortunately, now future users will have to find out the original one is incomplete first. Nice one, reviewers!
Instead of using a onClickListener, you can try this.
private void addLink() {
tvLink = (TextView) findViewById(R.id.tvInfo2);
String strURL = UrlLoader.getCodeUrl();
// Make the url string clicable and take action in its onclick
SpannableString spanUrl = SpannableString.valueOf(strURL);
spanUrl.setSpan(new InternalURLSpan(new OnClickListener() {
public void onClick(View v) {
//Do Some action
}
}), 0, spanUrl.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
tvLink.setText(spanUrl);
// We probably also want the user to jump to your link by moving the
// focus (e.g. using the trackball), which we can do by setting the
// proper movement method:
MovementMethod m = tvLink.getMovementMethod();
if ((m == null) || !(m instanceof LinkMovementMethod)) {
if (tvLink.getLinksClickable()) {
tvLink.setMovementMethod(LinkMovementMethod.getInstance());
}
}
}
Also in the layout XML file , dont forget to add
<TextView android:layout_width="wrap_content" android:linksClickable="true"
android:layout_height="wrap_content" android:id="#+id/tvInfo2" android:text="#string/url_link" />
Just adding
textView.setMovementMethod(CustomLinkMovementMethod.getInstance());
to #binary's answer for those whose the method did not work with them

Categories

Resources