I am writing an app on Android Studio and I am trying to create a custom view with a specific form I need, something like:
Custom View Example
(I used different colors to show how the layout is supposed to go)
Here's the xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="150dp"
android:weightSum="2"
android:background="#android:color/holo_red_dark">
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_weight="1"
android:paddingLeft="15dp"
android:paddingRight="15dp">
<TextView
android:layout_width="match_parent"
android:layout_height="75dp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="#+id/hourLbl"
android:layout_gravity="center"
android:background="#android:color/holo_blue_bright"/>
<TextView
android:layout_width="match_parent"
android:layout_height="75dp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="#+id/minuteLbl"
android:layout_gravity="center"
android:background="#android:color/holo_orange_dark"/>
</LinearLayout>
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="#+id/actionName"
android:layout_weight="1"
android:gravity="center"
android:background="#android:color/darker_gray"/>
</LinearLayout>
The problem comes when I try to add this view to another layout in the app.. It comes as a blank square. I have been trying to look for an answer on how to properly do this, but nothing helps.
This is what I have in the xml of the activity where I want the view (ActionView):
<RelativeLayout 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" tools:context=".HomeActivity">
<...ActionView
android:layout_width="match_parent"
android:layout_height="150dp"
android:id="#+id/firstAction" />
</RelativeLayout>
Here's the ActionView's constructors I have (not sure what to do with them to be honest, just copied them from a tutorial):
public ActionView(Context context) {
super(context);
}
public ActionView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.ActionView,
0, 0);
try {
mHourLbl = a.getString(R.styleable.ActionView_hourLbl);
mMinuteLbl = a.getString(R.styleable.ActionView_minuteLbl);
mActionName = a.getString(R.styleable.ActionView_actionName);
} finally {
a.recycle();
}
}
public ActionView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
I think you're missing the most important part. You're not tying your layout to your ActionView object...
Add:
LayoutInflater.from(context).inflate(R.layout.<xml_of_action_view>, this, true);
inside your ActionView constructor.
Related
I am trying to show a multiline button inside a MaterialButtonToggleGroup but it always shows me ... at the newline
but it works fine outside the MaterialButtonToggleGroup I have tried
using \n and
using <br/> HTML tag with Html.form method
As shown in the image below the first button is outside the MaterialButtonToggleGroup but the second is inside it.
<?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>
</data>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:context=".conversation.ui.conversations.AddNewConversationFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_margin="20dp"
android:background="#drawable/register_field_background"
android:orientation="vertical"
android:padding="10dp">
<ImageView
android:id="#+id/img_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_baseline_close_24"
android:tint="#android:color/darker_gray"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
<com.google.android.material.button.MaterialButton
android:id="#+id/add_anyone"
android:singleLine="false"
android:maxLines="2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="#color/gray100"
android:text="This is Multi Line Text
Line2"
android:textAllCaps="false"
android:textColor="#color/gray700"
app:iconTint="#color/gray700"
/>
<com.google.android.material.button.MaterialButtonToggleGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:layout_marginBottom="10dp"
android:orientation="vertical"
app:checkedButton="#+id/button_add_native"
app:layout_constraintBottom_toTopOf="#+id/tv_select_address"
app:layout_constraintTop_toBottomOf="#+id/textView"
app:selectionRequired="true"
app:singleSelection="true">
<com.google.android.material.button.MaterialButton
android:id="#+id/add_anyone"
android:singleLine="false"
android:maxLines="2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="#color/gray100"
android:text="This is Multi Line Text
Line2"
android:textAllCaps="false"
android:textColor="#color/gray700"
app:iconTint="#color/gray700"
/>
</com.google.android.material.button.MaterialButtonToggleGroup>
<TextView
android:id="#+id/textView"
style="#style/bottomSheetDialogHeader"
android:layout_marginStart="16dp"
android:letterSpacing="0.1"
android:text="#string/add_conversation_dialog_title"
android:textAllCaps="true"
app:layout_constraintBottom_toBottomOf="#+id/img_close"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/img_close" />
<com.google.android.material.button.MaterialButton
android:id="#+id/tv_select_address"
style="#style/LinguisticMainLayoutOrangeButton"
android:paddingBottom="10dp"
android:text="#string/start_chatting"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</RelativeLayout>
</layout>
It is an expected result.You can check the source code below where the multiline is overridden.
You can set it programmatically. Something like:
val button : MaterialButton = findViewById(R.id.add_anyone)
button.maxLines = 2
Source code:
https://github.com/material-components/material-components-android/blob/e944d1b2a6ee5d9d5a338de0c0061f7b02790f77/lib/java/com/google/android/material/button/MaterialButtonToggleGroup.java#L751-L754
private void setupButtonChild(#NonNull MaterialButton buttonChild) {
buttonChild.setMaxLines(1);
buttonChild.setEllipsize(TruncateAt.END);
buttonChild.setCheckable(true);
An alternative trick for future reference:
Provide your own custom class, let's name it CustomMaterialButtonToggleGroup, which extends MaterialButtonToogleGroup
example:
public class CustomMaterialButtonToggleGroup extends MaterialButtonToggleGroup {
public CustomMaterialButtonToggleGroup(#NonNull Context context) {
super(context);
}
public CustomMaterialButtonToggleGroup(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
public CustomMaterialButtonToggleGroup(#NonNull Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
super.addView(child, index, params);
if(child instanceof MaterialButton)
{
((MaterialButton) child).setMaxLines(2);
}
}
This way we enforce via code the child views of the MaterialToggleGroup to implement maxLines!
Final the 2nd weird part is:
Go to your Activity/Fragment in which you define your button...and set it via code!
example:
SampleButton.setText("Hey\nI'm multiline"); // notice the escape character of newline-> \n
Afterwards extract it in the strings.xml as you would do normally!
I am trying to implement horizontal timeline. SO I have written the code to design the horizontal line but I am able to figure out how I will write text on the above and below of the line.
One more thing I don't want to use any other library.
I have try to solve it through Custom view as people here have been suggested but got struck.
timeline_segment.xml
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:weightSum="1"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:padding="3dp"
android:textAlignment="textEnd"
android:text="Top"
android:id="#+id/top_data"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_gravity="center"
android:layout_weight="0.5"
android:background="#color/alphabet_a"
android:layout_width="wrap_content"
android:layout_height="2dp" />
<ImageView
android:background="#drawable/circle1"
android:layout_width="15dp"
android:layout_height="15dp" />
<TextView
android:layout_weight="0.5"
android:layout_gravity="center"
android:background="#color/alphabet_a"
android:layout_width="wrap_content"
android:layout_height="2dp" />
</LinearLayout>
<TextView
android:padding="3dp"
android:gravity="center"
android:text="bottom"
android:id="#+id/bottom_data"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</merge>
timeline_segment.java
public class timeline_segement extends LinearLayout {
View rootView;
TextView upperText;
TextView startLine;
TextView endLine;
ImageView circleView;
TextView bottomText;
public timeline_segement(Context context) {
super(context);
init(context);
}
public timeline_segement(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public timeline_segement(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
rootView=inflate(context, R.layout.timeline_segment, this );
upperText=(TextView) rootView.findViewById(R.id.top_data);
bottomText=(TextView) rootView.findViewById(R.id.bottom_data);
upperText.setText("Top");
bottomText.setText("Bottom");
}
public void setUpperText(String string)
{
upperText.setText(string);
}
public void setBottomText(String string)
{
bottomText.setText(string);
}
}
Decided to answer because the comment box is kinda limiting. This is my comment:
You'll need a custom view to achieve this. You can either composite ready-made views or go full custom
If you choose to composite views, then you start by breaking down that image level by level. At the highest level, its a horizontal layout with 'TimelineCell's (or whatever you choose to call it).
A TimelineCell will basically be a vertical LinearLayout with a right aligned TextView, a View that draws the line and another center aligned TextView.
You can then create these programmatically and add them to a parent horizontal LinearLayout.
If you however choose to go full custom, Youll have to handle measuring, layouting and drawing of all the components including the text above and below the line.
Take a look at this link for a good introduction to custom views on android
I have a layout which contains only a LinearLayour with 3 buttons inside.
I would want this 3 buttons to fill the screen vertically so I used "weigth=1" but I should also want the buttons to be square, that is, that their width is equal to their height.
Any way to do it?
Here's the .xml file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="android.jose.se.Prueba"
android:background="#drawable/bg"
android:gravity="center">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<Button
android:id="#+id/bHet"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#drawable/layer1"
android:onClick="cambiarBoton"/>
<Button
android:id="#+id/bGay"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#drawable/layer2"
android:onClick="cambiarBoton"/>
<Button
android:id="#+id/bLesbi"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#drawable/layer3"
android:onClick="cambiarBoton"/>
</LinearLayout>
</RelativeLayout>
I had similar issue and done it using Google's Percent Relative Layout that helps you manage view aspect ratio.
You can use it like this
<android.support.percent.PercentRelativeLayout
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">
<Button
android:layout_width="match_parent"
app:layout_aspectRatio="100%"/>
</android.support.percent.PercentFrameLayout>
The best way to do this, is to make a new Class called Square button and this class should extend Button. Then in the onMeasure of this class, simply make your heightSpec as WidthSpec.
public class SquareButton extends Button {
public SquareButton(Context context) {
super(context);
}
public SquareButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SquareButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onMeasure(int WidthSpec, int HeightSpec){
int newWidthSpec = HeightSpec ;
super.onMeasure(newWidthSpec, HeightSpec);
}}
Now you can use this SquareButton instead of a normal Button in your xml like this. The value of android:width attribute will be ignored.
<com.example.package.SquareButton
android:height = "0dp"
android:weight = "1"
android:width = "0dp"
/>
I have a custom header bar (something like actionbar).
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#drawable/bg_header">
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/ibSlider"
android:src="#drawable/ic_drawer"
android:background="#color/transparent"
android:layout_marginLeft="#dimen/side_margin"
android:contentDescription="#string/general_content_description"
android:layout_centerVertical="true"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="#string/header_branding"
android:id="#+id/tvAppName"
android:layout_toRightOf="#+id/ibSlider"
android:gravity="center_vertical"
android:layout_marginLeft="#dimen/side_margin"
style="#style/branding_orange"/>
<ProgressBar
android:layout_width="20dp"
android:layout_height="20dp"
android:id="#+id/pbLoading"
android:layout_alignParentRight="true"
android:indeterminate="true"
android:layout_marginRight="#dimen/side_margin"
android:layout_centerVertical="true"/>
</RelativeLayout>
When I'm adding this custom view in my activity, there is padding right that I have no idea comes from where! I have added green background to the view in order to find I'm talking about where.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<view
android:layout_width="match_parent"
android:layout_height="50dp"
android:id="#+id/headerBar"
android:background="#color/green"
class="com.kamalan.widget.HeaderBar"/>
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/headerBar"/>
</RelativeLayout>
And this is the code of my HeaderBar.
public class HeaderBar extends RelativeLayout {
private static final String TAG = "HeaderBar";
private Context mContext;
private ProgressBar progressBar;
private ImageButton ibMenuSlider;
public HeaderBar(Context context) {
super(context);
this.mContext = context;
init();
}
public HeaderBar(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
init();
}
public HeaderBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.mContext = context;
init();
}
private void init() {
LayoutInflater mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
RelativeLayout view = (RelativeLayout) mInflater.inflate(R.layout.widget_headerbar, null);
addView(view);
progressBar = (ProgressBar) view.findViewById(R.id.pbLoading);
ibMenuSlider = (ImageButton) view.findViewById(R.id.ibSlider);
}
...
}
Image 1 shows preview of class header (first xml code) and second image displays when it has been added to my activity. I have no idea that green padding comes from where! any idea would be appreciated. thanks.
Problem was the image that I was using as background of Header. Have no Idea why it works on first image but doesn't work on second one. Maybe activity is messing or Theme has bug, as Bob said in comment.
Anyways, I fixed the problem by not using image :)
For other's reference, I changed xml of header as below and I could fix the problem in this way.
<?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="#dimen/header_bar_height"
android:background="#color/gray">
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/ibSlider"
android:src="#drawable/ic_drawer"
android:background="#color/transparent"
android:layout_marginLeft="#dimen/side_margin"
android:contentDescription="#string/general_content_description"
android:layout_centerVertical="true"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="#string/header_branding"
android:id="#+id/tvAppName"
android:layout_toRightOf="#+id/ibSlider"
android:gravity="center_vertical"
android:layout_marginLeft="#dimen/side_margin"
style="#style/branding_orange"/>
<ProgressBar
android:layout_width="20dp"
android:layout_height="20dp"
android:id="#+id/pbLoading"
android:layout_alignParentRight="true"
android:indeterminate="true"
android:layout_marginRight="#dimen/side_margin"
android:layout_centerVertical="true"/>
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="#color/header_divider"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
I also face same problem but i get success when i try customize Actionbar.I am unable to resolve your problem due to absence of drawable and string resource so please provide zip of this one so that i can see directly .....
I am trying to create a custom button layout. I created an xml file "custom_button.xml" which I then inflate in the "ButtonLanguageSelection" class. In this class I added the onClickListener. I added this class to the "main_activity.xml". It behaves like it should except it won't receive any touch events. Then I copied the code from "custom_button.xml" and added it directly without inflating it, I just added the android:onClick parameter and in this way it worked. I can't find out what would be the problem, the layouts are the same.
Has some of you have similar problems? What could be the problem? I attached the code if it helps someone to find the problem.
Thank you for any help!
custom_button.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/button_language_selection_states"
android:weightSum="1"
android:clickable="true"
>
<TextView
android:id="#+id/textview_select_language"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center"
android:gravity="center_horizontal"
android:paddingTop="30px"
android:layout_weight="0.4"
android:textSize="21sp"
android:textColor="#333333"
/>
<View
android:layout_width="match_parent"
android:background="#drawable/gradient"
android:layout_height="1dp"
android:layout_margin="10px">
</View>
<TextView
android:id="#+id/textview_language"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center"
android:paddingTop="40px"
android:layout_weight="0.6"
android:textSize="28sp"
android:textColor="#ffffff"
/>
</LinearLayout>
ButtonLanguageSelection
public class ButtonLanguageSelection extends LinearLayout
{
private TextView introductoryTextView;
private TextView language;
private final String TAG = "ButtonLanguageSelection";
public ButtonLanguageSelection(Context context) {
super(context);
}
public ButtonLanguageSelection(Context context, AttributeSet attrs)
{
super(context, attrs);
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
layoutInflater.inflate(R.layout.button_language_selection, this);
introductoryTextView = (TextView)findViewById(R.id.textview_select_language);
language = (TextView)findViewById(R.id.textview_language);
this.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "onclick");
}
});
}
public ButtonLanguageSelection(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setIntroductoryTextView(String s)
{
introductoryTextView.setText(s);
}
public void setLanguage(String s)
{
language.setText(s);
}
}
main_activity.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/screen_welcome_bg">
<defaultpackage.ButtonLanguageSelection
android:id="#+id/ButtonLanguageSelection_Slovene"
android:layout_width="341px"
android:layout_height="260px"
android:layout_marginRight="2px"/>
<defaultpackage.ButtonLanguageSelection
android:id="#+id/ButtonLanguageSelection_Italian"
android:layout_width="341px"
android:layout_height="260px"
android:layout_marginRight="2px"/>
<!--<defaultpackage.ButtonLanguageSelection-->
<!--android:id="#+id/ButtonLanguageSelection_English"-->
<!--android:layout_width="341px"-->
<!--android:layout_height="260px" />-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="341px"
android:layout_height="260px"
android:background="#drawable/button_language_selection_states"
android:weightSum="1"
android:clickable="true"
android:onClick="sendMessage"
>
<TextView
android:id="#+id/textview_select_language"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center"
android:gravity="center_horizontal"
android:paddingTop="30px"
android:layout_weight="0.4"
android:textSize="21sp"
android:textColor="#333333"
/>
<View
android:layout_width="match_parent"
android:background="#drawable/gradient"
android:layout_height="1dp"
android:layout_margin="10px">
</View>
<TextView
android:id="#+id/textview_language"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center"
android:paddingTop="40px"
android:layout_weight="0.6"
android:textSize="28sp"
android:textColor="#ffffff"
/>
</LinearLayout>
I think the problem is writing all the init code in only one constructor. Consider making an init function and call it from all the constructors. Also consider setting the onClick events listeners in your activity rather than than the layout constructor itself.