ConstraintSet.RIGHT not working - android-constraintlayout

I am trying to create an app that can dynamically add view to a ConstraintLayout without a database. I put LayoutParams to wrap there sizes to see where they are going. I already am able to add views but I don't know why they keep going to the left side of the screen and there size are the same even though i used different LayoutParams for each view. Also the margins seems to not work as well. Below is my code:
ConstraintSet set = new ConstraintSet();
ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(
ConstraintLayout.LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.WRAP_CONTENT);
lp.setMargins(8, 8, 8, 0);
ConstraintLayout.LayoutParams lpWrap = new ConstraintLayout.LayoutParams(
ConstraintLayout.LayoutParams.WRAP_CONTENT, ConstraintLayout.LayoutParams.WRAP_CONTENT);
int fieldCount = sharedPref.getInt(fieldCountTag, 0);
fieldCount++;
editor = sharedPref.edit();
editor.putInt(fieldCountTag, fieldCount);
editor.commit();
EditText txt = new EditText(ctx);
txt.setHint("IP:Port "+fieldCount);
txt.setInputType(InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT);
txt.setId(fieldCount);
txt.setLayoutParams(lp);
Button btn = new Button(ctx);
btn.setText("Use "+fieldCount);
btn.setId(fieldCount);
btn.setLayoutParams(lpWrap);
mainLyt.addView(txt);
mainLyt.addView(btn);
set.clone(mainLyt);
set.connect(btn.getId(), ConstraintSet.RIGHT, mainLyt.getId(), ConstraintSet.RIGHT, 8);
set.connect(btn.getId(), ConstraintSet.TOP, txt.getId(), ConstraintSet.TOP, 0);
set.connect(txt.getId(), ConstraintSet.LEFT, mainLyt.getId(), ConstraintSet.LEFT, 8);
set.connect(txt.getId(), ConstraintSet.TOP, txt3.getId(), ConstraintSet.BOTTOM, 8);
set.connect(txt.getId(), ConstraintSet.RIGHT, btn.getId(), ConstraintSet.LEFT, 8);
set.applyTo(mainLyt);
UPDATE:
what im trying to do is just simply adding a edittext and button side by side
UPDATE:
my current code:
ConstraintSet set = new ConstraintSet();
ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(
ConstraintLayout.LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.WRAP_CONTENT);
lp.setMargins(8, 8, 8, 0);
ConstraintLayout.LayoutParams lpWrap = new ConstraintLayout.LayoutParams(
ConstraintLayout.LayoutParams.WRAP_CONTENT, ConstraintLayout.LayoutParams.WRAP_CONTENT);
int fieldCount = sharedPref.getInt(fieldCountTag, initFieldCount);
int topViewId = 0;
for(int x = 3; x < fieldCount; x++){
if(txtId != 0){
prevTxtId = txtId;
}
txtId = View.generateViewId();
btnId = View.generateViewId();
int id = x;
id++;
EditText txt = new EditText(ctx);
txt.setHint("IP:Port "+id);
txt.setInputType(InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT);
txt.setId(txtId);
txt.setLayoutParams(lp);
Button btn = new Button(ctx);
btn.setText("Use "+id);
btn.setId(btnId);
btn.setLayoutParams(lpWrap);
mainLyt.addView(txt);
mainLyt.addView(btn);
set.clone(mainLyt);
if(x == 3){
Log.d(TAG, "txt3Id: "+txt3.getId());
topViewId = txt3.getId();
}else{
topViewId = prevTxtId;
}
set.connect(btnId, ConstraintSet.END, mainLyt.getId(), ConstraintSet.END, 0);
set.connect(btnId, ConstraintSet.TOP, txtId, ConstraintSet.TOP, 0);
set.connect(txtId, ConstraintSet.START, mainLyt.getId(), ConstraintSet.START, 0);
set.connect(txtId, ConstraintSet.TOP, topViewId, ConstraintSet.BOTTOM, 0);
set.connect(txtId, ConstraintSet.END, btnId, ConstraintSet.START, 0);
set.applyTo(mainLyt);
}
UPDATE:
my load method:
ConstraintSet set = new ConstraintSet();
ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(
ConstraintLayout.LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.WRAP_CONTENT);
lp.setMargins(8, 8, 8, 0);
ConstraintLayout.LayoutParams lpWrap = new ConstraintLayout.LayoutParams(
ConstraintLayout.LayoutParams.WRAP_CONTENT, ConstraintLayout.LayoutParams.WRAP_CONTENT);
int fieldCount = sharedPref.getInt(fieldCountTag, initFieldCount);
int topViewId = 0;
Log.d(TAG, "fieldCount: "+fieldCount);
Log.d(TAG, "------");
for(int x = 3; x < fieldCount; x++){
if(txtId != 0){
prevTxtId = txtId;
}
txtId = View.generateViewId();
btnId = View.generateViewId();
int id = x;
id++;
EditText txt = new EditText(ctx);
txt.setHint("IP:Port "+id);
txt.setInputType(InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT);
txt.setId(txtId);
txt.setLayoutParams(lp);
Button btn = new Button(ctx);
btn.setText("Use "+id);
btn.setId(btnId);
btn.setLayoutParams(lpWrap);
mainLyt.addView(txt);
mainLyt.addView(btn);
set.clone(mainLyt);
if(x == 3){
Log.d(TAG, "txt3Id: "+txt3.getId());
topViewId = txt3.getId();
}else{
topViewId = prevTxtId;
}
Log.d(TAG, "txtId: "+txtId+" connect to topView: "+topViewId+" end"+" btnId: "+btnId);
set.connect(btnId, ConstraintSet.END, mainLyt.getId(), ConstraintSet.END, 0);
set.connect(btnId, ConstraintSet.TOP, txtId, ConstraintSet.TOP, 0);
set.connect(txtId, ConstraintSet.START, mainLyt.getId(), ConstraintSet.START, 0);
set.connect(txtId, ConstraintSet.TOP, topViewId, ConstraintSet.BOTTOM, 0);
set.connect(txtId, ConstraintSet.END, btnId, ConstraintSet.START, 0);
prevTxtId = txtId;
set.applyTo(mainLyt);
}
UPDATE:
I tried using 3 EditText inside the xml to connect to each other and it worked fine. The logic is the same for my load method by it still doesnt work. The views keep going to the top. The logs shows
txtId: 1 connect to topView: 2131558527 end btnId: 2 fieldCount: 4
txtId: 3 connect to topView: 1 end btnId: 4 fieldCount: 5
which should be correct right.
UPDATE:
here is my xml if you want to try it
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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:id="#+id/mainLyt"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="app.com.simplewebview.MainActivity">
<EditText
android:id="#+id/txt1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:ems="10"
android:hint="IP:Port 1"
android:inputType="textUri"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="#+id/btn1"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="8dp"
android:layout_marginTop="0dp"
android:text="Use 1"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="#+id/txt1" />
<EditText
android:id="#+id/txt2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:ems="10"
android:hint="IP:Port 2"
android:inputType="textUri"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="#+id/btn2"
app:layout_constraintTop_toBottomOf="#+id/txt1" />
<Button
android:id="#+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="8dp"
android:layout_marginTop="0dp"
android:text="Use 2"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="#+id/txt2" />
<EditText
android:id="#+id/txt3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:ems="10"
android:hint="IP:Port 3"
android:inputType="textUri"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="#+id/btn3"
app:layout_constraintTop_toBottomOf="#+id/txt2" />
<Button
android:id="#+id/btn3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="8dp"
android:layout_marginTop="0dp"
android:text="Use 3"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="#+id/txt3" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginRight="8dp"
android:clickable="true"
app:fabSize="mini"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:srcCompat="#mipmap/ic_launcher" />
</android.support.constraint.ConstraintLayout>

txt and btn need to have different ids or the contraints won't work. Try use View.generateViewId() if you have a minSdkVersion of 17 or higher. Whatever you do, your views need distinct ids.
Once you make sure the ids you set are distinct, check out your constraints. These look OK but it is unclear what you vertical constraint in the container is until txt3 has a vertical constraint. Also, try start/end instead of left/right if you still have trouble.
There may be some other things going on, but make these changes and you should see some of your issues disappear.

Related

Xamarin Adapter FindViewById returns null

Not sure what I'm doing wrong here but FindViewById always returns null for my custom row view:
public override View GetView(int position, View convertView, ViewGroup parent) {
var view = convertView;
var item = items[position];
if(view == null)
view = context.LayoutInflater.Inflate(Resource.Layout.listview_row, null);
var nameTextView = view.FindViewById<TextView>(Resource.Id.nameTextView);
var priceTextView = view.FindViewById<TextView>(Resource.Id.priceTextView);
nameTextView.Text = item.Name;
priceTextView.Text = (item.Price ?? 0M).ToString("#.00");
return view;
}
This is the view code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView id="#+id/nameTextView"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="0.8"
android:layout_margin="5dp" />
<TextView id="#+id/priceTextView"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="0.2"
android:layout_margin="5dp" />
</LinearLayout>
The view inflates correctly but for some reason both TextViews are always null after the call to FindViewById.
I have tried cleaning and rebuilding the project but that did not work. Not sure why this is not working.
Thank you for any pointers.
You are providing an id with the wrong way hence it is not getting registered in Resource designer
Try this :
android:id="#+id/nameTextView"
android:id="#+id/priceTextView"

In android, A ListView Contains a TextView, and how to set minHeight for TextView

I have a ListItem with TextView.I set the minHeight of TextView as follows.
list_item_forecast.xml
<TextView ?xml version="1.0" encoding="utf-8"?>
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id = "#+id/list_item_forecast_textView"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeight"
/>
and the fragment file xml is as follows.
fragment_main.xml
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context=".ForecastFragment">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/listView_forecast"
/>
Even though I set the minHeight of textView to "?android:attr/listPreferredItemHeight" , I am seeing the output on device as follows.
This the code in fragment.java. Need to display forecastArrayAdapter String data in ListView
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
String[] forecastArray = new String[]{"Today - Sunny - 86/83",
"Tomorrow - Foggy - 70/46",
"Weds - Cloudy - 72/63",
"Thurs - Rainy - 64/51",
"Fri - Foggy - 70/46",
"Sat - Sunny - 76/68",
"Sun - Sunny - 20/7"};
List<String> weekForecast = new ArrayList<String>(Arrays.asList(forecastArray));
ArrayAdapter<String> mForecastAdapter = new ArrayAdapter<String>(getActivity(), R.layout.list_item_forecast,
R.id.list_item_forecast_textView,weekForecast );
ListView listView = (ListView) rootView.findViewById(R.id.listView_forecast);
listView.setAdapter(mForecastAdapter);
return rootView;
}
Could someone help me out setting the minHeight for each text?
Thanks
Though I can't see any TextView in your list_item_forcast.xml
In your text view you have to add: android:minLines = "3" and android:maxLines = "3"
It will keep the height of textView for 3 lines.
A sample TextView will look like:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="6dip" >
<TextView
android:id="#+id/tv_addesc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
android:maxLines="3"
android:minLines="3"
android:textColor="#FFFFFFFF"
android:textSize="15sp" />
</RelativeLayout>
Note: If the number of characters exceeds the 3 line limit then it will show text like below:
"
Hello world
Hello world
Hello world..."

How to create app bar with icons using TabLayout Android Design?

I'm trying to use the new TabLayout in the android design library to create app bar with icons.
public void setupTabLayout(TabLayout tabLayout) {
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
tabLayout.setTabGravity(TabLayout.GRAVITY_CENTER);
tabLayout.setupWithViewPager(mViewpager);
tabLayout.getTabAt(0).setIcon(R.drawable.ic_tabbar_library);
tabLayout.getTabAt(1).setIcon(R.drawable.ic_tabbar_recents);
tabLayout.getTabAt(2).setIcon(R.drawable.ic_tabbar_favorites);
tabLayout.getTabAt(3).setIcon(R.drawable.ic_tabbar_notifications);
tabLayout.getTabAt(4).setIcon(R.drawable.ic_tabbar_settings);
}
Result:
Please help me to create app bar similar:
Sorry my english is not good.Thanks is advance !
From the documentation :
https://developer.android.com/reference/android/support/design/widget/TabLayout.Tab.html#setCustomView(android.view.View)
Set a custom view to be used for this tab. This overrides values set
by setText(CharSequence) and setIcon(Drawable).
you will have to set the title values yourself
From your example:
public void setupTabLayout(TabLayout tabLayout) {
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
tabLayout.setTabGravity(TabLayout.GRAVITY_CENTER);
tabLayout.setupWithViewPager(mViewpager);
TextView tab = (TextView) LayoutInflater.from(this).inflate(R.layout.custom_tab, null);
tab.setText("Library");
tab.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.ic_tabbar_library, 0, 0);
tabLayout.getTabAt(0).setCustomView(tab);
//..
}
custom_tab.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/tab" />
Update
The api has changed to allow you to set a custom id so you don't have to set the text/drawable manually. It'll use the adapter's values.
If the provided view contains a TextView with an ID of text1 then that
will be updated with the value given to setText(CharSequence).
Similarly, if this layout contains an ImageView with ID icon then it
will be updated with the value given to setIcon(Drawable).
You can use the attribute android:layout of TabItem to set custom view.
In custom view xml file, remember to set id of icon and text view to #android:id/icon and android:id="#android:id/text1", then the library will take care the rest.
Here's an example:
. custom_tab_item.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="#android:id/icon"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginTop="4dp"
android:scaleType="centerInside"/>
<TextView
android:id="#android:id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:textSize="16dp"/>
</LinearLayout>
. main.xml
<android.support.design.widget.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TabItem
android:id="#+id/ti_activities"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:icon="#drawable/ic_question"
android:layout="#layout/custom_tab_item"
android:text="#string/activities"/>
<android.support.design.widget.TabItem
android:id="#+id/ti_profile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:icon="#drawable/ic_question"
android:layout="#layout/custom_tab_item"
android:text="#string/Profile"/>
</android.support.design.widget.TabLayout>
Hope this help.
As documentation said You can add items to TabLayout through the xml by use of TabItem. An example usage is like:
<android.support.design.widget.TabLayout
android:layout_height="wrap_content"
android:layout_width="match_parent">
<android.support.design.widget.TabItem
android:text="#string/tab_text"/>
<android.support.design.widget.TabItem
android:icon="#drawable/ic_android"/>
</android.support.design.widget.TabLayout>
When you use vector drawables as icons you might want to reuse a single drawables for different states, by simply tinting it differently. This way you can reduce the apk size and the allocation of resources. First define a custom FragmentPagerAdapter (I am using kotlin instead of java here)
class TabPagerAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm) {
override fun getCount(): Int = 2
override fun getItem(position: Int): Fragment = when (position) {
0 -> FirstFragment.newInstance()
else -> SecondFragment.newInstance()
}
fun getPageIcon(context: Context, position: Int): Drawable = when (position) {
0 -> ContextCompat.getDrawable(context, R.drawable.ic_whatshot)
else -> ContextCompat.getDrawable(context, R.drawable.ic_face)
}
}
Instead of implementing getPageTitle we create a getPageIcon method, that returns a drawable for a specific tab. Next we create a custom TabLayout:
class IconTabLayout : TabLayout {
private var viewPager: ViewPager? = null
constructor(context: Context) : super(context)
constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet)
constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr)
override fun onAttachedToWindow() {
if (viewPager == null) {
if (parent is ViewPager) viewPager = parent as ViewPager
}
super.onAttachedToWindow()
}
override fun setupWithViewPager(viewPager: ViewPager?, autoRefresh: Boolean) {
this.viewPager = viewPager
super.setupWithViewPager(viewPager, autoRefresh)
}
override fun addTab(#NonNull tab: Tab, position: Int, setSelected: Boolean) {
if (viewPager != null && viewPager!!.adapter is TabPagerAdapter) {
val icon: Drawable = DrawableCompat.wrap((viewPager!!.adapter as TabPagerAdapter).getPageIcon(context, position))
DrawableCompat.setTintList(icon.mutate(), ContextCompat.getColorStateList(context, R.color.tab_color))
tab.icon = icon
}
super.addTab(tab, position, setSelected)
}
}
So the magic happens in the addTab method, where the icon and the color state list are set. The color state list has following structure:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Non focused states -->
<item android:color="#color/tab_not_active" android:state_focused="false" android:state_pressed="false" android:state_selected="false" />
<item android:color="#color/tab_active" android:state_focused="false" android:state_pressed="false" android:state_selected="true" />
<!-- Focused states -->
<item android:color="#color/tab_not_active" android:state_focused="true" android:state_pressed="false" android:state_selected="false" />
<item android:color="#color/tab_active" android:state_focused="true" android:state_pressed="false" android:state_selected="true" />
<!-- Pressed -->
<item android:color="#color/tab_not_active" android:state_pressed="true" />
</selector>

Androidplot - creating chart without XML

I need to create some PieCharts on my Activity, and quantity of charts varies.
I try to create PieChart dynamically from code, and it's doesn't work. My Layout correct - Button added successfully. Can you help me? Some code:
Layout:
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="example.bros.nik.tabs1.MealsActivity"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/l_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
android:orientation="vertical" >
</LinearLayout>
</ScrollView>
Java:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_meals);
LinearLayout l_layout = (LinearLayout) findViewById(R.id.l_layout);
meals_params = ResultsActivity.get_meals_params();
LinearLayout.LayoutParams lp_view = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT, 1.0f);
PieChart pie = new PieChart(this, "Chart#1");
Segment s1 = new Segment("Углеводы", meals_params[0].get_carbohydrates_percent());
Segment s2 = new Segment("Жиры", meals_params[0].get_fats_percent());
Segment s3 = new Segment("Белки", meals_params[0].get_proteins_percent());
EmbossMaskFilter emf = new EmbossMaskFilter(new float[]{1, 1, 1}, 0.4f, 10, 8.2f);
SegmentFormatter sf1 = new SegmentFormatter();
sf1.configure(getApplicationContext(), R.xml.pie_segment_formatter1);
sf1.getFillPaint().setMaskFilter(emf);
SegmentFormatter sf2 = new SegmentFormatter();
sf2.configure(getApplicationContext(), R.xml.pie_segment_formatter2);
sf2.getFillPaint().setMaskFilter(emf);
SegmentFormatter sf3 = new SegmentFormatter();
sf3.configure(getApplicationContext(), R.xml.pie_segment_formatter3);
sf3.getFillPaint().setMaskFilter(emf);
pie.addSeries(s1, sf1);
pie.addSeries(s2, sf2);
pie.addSeries(s3, sf3);
pie.getRenderer(PieRenderer.class).setDonutSize(0.1f,PieRenderer.DonutMode.PERCENT);
pie.redraw();
pie.getBorderPaint().setColor(Color.TRANSPARENT);
pie.getBackgroundPaint().setColor(Color.TRANSPARENT);
l_layout.addView(pie, lp_view);
I try this:
pie.setLayoutParams(lp_view);
l_layout.addView(pie);
and it's doesn't help me.
And if I add Button to Layout:
pie.setLayoutParams(lp_view);
l_layout.addView(pie);
Button but = new Button(this);
but.setText("bla");
l_layout.addView(but, lp_view);
then I see this Button (look at screenshot).
Added button
EDIT:
In Android docs written, that in constructor
ViewGroup.LayoutParams (int width, int height)
attributes may be the absolute sizes of view, or may be constants - WRAP_CONTENT (int value -2), MATCH_PARENT (int value -1). Probably, PieChart doesn't recognize these constants, and get it as absolute size with negative values.
I found solution:
private int[] getDisplayParams() {
int[] display_params = new int[2];
Display display = getWindowManager().getDefaultDisplay();
if (Build.VERSION.SDK_INT >= 13) {
Point size = new Point();
display.getSize(size);
display_params[0] = size.x;
display_params[1] = size.y;
}
else {
display_params[0] = display.getWidth();
display_params[1] = display.getHeight();
}
return display_params;
}
and use size of screen for determining size of chart:
int[] display_params = getDisplayParams();
Double pie_size = display_params[0]*0.8;
int pie_size_int = pie_size.intValue();
ViewGroup.LayoutParams lp_view = new LinearLayout.LayoutParams(pie_size_int, pie_size_int);
Looks like you are not providing LayoutParams for pie. Try doing this before adding pie to l_layout:
pie.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.FILL_PARENT));
EDIT:
I went back and noticed that the layout is enclosed in a ScrollView but the Scrollview is set to wrap content and the content is set to match parent so it seems like it might be a chicken and egg problem as described here. I believe buttons, etc. have default non-zero values for these whereas plots do not, which might explain why the button works.
As a sanity check, what happens if you specify an absolute size for your plot like this:
LinearLayout.LayoutParams lp_view = new LinearLayout.LayoutParams(100, 100);
You can also try:
plot.setMinimumHeight(100);
plot.setMinimumWidth(100);
Problem resolved by Nick.
You can also try:
plot.setMinimumHeight(100);
plot.setMinimumWidth(100);

ListView with ViewStub in Item Template - expanded controls not showing for last item

I have the following application layout:
Activity with a LinearLayout hosting a Fragment, which hosts a ListView in a LinearLayout. I've templated (not sure it's the right term - I'm coming from WPF) how the ListView is displayed. There's a 3 line part that is shown at all times, plus a ViewStub which is expanded when the item is clicked (and only one item is to be expanded at all times).
Upon the first click on each ListView item, the stub is inflated (works for all items), and then the details and myButton controls are configured. This works for all ListView items - however, for the last of them, details and myButton never show.
On top of that, if another stub is expanded, the last ListView item becomes invisible - instead of it moving down to make space for the item that is currently expanded.
So, if I click on ListView item on position myListView.Items.Count -1, I don't see anything of the expansion. If I click on any other ListView item, the last ListView item disappears.
Here's the fragment layout
<?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:minWidth="25px"
android:minHeight="25px">
<TextView
android:text="#string/active_calls"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/Calls_Header" />
<ListView
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/ActiveCallsList" />
</LinearLayout>
And the layout for each ListView item
<?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">
<TableLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/tableLayout1"
android:shrinkColumns="*"
android:stretchColumns="*">
<TableRow
android:id="#+id/tableRow1">
<TextView
android:text="Caller Name"
android:textAppearance="?android:attr/textAppearanceLarge"
android:id="#+id/CallerName"
android:layout_column="0"
android:layout_span="2" />
</TableRow>
<TableRow
android:id="#+id/tableRow2">
<TextView
android:text="+41 12 345 6789"
android:textAppearance="?android:attr/textAppearanceSmall"
android:id="#+id/CallerNumber"
android:layout_column="0" />
<TextView
android:text="00:01:25"
android:textAppearance="?android:attr/textAppearanceSmall"
android:id="#+id/CallDuration"
android:layout_column="1" />
</TableRow>
<TableRow
android:id="#+id/tableRow3">
<TextView
android:text="Ringing"
android:textAppearance="?android:attr/textAppearanceSmall"
android:id="#+id/CallStatus"
android:layout_column="0" />
</TableRow>
</TableLayout>
<ViewStub
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/viewStub1"
android:inflatedId="#+id/CallDetails"
android:layout="#layout/CallDetails" />
</LinearLayout>
and the part to be expanded
<?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">
<TextView
android:text="Text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/CallDetailsText" />
<Button
android:text="#string/endCall"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/EndCallButton" />
</LinearLayout>
And the ItemClick handler associated to my own implementation of an ArrayAdapter deriving from BaseAdapter.
void calls_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
{
if (inflatedView != null)
inflatedView.Visibility = ViewStates.Gone; // make sure only one item is inflated at all times
var obj = e.Parent.GetItemAtPosition(e.Position);
var listView = sender as ListView;
Model.Call t = Model.Calls.MyCalls[e.Position];
string text = t.CallerName + " " + t.CallState;
Log.Debug("SmartAppMobile", "Call " + text + " clicked");
//Toast.MakeText(this.Activity, text, ToastLength.Short).Show();
ViewStub myStub = e.View.FindViewById<ViewStub>(Resource.Id.viewStub1);
bool previouslyFound = false;
if (myStub != null)
{
inflatedView = myStub.Inflate();
}
else
{
Log.Debug("myapp", "View stub not found for " + text);
inflatedView = e.View.FindViewById<View>(Resource.Id.CallDetails);
inflatedView.Visibility = ViewStates.Visible;
previouslyFound = true;
}
TextView details = inflatedView.FindViewById<TextView>(Resource.Id.CallDetailsText);
if (details != null)
details.Text = "Call details go here... " + t.CallerNumber;
else
Log.Debug("myapp", "Call Details Text field not found for " + text);
Button myButton = inflatedView.FindViewById<Button>(Resource.Id.EndCallButton);
if (myButton != null)
{
if (!previouslyFound)
myButton.Click += (x, y) =>
{
Model.Calls.MyCalls.Remove(t);
//((ArrayAdapter)listView.Adapter).NotifyDataSetChanged();
inflatedView.Visibility = ViewStates.Gone;
};
}
}
Also, if I click on myButton, the application reacts as if I had pressed the back button on the phone - and the ListView item is only removed if it is one that I added in code.
So I guess I have to add the way I call the activity hosting the fragment, and how the ListView items are bound as well:
In my fragment hosting the ListView:
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View fragment = inflater.Inflate(Resource.Layout.CallsFragment, null);
calls = fragment.FindViewById<ListView>(Resource.Id.ActiveCallsList);
calls.Adapter = new ActiveCallsAdapter(this.Activity, Model.Calls.MyCalls);
calls.ItemClick += new EventHandler<AdapterView.ItemClickEventArgs>(calls_ItemClick);
return fragment;
}
and my Data model for the calls
public class Calls
{
private static List<Call> myCalls;
private static object myLock = new object();
public static List<Call> MyCalls
{
get
{
lock (myLock)
{
if (myCalls != null)
return myCalls;
myCalls = new List<Call>();
myCalls.Add(new Call { CallerName = "some name", CallerNumber = "some phone number", CallState = Model.CallState.Init });
myCalls.Add(new Call { CallerName = "some other name", CallerNumber = "another number", CallState = CallState.Held });
return myCalls;
}
}
}
}
And the button I use in my main activity to add a new item to the list and display the list:
Button button = FindViewById<Button> (Resource.Id.myButton);
button.Click += delegate
{
button.Text = string.Format ("{0} clicks!", count++);
Model.Calls.MyCalls.Add(new Model.Call { CallerName = "test " + count, CallerNumber = "" + count, CallState = Model.CallState.Active });
StartActivity(new Intent(this, typeof(CallsActivity)));
};
And of course, CallsActivity
[Activity(Label = "My Activity")]
public class CallsActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.CallsActivity);
// Create your application here
}
}
This is a layout bug. When you inflate the selected call, the call layout gets bigger but its parent doesn't, so the bottom one falls off the edge. That's also why it looks like the bottom one is not expanding--the expanded content is falling off the bottom. You can see this in action if you edit CallDetails.axml to set layout_height for the button to 1dp.
You can fix this layout issue by changing activeCallsList/layout_height (in CallsFragment.axml) to match_parent or fill_parent instead of wrap_content. Instead of reserving just enough space to show the calls when first drawn, activeCallsList will reserve as much space as it can. This makes your call Views behave as expected.
-Max