Kotlin Android Extensions: How to get a reference to a view in a layout that gets included into another layout? - kotlin-android-extensions

I have a layout that includes another layout:
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"/>
<include layout="#layout/included_layout" />
</LinearLayout>
included_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/includedTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Included TextView"/>
</LinearLayout>
How can I get a reference to the TextView in the included layout? Is it not supported (yet)?
MainActivity:
import android.app.Activity
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import kotlinx.android.synthetic.activity_main.*
class MainActivity : AppCompatActivity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
textView.text = "text" // works!
textViewInclude.text = "textInclude" // does not work: "Unresolved reference: textViewInclude "
}
}

You should import the included layout.
import android.app.Activity
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.included_layout.* // Here
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// From activity_main.textView
textView.text = "text"
// From included_layout.textViewInclude
textViewInclude.text = "textInclude"
}
}

In the Activity where you want acess of other layout element implement click Listner
class LoginActivity : AppCompatActivity(), View.OnClickListener {
override fun onClick(view: View?) {
when (view?.id) {
R.id.dialog_cancel-> { dialog.cancel() }
}
}
}
in the another layout which you are importing in your Activity, place onClick() in the element and refrence it to the Activity where you imported onClick listner
android:onClick="onClick"
It will work definetly and the another xml element will listen the click

Related

Xamarin latest update findviewbyid returns null

I just installed the latest update of Xamarin for Visual Studio.
Ever since, android can't find the views in my activity layouts.
Apparently the auto-generated IDs aren't updated correctly when i just save my resources.
If I clean the project and rebuild, my app runs fine. But after like 20 minutes of coding the problem will occur again.
Simple code: Resources/Layout/Main.axml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="9dp"
android:paddingBottom="9dp">
<Button
android:text="#string/action_stockcount"
android:layout_width="match_parent"
android:layout_height="90dp"
android:id="#+id/btnStockCount"
android:layout_marginLeft="18dp"
android:layout_marginRight="18dp"
android:layout_marginStart="9dp"
android:layout_marginTop="9dp"
android:textColor="#color/menu_button_text"
android:textSize="30dp"
android:drawableLeft="#drawable/menu_stockcount_big"
android:paddingLeft="18dp"
android:paddingRight="18dp"
android:paddingBottom="9dp"
android:paddingTop="9dp" />
</LinearLayout>
</ScrollView>
MainActivity.designer.cs:
using ...
namespace MyApp.Droid.Activities
{
public partial class MainActivity
{
private Button btnStockCount;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Main);
SetTitle(Resource.String.ApplicationName);
btnStockCount = FindViewById<Button>(Resource.Id.btnStockCount);
// From time to time, this gives a NullReferenceException
btnStockCount.Click += BtnStockCount_Click;
InitComplete(savedInstanceState);
}
}
}
MainActivity.cs (Not quite important):
using ...
namespace MyApp.Droid.Activities
{
public partial class MainActivity : Activity
{
private void BtnStockCount_Click(object sender, EventArgs e)
{
StartActivity(typeof(IndexStockCountActivity));
}
}
}
I know how android works, I know how Xamarin works. Why would the latest update of Xamarin cause this issue (the IDs that aren't updated correctly when saving a resource)? What can I do to solve this issue?
It's really annoying to have to debug my project, notice that again it's not working well, and having to clean and rebuild, and notice that after that it IS working.
I also already noticed that when it's not working, after I cleaned and rebuilded the Resource Ids are in fact changed.
Cheers

MvvmCross creating custom binding to LinearLayout

I am trying to create a custom binding to LinearLayout to allow me create a view dynamically and bind this as a child to LinearLayout. For anyone familiar with WPF, this is similar to the functionality provided by the ContentControl or any WPF control deriving from ContentControl. Basically you can create your dynamic content and bind to the Content property of a ContentControl.
Here's what I have for the custom binding:
public class MvxLinearLayoutContentTargetBinding : MvxPropertyInfoTargetBinding<LinearLayout>
{
public MvxLinearLayoutContentTargetBinding(object target, PropertyInfo targetPropertyInfo) : base(target, targetPropertyInfo)
{
}
protected override void SetValueImpl(object target, object value)
{
base.SetValueImpl(target, value);
var view = target as LinearLayout;
if (view == null) return;
view.AddView((View)value);
}
public override Type TargetType
{
get { return typeof(LinearLayout); }
}
}
Here's how I am attempting to use this new binding in my layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="3dp"
android:paddingTop="3dp"
android:paddingLeft="5dp">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="3dp"
android:paddingTop="3dp"
android:paddingLeft="0dp"
local:MvxBind="Content CustomView">
</LinearLayout>
</LinearLayout>
Any my ViewModel looks like this:
public class CustomViewModel : MvxViewModel
{
public object CustomView { get; set; }
}
The custom binding has also been registered in Setup.cs as follows:
protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
{
registry.RegisterPropertyInfoBindingFactory(
typeof(MvxLinearLayoutContentTargetBinding),
typeof(LinearLayout), "Content");
base.FillTargetFactories(registry);
}
Yet with all this in place, I do not see my view.
MvvmCross already supports a primitive version of this. Although without DataTemplateSelector.
You can bind a collection of ViewModels to MvxLinearLayout.ItemsSource. You also need to remember to set a ItemTemplateId:
<MvxLinearLayout
...
local:MvxItemTemplateId="#layout/layout_to_repeat"
local:MvxBind="ItemsSource ViewModelCollection"
/>
This is however super inefficient as it does not recycle views etc. So if you need a variant that supports DataTemplateSelector, then use MvxRecyclerView instead.

xamarin mvvmcross binding relative layout

I am new to mvvmcross. I do not know how to bind touch event of a relative layout to a view model. Can someone help me on this. Thanks in advance.
This is possible using standard MvvmCross code. For the viewmodel you can use something like:
public class SomeViewModel : MvxViewModel
{
public IMvxCommand OpenSomethingCommand { get; private set; }
public SomeViewModel ()
{
OpenSomethingCommand = new MvxCommand(() => ShowViewModel<SomeOtherNewViewModel>());
}
}
Then for the layout in your android project, you can use:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
local:MvxBind="Click OpenSomethingCommand"
android:id="#+id/someLayout">
//Wrap any other layouts in here
</RelativeLayout>

Implementing JazzyViewPager

Branching from my other question from HERE, I want to try and implement JazzyViewPager. I tried following the setup instructions along with a few other posts on this site, but was unable to get it working, just did the ViewPager action.
Below is the relevant untouched (sync issue with AIDE erased previous) code I'm working with.
MainActivity:
pageAdapter = new MyPagerAdapter(getSupportFragmentManager());
final ViewPager pager = (ViewPager) findViewById(R.id.myViewPager);
pager.setAdapter(pageAdapter);
pager.setOffscreenPageLimit(1);
pager.setPageMarginDrawable(R.color.pager_bg);
MyPagerAdapter:
package com.chris.myapp;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import com.chris.myapp.fragment.Shoutbox;
import com.chris.myapp.fragment.WebViewFragment;
import java.util.ArrayList;
import java.util.List;
public class MyPagerAdapter extends FragmentPagerAdapter {
public static final int WEBVIEW_FRAGMENT_POSITION = 0;
public static final int SHOUTBOX_FRAGMENT_POSITION = 1;
private List<Fragment> fragments;
public MyPagerAdapter(FragmentManager fm) {
super(fm);
this.fragments = new ArrayList<Fragment>();
fragments.add(new WebViewFragment());
fragments.add(new Shoutbox());
}
public Fragment getItem(int position) {
return fragments.get(position);
}
public int getCount() {
return fragments.size();
}
}
Content.xml
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/myViewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#111" />
Any help would be greatly appreciated.
You can get the package libraries here
You content xml should be:
<packagename.JazzyViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/myViewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#111" />
You call the MainAdapter class to initialize the object and your various screens by:
JazzyViewPager mPager = (JazzyViewPager)findViewById(R.id.pager);
mPager.setAdapter(new MainAdapter());
Various transition effects are available like:
public enum TransitionEffect {
Standard,
Tablet,
CubeIn,
CubeOut,
Flip,
Stack,
ZoomIn,
ZoomOut,
RotateUp,
RotateDown,
Accordion
}
All these animations are placed in the JazzyViewPager class and you can call any one of the above mentioned animations by:
mPager.setTransitionEffect(TransitionEffect.*);
I hope the answer helps. I you still are unable to do it then i can post the code by which i have implemented the JazzyViewPager.

Custom ToggleButton findViewById Null Pointer

I have been trying to solve this problem for hours now and have exhausted all the obvious solutions. I have a custom toggle button that works fine as long as I don't try to get it using findViewById
Here is the relevant code:
public class WeekButton extends ToggleButton {
private static int mWidth;
public WeekButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public WeekButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
...
}
Here is the layout..
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:gravity="center"
android:orientation="horizontal"
android:padding="5dp">
<org.myname.projetname.reminders.WeekButton.WeekButton
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mondayToggleButton"
style="#style/RecurrenceDayOfWeekStyle"
android:textOff=" Mon"
android:textOn=" Mon" />
</LinearLayout>
Exception occurs here..
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.edit_reminder_activity);
//This causes null pointer
WeekButton weekButton = (WeekButton)findViewById(R.id.mondayToggleButton));
}
Thanks for any help you can provide!
SOLUTION: Turns out I forgot to instantiate the list I was adding the WeekButtons which made it look like the call to find id was working but it was. Thank you everyone you tried to help.
Didn't it show any error before run? xml name space attribute is given for the parent tag.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:gravity="center"
android:orientation="horizontal"
android:padding="5dp">
<org.myname.projetname.reminders.WeekButton.WeekButton
android:id="#+id/mondayToggleButton"
style="#style/RecurrenceDayOfWeekStyle"
android:textOff=" Mon"
android:textOn=" Mon" />
</LinearLayout>
Also, Cast to your class on findViewById().
Forgot to instantiate a list I was adding the weekbuttons to.

Resources