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

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>

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"

is there any way to put Cardview inside Horizontalscrollview?

I have an horizontalScrollView with some card style view inside.
there are image and textview inside the card style view.
I used to do it by manually creating a new linearlayout and put the image and text inside the view programmally.
the card style code is like below:
LinearLayout layout = new LinearLayout(getActivity()
.getApplicationContext());
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(PixeltoDp(100),PixeltoDp(180));
//params.setMargins(PixeltoDp(10),PixeltoDp(5),PixeltoDp(10), PixeltoDp(5));
params.setMargins(10,5,10,5);
//layout.setLayoutParams(new LayoutParams(280,400));// single container
layout.setLayoutParams(params);
layout.setOrientation(LinearLayout.VERTICAL);
layout.setGravity(Gravity.TOP);
layout.setBackgroundResource(R.drawable.bg_card);
final ImageView imageView = new ImageView(getActivity()
.getApplicationContext());
imageView............
TextView textView = new TextView(getActivity().getApplicationContext());
...............
layout.addView(imageView);
layout.addView(textView);
return layout;
}
but now, I'd like to use android.support.v7.widget.CardView class to make this. so I can easily customize the layout of the cardview in an cardview.xml file in the layout/ folder. and my cardview layout is like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_gravity="center">
<ImageView
android:id="#+id/movie_img"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="0.8"
android:gravity="center_horizontal"
android:cropToPadding="false"
android:src="#drawable/ic_poster" />
<TextView
android:id="#+id/movie_title"
android:layout_width="fill_parent"
android:layout_height="25dp"
android:gravity="center"
android:ellipsize="end"
android:singleLine="true"
android:hint="synaptop"
android:textSize="10sp"
android:textColor="#e0e0e0" />
</LinearLayout>
the problem is how should i use the layout file?
I found the answer myself after all...
just inflat the view
//create ur cardview here and inflate it
final CardView mCardView = new CardView(getActivity());
View.inflate(getActivity(), R.layout.cardview_layout, mCardView);
LinearLayout mCardContainer = (LinearLayout)mCardView.findViewById(R.id.card_view_container);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mCardContainer.setBackgroundResource(R.drawable.ripple_color_borderless);
}
//here u just define whatever u have in ur cardview xml
final ImageView mImageView = (ImageView) mCardView.findViewById(R.id.movie_img);
mImageView.setTag(index);
mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
and the end, add this view to your horizontalScrollView.

How to use adapter for list of images in listview in xamarin C#

I have ListView and I want to add images for it by using adapter:
this is the row axml:
<?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">
<LinearLayout
android:orientation="horizontal"
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="match_parent"
android:layout_height="81.1dp"
android:id="#+id/linearLayout1">
<ImageView
android:layout_width="91.7dp"
android:layout_height="match_parent"
android:id="#+id/imageView5" />
<TextView
android:text="Text"
android:layout_width="184.9dp"
android:layout_height="35.6dp"
android:id="#+id/textView1"
android:gravity="center"
android:textSize="20dp" />
<Button
android:text="Chat"
android:layout_width="62.3dp"
android:layout_height="37.8dp"
android:id="#+id/chat1"
android:layout_marginTop="32dp" />
</LinearLayout>
/////////////////////////////////////////////////////////
and this is the activity for it:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace EJIK_Network
{
[Activity (Label = "FriendsActivity")]
public class FriendsActivity : Activity
{
ListView listview;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
SetContentView (Resource.Layout.Friends);
listview = FindViewById<ListView> (Resource.Id.listView1);
var friends= new [] { "Артём Соколов", "Лидия Чуйкина", "Наташка Чебурашка" , "Даша Митрофанова"};
int [] image = {Resource.Drawable.next,Resource.Drawable.next,
Resource.Drawable.next,Resource.Drawable.next };
listview.Adapter=new ArrayAdapter (this,Resource.Layout.Row1,Resource.Id.textView1, friends);
listview.Adapter=new ArrayAdapter (this,Resource.Layout.Row1,Resource.Id.imageView5, image);
listview.ChoiceMode = ChoiceMode.Single;
}
}
}
///////////////////////////////////////////////////
1-The code run.
2-I have many layouts befor this and every thing good but when I click buttom to show list of friend with thier photo it gives me this error "Unfortunately ListView has stopped".
3-the error is between the list of images and the adapter:
int [] image = {Resource.Drawable.next,Resource.Drawable.next, Resource.Drawable.next,Resource.Drawable.next};
listview.Adapter=new ArrayAdapter (this,Resource.Layout.Row1,Resource.Id.imageView5, image);
4-In my example I have 4 friends:
var friends= new [] { "Артём Соколов", "Лидия Чуйкина", "Наташка Чебурашка" , "Даша Митрофанова"};
5-I know that I use the same photo but doesn't matter .

creating colored stripes in android ListView

I am trying to create thin colored stripes in my app. This is similar to stripes of different color that we see in calendar apps.
Is there any easy way to do it.
What I am doing:
I have a shape defined with width and height and I am trying to apply it to background of my ListView as it will occupy certain part of the ListView.
What is happening:
This is getting applied to the whole background.
What I need:
I am looking for help which can make this as stripes instead of complete background.
or any other way or alternatives for doing the same.
Some code:
rectangle.xml
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:radius="0dp"
/>
<size
android:width="20dp"
android:height="40dp" />
<solid
android:color="#color/opaque_red"
/>
</shape>
list_view_item_cell.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="95dp"
android:divider="?android:dividerVertical"
android:showDividers="middle" >
You can add a View of the width and height equal to that certain part where you want to have the colored background.
For example, if you want to show colored strip of width and height = 20dip. And this colored strip should appear at the left top of List item. Below is the sample
list_view_item_cell.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="95dp"
android:divider="?android:dividerVertical"
android:showDividers="middle" >
<!-- You can use any view here. Set background "rectangle.xml" drawable to this view.-->
<View
android:layout_width="20dip"
android:layout_height="20dip"
android:background="#drawable/rectangle"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
/>
</RelativeLayout>
Yes changing the colour of the shape is possible programatically.
Assume if you have a LayerDrawable set to the view background:
Then this is something which you can do:
LayerDrawable layerList = (LayerDrawable) view.getBackground();
if(layerList != null) {
final RotateDrawable shape = (RotateDrawable) layerList
.findDrawableByLayerId(R.id.header_titled);
final GradientDrawable tildShapeDrawable = (GradientDrawable)shape.getDrawable();
if (tildShapeDrawable != null) {
tildShapeDrawable.setColor(android.R.color.white);
}
}

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