I'm trying to make my first Android application, and I want to drag and drop coins into boxes. The onDrag method I found was this:
#Override
public boolean onDrag(View v, DragEvent e) { // onDrag(waarnaartoe, event)
if (e.getAction()==DragEvent.ACTION_DROP) {
// user interface
View view = (View) e.getLocalState();
ViewGroup from = (ViewGroup) view.getParent();
from.removeView(view);
FrameLayout to = (FrameLayout) v;
to.addView(view);
view.setVisibility(View.VISIBLE);
}
return true;
}
The boxes are LinearLayouts, so I changed the original code i.e.
from
ViewGroup from = (ViewGroup) view.getParent(); (which works fine)
to
LinearLayout from = (LinearLayout) view.getParent();
However, the app crashes if I try to drop something onto a box. The reason I want to get the LinearLayout is that I made a Map which connects LinearLayouts to "boxes" (which are theoretical objects with certain properties).
Could anyone explain to me why I cannot replace ViewGroup by LinearLayout?
The function which I copied was not applicable to my program. The line
FrameLayout from = (FrameLayout) e.getLocalState();
works perfectly fine, so e.getLocalstate already gave the container I wanted. Therefore the parent obtained by view.getParent() was the GridLayout.
Related
Is it possible to somehow take an array, for example, a TextView, which are in the current Activity, or is it necessary to take each view?
You can get all the views of your xml programmatically as below:
bind your ViewGroup / Parent layout
Then the child View are accessible in if condition
val container = findViewById(R.id.container) as ViewGroup
for (i in 0 until container.childCount) {
val v = container.getChildAt(i)
if (v is Button) {
// You will get Button here
}
else if(v is TextView){
// You will get textView here
}
}
I have custom listview and array adapter with ViewHolder. When click listview item, it expands new layout below. Problem is: unfortunately it is opened for every +9th item in listview.. For example: if item 0 is clicked; 0,9,18th elements opens their expand layouts. Any idea without looking code ?
I have no idea, but this sounds familair with an issue I had. I had a listview with TextView objects and multiple were selected and got typed in the same value.
I had a very, very dirty fix for that, in my custom adapter I'd always make a new View, no matter what:
#Override
public View getView (final int position, View convertView, final ViewGroup parent) {
//if (convertView == null) {
// Inflate the view from the converter
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
convertView = layoutInflater.inflate(converter.getLayout(), parent, false);
//}
// Populate the view from the converter
converter.populateInflatedView(convertView, getItem(position));
return convertView;
}
Source can be found here if you want to know what the converter is about.
On a side note, I have created a sort of interface type of thing for a TreeView, however this is in Activity form which uses a ScrollView. So this is not really a ListView type of deal, but might help you. The Tree part can be found on the Tree-link, with an implementation in the subject package.
I got a ListView with a custom Adapter.
In the Adapter a layout is inflated from xml.
All works fine, and I can see the items, until the Screen Orientation is changed.
I know that the Activity is recreated (or resumed) then, and the ListView is recreated too, as well as the Adapter.
But there are no items in the ListView now. The Adapter isn't empty, I use toasts to display the count of items in the Adapter.
I guess there is an inflating problem, because if I use the same Adapter (or an adapter with the same data) to a new ListView nothing is shown as well.
But the most crazy thing I don't understand is, that if I let my getView() method return a simple TextView, all works fine, even after orientation change.
I tried several things, like don't recycle a View so that it is inflated every time, or save the View to the matching Item (from getItem(position) from the Adapter).
I'm grateful for all hints :)
EDIT: so I was asked for some code.
Here is the getView() of my Adaptar
#Override
public View getView(final int position, View convertView,
ViewGroup parent) {
View view = convertView;
final Event event = getItem(position);
if (view == null) {
view = inflater.inflate(R.layout.new_event_item_layout, parent,
false);
view.setTag(R.id.eventDate, view.findViewById(R.id.eventDate));
view.setTag(R.id.eventTime, view.findViewById(R.id.eventTime));
view.setTag(R.id.eventName, view.findViewById(R.id.eventName));
view.setTag(R.id.eventBemerkungen,
view.findViewById(R.id.eventBemerkungen));
view.setTag(R.id.eventIcon, view.findViewById(R.id.eventIcon));
}
((TextView) view.getTag(R.id.eventDate)).setText(event.getDate());
((TextView) view.getTag(R.id.eventTime)).setText(event.getName());
((TextView) view.getTag(R.id.eventName)).setText(event.getTime());
((TextView) view.getTag(R.id.eventBemerkungen)).setText(event
.getDescription());
SquaredImageView icon = (SquaredImageView) view.getTag(R.id.eventIcon);
Picasso.with(context).load(event.getUri())
.placeholder(R.drawable.ic_reload).into(icon);
view.setBackgroundColor(event.getBackgroundColor());
view.setVisibility(View.VISIBLE);
return view;
//return getDummyTextView();
}
public TextView getDummyTextView()
{
TextView tv=new TextView(context);
tv.setText("YOLO BIATCHSES");
tv.setTextColor(Color.WHITE);
return tv;
}
I have had the same exact problem although it wasn't because of orientation change and I found the solution by just setting listView.setAdapter(adapter) again after the recreation of the activity or whatever case you have. I suspect the listview is basically losing the pointer to the adapter.
I just set up my ArrayAdapter to convertView to my favor , but now I wonder how to control the children of the LinearLayouts am using in that listview , lets say I have a TextView in the Linearlayout , I want to call setText , but I don't know how , or maybe I have a button which I want to call setOnClickListener , I don't know how !
Here is my getView code :
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
if (convertView == null){
convertView = inf.inflate(R.layout.normal_row, parent , false);
}
switch(position){
case(0):
// here is where my first LinearLayout goes , containing an Image and Switch which I need to program in onCheckedChangeListener ...
convertView = (LinearLayout) inf.inflate(R.layout.row_switch, parent,false);
break;
case(1)
// here I need to set the Text for the following two options on some basis , they are both linearLayouts containing a single textView which I want to call setText for each case 1 and 2.
break;
case(2)
}
TextView textview = (TextView) convertView.findById(R.id.txt);
text.setText("textview");
Button btn = (Button) convertView.findById(R.id.btn);
btn.setTag(textview);
btn.setOnClickListener(...)
{
onClick(..){
TextView t = (Textview)btn.getTag():
t.setText("new value")
}
}
i suggest you to look at the question which i replied before.
Let's say your normal_row layout has a TextView in it with the id #id/my_text_view. Then you would set the text like
TextView view = (TextView) convertView.findViewById(R.id.my_text_view);
view.setText("Some text");
You can access anything in the layout you've inflated by its id in a similar way.
One thing to note though is there seem to be two types of views that you're inflating. Let's say that you try to use the code I gave you, but my_text_view is only in normal_row. Then if you've inflated the row_switch view, the findViewById() will return null because it can not find a view with the given id.
Use onItemClick and find your view by the view that the OnItemClickListener provides you!
For example: `mListView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
}
});`
By the passed View find your textview or your button inside every listView children.
Example: TextView tempTextView = (TextView) arg1.findViewById(R.id.myTextView);
The id of the textview is the one you assigned to it in your inflated layout for every row!
I've spent the day playing around with the GreenDroid PagedView and PagedAdaptor to create multiple screens that one can swipe through (a la iPhone style and Android Home Screen style). It's a very cool effect and the GreenDroid library is awesome. Soo.. I can get this working for one XML layout (code below), but what I am attempting to do is have three screens with different layouts. I've played around and got it working successfully with one method, but am unsure whether the method I'm using will cause problems due to repeat inflation of XML layout at every method call. I'll give some examples of what I've tried to save time. I'm hoping someone reads this that has had experience with GreenDroid and can point me in the right direction. Maybe this will also help someone else too..
Here is my code:
HomePageActivity.java
public class HomePageActivity extends GDActivity {
private static final int PAGE_COUNT = 3;
private final Handler mHandler = new Handler();
private PageIndicator mPageIndicator;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setActionBarContentView(R.layout.homepage_view); // container xml
final PagedView pagedView = (PagedView) findViewById(R.id.homepage_view);
pagedView.setOnPageChangeListener(mOnPagedViewChangedListener);
pagedView.setAdapter(new HomePageAdapter());
mPageIndicator = (PageIndicator) findViewById(R.id.page_indicator);
mPageIndicator.setDotCount(PAGE_COUNT);
setActivePage(pagedView.getCurrentPage());
}
private void setActivePage(int page) {
mPageIndicator.setActiveDot(page);
}
private OnPagedViewChangeListener mOnPagedViewChangedListener = new OnPagedViewChangeListener() {
#Override
public void onStopTracking(PagedView pagedView) {
}
#Override
public void onStartTracking(PagedView pagedView) {
}
#Override
public void onPageChanged(PagedView pagedView, int previousPage, int newPage) {
setActivePage(newPage);
}
};
private class HomePageAdapter extends PagedAdapter {
#Override
public int getCount() {
return PAGE_COUNT;
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
Log.i("getView","ConvertView is null");
convertView = getLayoutInflater().inflate(R.layout.homepage_one, parent, false);
}
Log.i("getView Page",Integer.toString(position));
return convertView;
}
}
The two lines:
Log.i("getView","ConvertView is null");
Log.i("getView Page",Integer.toString(position));
I am using to debug this to see what is happening via. LogCat and so I can experiment.
The first line is displayed ONCE - first time application is created. I've noticed that VERY VERY occasionally as I swipe through the pages (I have three - set by variable PAGE_COUNT at top), that after 30-50 swipes I will see this message again. This shows that this layout is only INFLATED once - for all screens.
The second line I naturally see every time I change page. The integer position is either 0, 1 or 2 in this particular case.
The XML layout homepage_one is a simple layout with three TextViews. The XML layout homepage_view is the container for these pages.
homepage_view.xml
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:greendroid="http://schemas.android.com/apk/res/com.cyrilmottier.android.gdcatalog">
<greendroid.widget.PagedView
android:id="#+id/homepage_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/splash" />
<greendroid.widget.PageIndicator
android:id="#+id/page_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|center_horizontal"
android:paddingTop="10dp" />
Naturally I've tried some obvious methods such as this: (which works as wanted)
public View getView(int position, View convertView, ViewGroup parent) {
if (position == 0) {
convertView = getLayoutInflater().inflate(R.layout.homepage_one, parent, false);
} else if( position == 1 ){
convertView = getLayoutInflater().inflate(R.layout.homepage_two, parent, false);
} else {
convertView = getLayoutInflater().inflate(R.layout.homepage_three, parent, false);
}
return convertView;
}
This works as intended. Every screen is different as I want. I've not noticed any performance problems during testing, but it's worth noting in the original instance that we only inflate the layout ONCE. As this method is called (which is every time the page changes, we inflate the layout again. This doesn't seem resourceful, but then again this is my first week with Android development and I don't know how the architecture works... (just reading, reading, reading and testing, testing, testing) - so hence why I would like to hear from more experienced and knowledgeable developers. This may well be acceptable.. I would like to hear from you.
I tried this:
public View getView(int position, View convertView, ViewGroup parent) {
if (PAGE_ONE == false && position == 0) {
convertView = getLayoutInflater().inflate(R.layout.homepage_one, parent, false);
PAGE_ONE = true;
} else if(PAGE_TWO == false && position == 1 ){
convertView = getLayoutInflater().inflate(R.layout.homepage_two, parent, false);
PAGE_TWO = true;
} else if( PAGE_THREE == false && position == 2 ){
convertView = getLayoutInflater().inflate(R.layout.homepage_three,parent, false);
PAGE_THREE = true;
}
return convertView;
}
PAGE_ONE, PAGE_TWO, PAGE_THREE were set in the class as private boolean = false. The consideration behind this is that we only inflate layout once and every other call to this method simply returns the already inflated xml layout. Unfortunately this crashes my emulator and my phone (HTC EVO 3D). As Jay-Z would say, on to the next one...
Any ideas guys?
The GreenDroid's PagedView is normally intended to display a large set of pages. It can be considered as an horizontal paged ListView. This is the reason why using it is very close to the common ListAdapter.
In your case, you want to keep three pages in memory. This is completely possible but not recommended as you are preventing the PagedView from recycling your pages and also increasing the amount of View in memory.
Having only 3 pages (with a relatively flat and narrow View hierarchy) is OK. A better way do to what you are trying to do would be to lazily-initialize the pages and keep a reference on each pages.
private static final int PAGE_COUNT = 3;
private View[] mPages = new View[PAGE_COUNT];
public View getView(int position, View convertView, ViewGroup parent) {
if (mPages[position] == null) {
View page = createPageAtPosition(position, parent);
mPages[position] = page;
}
return mPages[position];
}
Of course you may have a warning in your logs as the PagedView notify the developer when the convertView is not reused.
I ran into a similar issue as well. Not sure if it is a bug with GreenDroid or user error on my part. (The latter is more likely)
Anyway, here is the solution I came up with. Your solution was nearly there, but you missed the critical 'else' condition when grabbing an existing view. It's working quite well for me.
/** get the view to display */
#Override
public View getView(int position, View convertView, ViewGroup parent) {
pageEnum currentPage = pageEnum.values()[position];
if(null == mViews[position]) {
switch(currentPage) {
case PAGE_1:
convertView = getLayoutInflater().inflate(R.layout.page1, parent, false);
break;
case PAGE_2L:
convertView = getLayoutInflater().inflate(R.layout.page2, parent, false);
break;
case PAGE_3:
convertView = getLayoutInflater().inflate(R.layout.page3, parent, false);
break;
default:
convertView = null;
Log.e(TAG, "Invalid page.");
break;
} /* switch(currentPage) */
mViews[position] = convertView;
} /* if(null == mViews[position]) */
else {
convertView = mViews[position];
}
return convertView;
} /* getView() */