I am following Android Archt. component to build a project. Following the guidelines I have created a custom Adapter named CataloguesAdapter extending DataBoundListAdapter as :
public class CataloguesAdapter extends DataBoundListAdapter<CatalogueEntity, CatalogueItemBinding> {
private final android.databinding.DataBindingComponent dataBindingComponent;
private final ContributorClickCallback callback;
private CatalogueItemBinding mBinding;
public CataloguesAdapter(DataBindingComponent dataBindingComponent,
ContributorClickCallback callback) {
this.dataBindingComponent = dataBindingComponent;
this.callback = callback;
}
#Override
protected CatalogueItemBinding createBinding(ViewGroup parent) {
mBinding = DataBindingUtil
.inflate(LayoutInflater.from(parent.getContext()),
R.layout.catalogue_item, parent, false,
dataBindingComponent);
//while this click event is working fine
mBinding.getRoot().setOnClickListener(v -> {
CatalogueEntity catalogueEntity = mBinding.getCatalogue();
if (catalogueEntity != null && callback != null) {
callback.onClick(catalogueEntity);
}
});
//todo:not working, this event is not firing
mBinding.deleteIcon.setOnClickListener(v-> callback.onItemDelete());
return mBinding;
}
}
I am implementing swipe to delete layout on Recycler view item. Below is the XML layout of list item:
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
<variable
name="catalogue"
type="com.mindtree.igxbridge.traderapp.datasource.local.entity.CatalogueEntity" />
</data>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardUseCompatPadding="true">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:id="#+id/view_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorRed">
<ImageView
android:id="#+id/delete_icon"
android:layout_width="#dimen/dimen_30_dp"
android:layout_height="#dimen/dimen_30_dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="#dimen/dimen_10_dp"
app:srcCompat="#drawable/ic_delete"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginEnd="#dimen/dimen_10_dp"
android:layout_toStartOf="#id/delete_icon"
android:text="#string/text_delete"
android:textColor="#color/Material.87.white"
android:textSize="14sp" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/view_foreground"
android:layout_width="match_parent"
android:background="#FFFFFF"
android:layout_height="wrap_content">
<android.support.v7.widget.AppCompatImageView
android:id="#+id/arrow_icon"
android:layout_width="#dimen/dimen_30_dp"
android:layout_height="#dimen/dimen_30_dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="#dimen/dimen_10_dp"
app:srcCompat="#drawable/ic_arrow_right" />
</RelativeLayout>
</FrameLayout>
</android.support.v7.widget.CardView>
</layout>
Another operation like swipe left/right is working fine but clicking on Delete button event is not getting called.
I tried checking findViewbyId and register click event by that, but no luck with that too.
While CatalogueItemBinding is registered correctly, I am not able to find any other source of error.
Thanks.
Correct me if I have misunderstood your code. You used a FrameLayout to host two relative layouts one top of each other (foreground and background). The delete button is in the background and foreground has match_parent in its width attribute. Therefore, I think the delete button is getting covered by the foreground, leading to "not firing of the event".
Possible Solution
Try incorporating the delete button in the foreground. It makes sense to put UI components in the front.
I think you forget to tell your adapter class to where your XML is set or not to adapter class. just create a variable in XML which will import your adapter class have look.
<variable
name="myAdapter"
type="import your adapter class">
</variable>
Now set this variable to your adapter.
#Override
protected CatalogueItemBinding createBinding(ViewGroup parent) {
mBinding = DataBindingUtil
.inflate(LayoutInflater.from(parent.getContext()),
R.layout.catalogue_item, parent, false,
dataBindingComponent);
mBinding .setmyAdapter(this);
return mBinding;
}
}
then your click will work. Hope it will help you.
Related
I am guessing my problem is with inflating layouts. I have 2 layout files:
activity_mail.xlm:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/results"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/profilesCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
android:textSize="18sp" />
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
... and listitem_device.xlm:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/device_label"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"/>
<TextView
android:id="#+id/device_service"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.5"/>
</LinearLayout>
in my main_activity java file, I have:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
....
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder;
if (view == null) {
view = mInflator.inflate(R.layout.listitem_device, null);
viewHolder = new ViewHolder();
viewHolder.deviceAddress = (TextView) view.findViewById(R.id.device_label); // from listitem_device.xml
viewHolder.profilesCount = (TextView) view.findViewById(R.id.profilesCount); // from activity_main.xml
The problem is the subsequent code:
viewHolder.profilesCount.setText("HELLO");
generates the error "Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference".
How do I fix this?
I don't see anywhere that you have even have a view with id "profilesCount".You only have device label and device service as ids in the layout file that you are using to inflate the rows of the list view.Better use Recycler view also, it provides more flexibility.
Also, you can't access something from activity_mail.xml in the getView() function of your adapter because by using "view" in getfunction, as that corrspond to only the row of the list view and since that id is not present in the xml file associated with the row of list view, you are getting "viewholders.profileCount" as null and hence the Nullpointer exception.
If you wanna use a TextView or any view in your adapter, better create an interface and implement that interface in your activity to use as a call back and then set the textview field of your activity.xml file, thats the best way as it would keep your code cleaner.Other way is to pass the reference of the activity to your adapter and then find the text view or whatever that you wanna use from actvity_mail.xml file, but its not recommended and is a very bad way as it may require additional memory.
I am creating a simple view where on the top I have some elements and below a recyclerView. When I scroll it down, would like to scroll the whole screen, not the only recycler.
I have achieved it with NestedScrollView, however, now the problem appears. Items in the list will be pretty heavy and in this configuration, all the items are bind at the same time(call of onBindViewHolder).
any ideas how to make them recycle and solve this problem?
Here is my xml file
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView 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:background="#android:color/darker_gray"
android:orientation="vertical"
tools:context="com.gkuziel.testkotlin.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:src="#drawable/ic_available_stores_default" />
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="test text" />
<android.support.v7.widget.RecyclerView
android:id="#+id/list_test"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:isScrollContainer="false"
android:nestedScrollingEnabled="false">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
Update:
The found a sweet solution: you add a complex header as ItemDecoration, its great cause your adapter can stay untouched, you just add sth like this:
recyclerView.addItemDecoration(dividerItemDecoration);
the only drawback of this solution is i couldn't make this header clickable (in my case it contains another recyclerView), however I know some people achieved it as well.
For this moment I decided implement heterogeneous recyclerview, with 1 instance of header type and the rest of simple row types.
What is important, the header type is fully binded once in HeaderViewHolder constructor and onBindViewHolder looks like this:
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is HeaderViewHolder) {
//do nothing
Log.d("ProductAdapter", "Binding: Header")
} else if (holder is ItemViewHolder) {
Log.d("ProductAdapter", "Binding: " + position.toString())
val searchItem = items!![position - 1]
//here the proper binding is going on
}
}
You can try setting the recyclerview layout manager's method canScrollVertical to false and it won't respond to any touch inner scroll events.
override below method and return false.
boolean canScrollVertically()
here it is how to set.
#Override
protected void onCreate(Bundle savedInstanceState) {
// ...
// Lookup the recyclerview in activity layout
RecyclerView listTest = (RecyclerView) findViewById(R.id.list_test);
// Attach the adapter to the recyclerview to populate items
listTest.setAdapter(adapter);
// Set layout manager to position the items
listTest.setLayoutManager(new LinearLayoutManager(this){
#Override
public boolean canScrollVertically(){
return false;
}
});
// That's all!
}
Goodd day.I have simple recycler view with simplest dummy datas for test purpose,thus i have an weird issue to which the google did not find any solution or even an issue at all.On first launch the view is all good but as soon as i start to scrool,the child items are being as far from each other as no one can image...Really very and very far.But the issue is that the actual child items layout parameters are correct,only issue is that i dont know why RecyclerView decides to have each item heaps far away from each other.Please can you give me an help?Posting full code of my RecyclerView.
The view for recyclerView
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="com.ink.activities.HomeActivity"
tools:showIn="#layout/app_bar_home">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical" />
</RelativeLayout>
The Adapter.
public class FeedAdapter extends RecyclerView.Adapter<FeedAdapter.ViewHolder> {
private List<FeedModel> feedList;
private Context mContext;
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView title, content;
public ViewHolder(View view) {
super(view);
title = (TextView) view.findViewById(R.id.feedTitle);
content = (TextView) view.findViewById(R.id.feedContent);
}
}
public FeedAdapter(List<FeedModel> feedList, Context context) {
mContext = context;
this.feedList = feedList;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.feed_single_view, parent, false);
return new ViewHolder(itemView);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
FeedModel feedModel = feedList.get(position);
holder.title.setText(feedModel.getTitle());
holder.content.setText(feedModel.getContent());
// animate(holder);
}
public void animate(RecyclerView.ViewHolder viewHolder) {
final Animation animAnticipateOvershoot = AnimationUtils.loadAnimation(mContext, R.anim.bounce_interpolator);
viewHolder.itemView.setAnimation(animAnticipateOvershoot);
}
#Override
public int getItemCount() {
return feedList.size();
}
}
I guess you won`t need holder as no view initiated with it.
The single child item view of RecyclerView adapter.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:clickable="true"
android:foreground="?android:attr/selectableItemBackground"
app:cardCornerRadius="5dp"
app:cardElevation="10dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/feedTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
android:fontFamily="#string/appFont"
android:text="loading...."
android:textColor="#000000"
android:textSize="20sp" />
<TextView
android:id="#+id/feedContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/feedTitle"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:layout_marginTop="10dp" />
</RelativeLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
The initiation of actual parameters.
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mAdapter = new FeedAdapter(mFeedModelArrayList, this);
RecyclerView.ItemAnimator itemAnimator = new DefaultItemAnimator();
itemAnimator.setAddDuration(500);
itemAnimator.setRemoveDuration(500);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setItemAnimator(itemAnimator);
This code is as simple as it can get and it is important to mention that i am initiation all this inside the default NAVIGATION DRAWER ACTIVITY of android studio (the default templae inside content_main layout).So plaese can you give me any hint about the issue?
You're using
android:layout_width="match_parent"
android:layout_height="match_parent"
on your child item views. As of Support Library 23.2:
The RecyclerView widget provides an advanced and flexible base for creating lists and grids as well as supporting animations. This release brings an exciting new feature to the LayoutManager API: auto-measurement! This allows a RecyclerView to size itself based on the size of its contents. This means that previously unavailable scenarios, such as using WRAP_CONTENT for a dimension of the RecyclerView, are now possible. You’ll find all built in LayoutManagers now support auto-measurement.
Due to this change, make sure to double check the layout parameters of your item views: previously ignored layout parameters (such as MATCH_PARENT in the scroll direction) will now be fully respected.
Change your layout_height to wrap_content if you only want your items to be as large as needed. match_parent means they will be as large as the screen.
Trying to create custom rows in my listview (to look like this). I've created a custom row layout & derived adapter class. The data loads and shows fine, but the text is not using any format/style specified in my custom row .xml layout file. It's all just the default size/weight, etc.
Here's the custom row layout (listview_desc.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="fill_parent"
android:orientation="vertical"
android:background="#222222">
<TextView
android:id="#+id/name"
android:text="Name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_margin="10dip"
android:textStyle="bold"
android:textSize="20dip"
/>
<TextView
android:id="#+id/description"
android:text="Description"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_margin="10dip"
android:textSize="13dip" />
</LinearLayout>
Here's my main layout file:
<?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="fill_parent"
android:theme="#android:style/Theme.NoTitleBar"
android:minWidth="25px"
android:minHeight="25px"
android:background="#drawable/gradient_darkbg">
<ListView
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/listView1" />
</LinearLayout>
My adapter code (I'm using Xamarin, but I don't think that's the problem...)
public class ListViewFormAdapter : BaseAdapter<Form>
{
List<Form> mForms;
Activity context;
public ListViewFormAdapter(Activity context, List<Form> items)
: base()
{
this.context = context;
this.mForms = items;
}
public override long GetItemId(int position)
{
return position;
}
public override Form this[int position]
{
get { return mForms[position]; }
}
public override int Count
{
get { return mForms.Count; }
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var item = mForms[position];
View view = convertView;
if (view == null) // no view to re-use, create new
view = context.LayoutInflater.Inflate(Resource.Layout.listview_desc, null);
view.FindViewById<TextView>(Resource.Id.name).Text = item.Name;
view.FindViewById<TextView>(Resource.Id.description).Text = item.Description;
return view;
}
}
And finally the main activity where I load and use the adapter:
public class HomeScreenActivity : Activity
{
List<Form> mForms;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Create your application here
SetContentView (Resource.Layout.Home);
// Load all forms and populate the main menu
mForms = Utils.FormLoader.LoadForms("Forms");
ListView listView = FindViewById<ListView>(Resource.Id.listView1);
listView.Adapter = new ListViewFormAdapter(this, mForms);
}
}
Sorry for all the code, maybe it'll help someone in the future... thanks for any help.
I'm not sure that this is the problem, but you inflating the views incorrectly. it should be
view = inflater.inflate(R.layout.listview_desc, parent, false);
instead of
view = context.LayoutInflater.Inflate(Resource.Layout.listview_desc, null);
using the 3 parameter version of inflate
What styles aren't showing correctly? I'm not sure what you're expecting or what you're seeing from the question. If it is to do with alignment, you should bear in mind that android:layout_alignParentLeft="true" is not valid in a LinearLayout
Thanks for the response guys. Turns out it was some problem with Git/Xamarin. I committed my sources at another machine, came home, synced up and all my formatting in the row layout xml were gone. Who knows... maybe a cached version was being used or something. I actually had to use the code posted on this page to get it to work (since it was lost), so maybe someone can use this as example code. It works.
I have the following situation:
in the main file I do
setContentView(R.layout.main);
which looks as follows:
<?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="fill_parent"
android:id="#+id/layout"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/result"
android:text="Gesamtstrecke: 0.0"
/>
<test.gustav.Spielfeld
android:id="#+id/spielfeld"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
</test.gustav.Spielfeld>
</LinearLayout>
the View "test.gustav.Spielfeld" refers to a class "Spielfeld" extending "View".
I now need a method that updates the content of the TextView with id "result" if a something happens in the onTouchEvent(..)-method in the Spielfeld-View.
How to do this? I've tried making a public TextView in the Main-Class but the Spielfeld class won't accept Main.this.myTextView.
I would recommend a callback approach (just like android does for all events):
Create a interface which represents the callback:
public interface OnSpielfeldUpdate {
public void onSpielfeldUpdate(Object myEventData, ...);
}
Provide a setter for the callback in SpielFeld (which will be used to send updates):
public void setOnSpielfeldUpdate(OnSpielfeldUpdate callback) {
this.callback = callback;
}
Set your callback in your activity (or somewhere else):
mySpielfeld.setOnSpielfeldUpdate(new OnSpielfeldUpdate() {
public void onSpielfeldUpdate(Object myEventData, ...) {
// perform update on result view
}
}