In these days i'm working on an app which is contain preference and i tried to put each preferences into a CardView. I can make a custom preference with old version of preference library but when i want to use CardView, I have to use preference library v7.
Screen Shot
As you can see, I made a preference category with CardView. Firstly I made a preference activity with a CardView which is contain a fragment. then i add my preference files in my ActivityPrefrences
public class ActivityPrefrences extends AppCompatActivity {
private int[] prefResId = {R.xml.app_preferences,R.xml.app_preferences};
private int[] fragmentResId = {R.id.fragmentGeneralSetting,R.id.fragmentRtl};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_preference);
if (savedInstanceState == null) {
for(int i=0;i<prefResId.length;i++){
Fragment fragment = new PreferenceDataFragment();
Bundle bundle = new Bundle();
bundle.putInt("PREFERENCE_KEY", prefResId[i]);
fragment.setArguments(bundle);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(fragmentResId[i],fragment).commit();
}
}
}
Fragment Class:
public class PreferenceDataFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener{
#Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
//getPreferenceManager().setSharedPreferencesName("settings");
//getPreferenceManager().setSharedPreferencesMode(Context.MODE_PRIVATE);
Bundle bundle = this.getArguments();
if (bundle != null) {
int resId = bundle.getInt("PREFERENCE_KEY", R.xml.app_preferences);
addPreferencesFromResource(resId);
}
}
}
activity_preference.xml
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbarThumbVertical="#drawable/scrollbar_thumb"
android:scrollbarTrackVertical="#drawable/scrollbar_track"
android:clipToPadding="false"
android:duplicateParentState="false"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="8dp"
app:cardElevation="6dp"
app:cardCornerRadius="6dp"
app:cardBackgroundColor="#android:color/white">
<FrameLayout
android:id="#+id/fragmentGeneralSetting"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="8dp"
app:cardElevation="6dp"
app:cardCornerRadius="6dp"
app:cardBackgroundColor="#android:color/white">
<FrameLayout
android:id="#+id/fragmentRtl"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.v7.widget.CardView>
</LinearLayout>
</ScrollView>
Finally i added my own Custom preference in preference.xml but when i loading this activity on phone, i miss a part of view on screen. as you can see on above image, Gray area is holder and white are is a part of custom preference view.
Now i can't understand why my custom view not fitting in whole area of holder? and i can't use setSummary and setTitle in class, Actually "title" and "summary" not applied on TextViews, I don't know why?
This is my custom preference class
public class RTLCheckBoxPreference extends Preference {
private OnPreferenceClickListener prefListener;
private boolean currentValue = false;
public RTLCheckBoxPreference(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RTLCheckBoxPreference(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
setWidgetLayoutResource(R.layout.prefrence_checkbox);
}
#Override
protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
super.onSetInitialValue(restorePersistedValue, defaultValue);
currentValue = restorePersistedValue ? getPersistedBoolean(false):(Boolean) defaultValue;
}
#Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
holder.itemView.setClickable(false);
holder.itemView.setPadding(0,0,0,0);
RecyclerView.LayoutParams param = (RecyclerView.LayoutParams) holder.itemView.getLayoutParams();
param.setMargins(0,0,0,0);
holder.itemView.setLayoutParams(param);
}
}
This is my custom layout for my prefrence.
<FrameLayout 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="wrap_content"
android:orientation="vertical"
android:minHeight="?attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:paddingRight="?android:attr/scrollbarSize"
android:background="?attr/selectableItemBackground"
android:focusable="true" >
<com.bvapp.widget.HoloButton.HoloButton
android:id="#+id/btnCheckBoxPrefrence"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dip"
android:layout_marginRight="15dip"
android:layout_marginTop="6dip">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:background="#drawable/check_box_outline_blank"
android:id="#+id/imgCheckBoxPrefrence"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"/>
<TextView android:id="#android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="#color/text_main"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:gravity="right"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:textSize="#dimen/font_norm_size"/>
<TextView android:id="#android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#android:id/title"
android:layout_alignRight="#android:id/title"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="#color/text_aux"
android:maxLines="4"
android:gravity="right"
android:textSize="#dimen/font_aux_norm_size"/>
</RelativeLayout>
</FrameLayout>
I tried a lot to find my answers, even i tried to set padding and margin to "0" but it's not working. How should I fit my own custom preference in holder and use "title" and "summary" in my custom preferences?
Related
I have a RecyclerView with other widgets in this type of layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="in.joey.joseph.aapnidukan.activities.CheckOutActivity">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/colorPrimary"
android:minHeight="?attr/actionBarSize">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/backIV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="#drawable/back_image"
android:padding="16dp"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="CheckOut"
android:textSize="18sp"
android:fontFamily="casual"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:gravity="center"
android:textColor="#android:color/white"/>
</RelativeLayout>
</android.support.v7.widget.Toolbar>
<RelativeLayout
android:id="#+id/nonEmptyState"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/toolbar"
android:visibility="visible">
<in.joey.joseph.aapnidukan.utils.EmptyRecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/checkOutRV"
/>
<RelativeLayout
android:id="#+id/cartTotalLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/checkOutRV"
android:layout_alignParentRight="true"
android:gravity="right"
android:layout_marginRight="20dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="right"
android:layout_marginRight="20dp"
android:padding="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Total: "
android:textSize="18sp"
android:textColor="#android:color/black"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="₹"
android:textSize="18sp"
android:textColor="#android:color/black"
android:layout_marginLeft="10dp"/>
<TextView
android:id="#+id/totalPriceTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="8999"
android:textSize="18sp"
android:textColor="#color/colorPrimary"
android:layout_marginLeft="5dp"/>
</LinearLayout>
</RelativeLayout>
<Button
android:id="#+id/billingBtn"
android:layout_width="match_parent"
android:layout_height="70dp"
android:background="#color/colorAccent"
android:text="Proceed to Billing and Address"
android:textColor="#android:color/white"
android:textAllCaps="false"
android:textSize="20sp"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
<TextView
android:id="#+id/emptyState"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Add Items to Cart Before CheckOut"
android:textSize="18sp"
android:fontFamily="casual"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:gravity="center"
android:textColor="#android:color/black"
android:visibility="visible"/>
I have created a custom RecyclerView to handle empty states but it works fine for only the RecyclerView. The other views like the button are still visible when the list is empty. I have tried to hide it in my custom RecyclerView class like this:
private void checkNotEmpty(){
if (nonEmptyView != null && getAdapter() != null){
boolean nonEmptyViewVisible = getAdapter().getItemCount() > 0;
nonEmptyView.setVisibility(nonEmptyViewVisible ? VISIBLE : GONE);
setVisibility(nonEmptyViewVisible ? GONE : VISIBLE);
}
}
Here's the full class code for the RecyclerView:
public class EmptyRecyclerView extends RecyclerView {
private View emptyView, nonEmptyView;
public EmptyRecyclerView(Context context) {
super(context);
}
public EmptyRecyclerView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
public EmptyRecyclerView(Context context, #Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
private final AdapterDataObserver dataObserver = new AdapterDataObserver() {
#Override
public void onChanged() {
checkEmpty();
}
#Override
public void onItemRangeInserted(int positionStart, int itemCount) {
checkEmpty();
}
#Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
checkEmpty();
}
};
private void checkEmpty() {
if (emptyView != null && getAdapter() != null){
boolean emptyViewVisible = getAdapter().getItemCount() == 0;
emptyView.setVisibility(emptyViewVisible ? VISIBLE : GONE);
setVisibility(emptyViewVisible ? GONE : VISIBLE);
}
}
private void checkNotEmpty(){
if (nonEmptyView != null && getAdapter() != null){
boolean nonEmptyViewVisible = getAdapter().getItemCount() > 0;
nonEmptyView.setVisibility(nonEmptyViewVisible ? VISIBLE : GONE);
setVisibility(nonEmptyViewVisible ? GONE : VISIBLE);
}
}
public void setButtonVisibility(Button button){ // to toggle the button visibility
if (getAdapter().getItemCount() > 0){
button.setVisibility(View.VISIBLE);
} else {
button.setVisibility(GONE);
}
}
#Override
public void setAdapter(Adapter adapter) {
Adapter oldAdapter = getAdapter();
if (oldAdapter != null){
oldAdapter.unregisterAdapterDataObserver(dataObserver);
}
super.setAdapter(adapter);
if (adapter != null){
adapter.registerAdapterDataObserver(dataObserver);
}
checkEmpty();
}
public void setEmptyView(View view){
this.emptyView = view;
checkEmpty();
}
public void setNonEmptyView(View view2){
this.nonEmptyView = view2;
checkNotEmpty();
}
}
And in my activity, I have tried this:
init();
checkOutRV.setEmptyView(emptyState);
checkOutRV.setNonEmptyView(nonEmptyState);
private void init() {
nonEmptyState = findViewById(R.id.nonEmptyState);
emptyState = findViewById(R.id.emptyState);
checkOutRV = findViewById(R.id.checkOutRV);
checkOutRV.setHasFixedSize(true);
checkOutRV.setLayoutManager(new LinearLayoutManager(this));
}
The list has no data right now as I have not made my API call yet, but still, the emptyStateTextView and the buttons are still visible. How do I fix this?
By default keep your layout INVISIBLE and show a layout that shows that the Recyclerview has no data or something, and then when you make your API calls and receive the data then hide the layout which show that the recyclerview in empty and set your data layout view to VISIBLE which you want to show.
UPDATED ANSWER
You need to register Data observer to listen to data changes from sync adapter.
mRecyclerViewAdapter.registerAdapterDataObserver(myObserver);
RecyclerView.AdapterDataObserver are a result of which notify methods you call. So for instance if you call notifyItemInserted() after you add an item to your adapter then onItemRangeInserted() will get called
A more detailed example
protected void setupRecyclerView() {
mAdapter = new MyAdapter(mItemList);
mAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
#Override
public void onChanged() {
super.onChanged();
checkAdapterIsEmpty();
}
});
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setAdapter(mAdapter);
checkAdapterIsEmpty();
}
Also don't forget to unregister the observer.
In the checkNonEmpty() method you have called getAdapter() which returns null as you have not used setAdapter() on recycler view .
Create an adapter for your recycler view and initialise it with an empty list , then setAdapter() on your view.
Then you can use these statements
checkOutRV.setEmptyView(emptyState);
checkOutRV.setNonEmptyView(nonEmptyState);
Hope it helps !!
Try this:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout >
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
>
...
</android.support.v7.widget.Toolbar>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/toolbar"
android:visibility="visible">
<RelativeLayout
android:id="#+id/nonEmptyState"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Existing layout like recyclerview, button -->
</RelativeLayout>
<RelativeLayout
android:id="#+id/emptyStateLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/emptyState"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:fontFamily="casual"
android:gravity="center"
android:text="Add Items to Cart Before CheckOut"
android:textColor="#android:color/black"
android:textSize="18sp"
android:visibility="visible"/>
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
Just set emptyStateLayout VISIBLE when RecyclerView is empty, otherwise GONE
I created a custom dialog preference in my Android application, but I can not figure out how to get the dialog which is displayed to span the complete width of the display.
image of dialog with too much space on left and right side
I found many proposed solutions to get a normal Dialog in full screen mode
Android get full width for custom Dialog
https://gist.github.com/koocbor/88db64192638bff09aa4
http://blog.jimbaca.com/force-dialog-to-take-up-full-screen-width/
But setting the attributes via getWindow does not work:
#Override
public Dialog getDialog() {
Dialog dialog = super.getDialog();
dialog.getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
// or
// dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
return dialog;
}
And applying a full screen theme to my dialogs root element didn't do the job neither:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
[...]
android:theme="#style/FullscreenTheme">
Moreover I'm not able to access the onCreate Method (at least I don't know how) of the Dialog, to set the style there.
Did anyone had the same problem and figured out a solution for this very specific issue?
My layout:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:orientation="vertical"
android:padding="0dp"
android:paddingTop="#dimen/preferences_dialog_def_padding"
android:paddingBottom="#dimen/preferences_dialog_def_padding">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginTop="-2dp"
android:background="#color/expandable_preference_divider"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="#dimen/preferences_expandable_margin_top_bottom"
android:layout_marginTop="#dimen/preferences_expandable_margin_top_bottom">
<RelativeLayout
android:id="#+id/icon_wrapper_choose"
android:layout_width="#dimen/preferences_expandable_icon_wrapper_size"
android:layout_height="#dimen/preferences_expandable_icon_wrapper_size"
android:layout_marginBottom="0dp"
android:layout_marginEnd="#dimen/preference_expandable_icon_margin"
android:layout_marginStart="#dimen/preference_expandable_icon_margin"
android:layout_marginTop="0dp"
android:gravity="center">
<ImageView
android:layout_width="#dimen/preferences_expandable_icon_size"
android:layout_height="#dimen/preferences_expandable_icon_size"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:cropToPadding="true"
android:scaleType="centerCrop"
android:src="#drawable/ic_settings_white_36dp"/>
</RelativeLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toEndOf="#+id/icon_wrapper_choose"
android:paddingBottom="#dimen/preferences_expandable_text_padding_top_bottom"
android:paddingTop="#dimen/preferences_expandable_text_padding_top_bottom"
android:text="#string/pref_wheel_circumference_choose"
android:textColor="#color/colorAccent"
android:textSize="#dimen/text_size_medium"
android:textStyle="bold"/>
</RelativeLayout>
<TextView
android:layout_width="match_parent"
android:layout_marginEnd="#dimen/preference_expandable_icon_margin"
android:layout_marginStart="#dimen/preference_expandable_icon_margin"
android:layout_height="wrap_content"
android:text="#string/etrto_hint"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeight"
android:orientation="horizontal"
android:paddingBottom="20dp"
android:paddingEnd="?android:attr/scrollbarSize"
android:layout_marginStart="#dimen/preference_expandable_icon_margin"
android:weightSum="3"
>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#string/etrto"/>
<Spinner
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingBottom="20dp"
android:paddingEnd="?android:attr/scrollbarSize"
android:layout_marginStart="#dimen/preference_expandable_icon_margin"
android:weightSum="3"
>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#string/manufacturer"/>
<Spinner
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"/>
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginTop="-2dp"
android:background="#color/expandable_preference_divider"/>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/preference_category_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:orientation="vertical"
android:padding="5dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="#dimen/preferences_expandable_margin_top_bottom"
android:layout_marginTop="#dimen/preferences_expandable_margin_top_bottom">
<RelativeLayout
android:id="#+id/icon_wrapper_manual"
android:layout_width="#dimen/preferences_expandable_icon_wrapper_size"
android:layout_height="#dimen/preferences_expandable_icon_wrapper_size"
android:layout_marginBottom="0dp"
android:layout_marginEnd="#dimen/preference_expandable_icon_margin"
android:layout_marginStart="#dimen/preference_expandable_icon_margin"
android:layout_marginTop="0dp"
android:gravity="center">
<ImageView
android:id="#+android:id/icon"
android:layout_width="#dimen/preferences_expandable_icon_size"
android:layout_height="#dimen/preferences_expandable_icon_size"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:cropToPadding="true"
android:scaleType="centerCrop"
android:src="#drawable/ic_edit_white_36dp"/>
</RelativeLayout>
<TextView
android:id="#+android:id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toEndOf="#+id/icon_wrapper_manual"
android:paddingBottom="#dimen/preferences_expandable_text_padding_top_bottom"
android:paddingTop="#dimen/preferences_expandable_text_padding_top_bottom"
android:text="#string/pref_wheel_circumference_manually"
android:textColor="#color/colorAccent"
android:textSize="#dimen/text_size_medium"
android:textStyle="bold"/>
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeight"
android:orientation="horizontal"
android:paddingBottom="20dp"
android:paddingEnd="?android:attr/scrollbarSize"
android:layout_marginStart="#dimen/preference_expandable_icon_margin"
android:weightSum="2.5"
>
<EditText
android:id="#+id/pref_dialog_wheelcircumference_et"
android:layout_width="0dp"
android:layout_weight="2"
android:layout_height="wrap_content"
android:textAlignment="textEnd"
android:textColor="#color/colorFont"
android:textSize="#dimen/text_size_small"
android:inputType="number"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:textAlignment="center"
android:text="#string/wheel_circumference_unit"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
My custom preference class
public class WheelCircumferencePreference extends android.preference.DialogPreference {
private static String TAG = "CustomSwitchPreference";
private int mWheelCircumference;
public static int WHEEL_CIRCUMFERENCE_DEFAULT = 2125;
private int mDialogLayoutResId = R.layout.pref_dialog_wheelcircumference;
public WheelCircumferencePreference(Context context) {
this(context, null);
}
public WheelCircumferencePreference(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.dialogPreferenceStyle);
}
public WheelCircumferencePreference(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
setLayoutResource(R.layout.custom_preference);
setDialogLayoutResource(mDialogLayoutResId);
setPositiveButtonText(getContext().getString(R.string.dialog_save));
setNegativeButtonText(getContext().getString(R.string.dialog_cancel));
}
#Override
protected Object onGetDefaultValue(TypedArray a, int index) {
// Default value from attribute. Fallback value is set to WHEEL_CIRCUMFERENCE_DEFAULT.
return a.getInteger(index, WHEEL_CIRCUMFERENCE_DEFAULT);
}
#Override
protected void onSetInitialValue(boolean restorePersistedValue,
Object defaultValue) {
would load value from shared preferences
if (restorePersistedValue) {
mWheelCircumference = getPersistedInt(WHEEL_CIRCUMFERENCE_DEFAULT);
} else {
mWheelCircumference = (Integer) defaultValue;
persistInt(mWheelCircumference);
}
}
private EditText mWheelCircumferenceEt;
#Override
protected void onBindDialogView(View view) {
mWheelCircumferenceEt = view.findViewById(R.id.pref_dialog_wheelcircumference_et);
if (mWheelCircumferenceEt == null) {
throw new IllegalStateException("preference dialog view must contain" +
" a EditText with id 'pref_dialog_wheelcircumference_et'");
}
mWheelCircumferenceEt.setText(Integer.toString(mWheelCircumference));
super.onBindDialogView(view);
}
#Override
public Dialog getDialog() {
//Dialog dialog = super.getDialog();
// WindowManager.LayoutParams p = getDialog().getWindow().getAttributes();
//p.height = LinearLayout.LayoutParams.WRAP_CONTENT;
//dialog.getWindow().setAttributes(p);
return dialog;
}
#Override
protected void onDialogClosed(boolean positiveResult) {
if (positiveResult) {
String circumferenceText = mWheelCircumferenceEt.getText().toString();
try {
mWheelCircumference = Integer.parseInt(circumferenceText);
} catch (Exception e) {
NLog.e(TAG, "onDialogClosed - ", e);
mWheelCircumference = WheelCircumferencePreference.WHEEL_CIRCUMFERENCE_DEFAULT;
}
persistInt(mWheelCircumference);
}
}
Edit:
Actually I only want the dialog to span over the full width of the screen, not the height. If I would use a additional PreferenceFragment (as the DialogPreference is already embedded in a PreferenceFragment ) the "Dialog" (aka Fragment) would take the complete width and height (i guess).
I already implemented a solution without a DialogPrefrence, that works but is not exactly elegant
using just a normal EditTextPreference
adding an onPreferenceClickListener to this preference in my SettingsFragment Code
the ClickListener displays a simple Dialog
Example:
Preference preference = findPreference(EXAMPLE_PREFRENCE);
if (preference != null) {
preference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
// showDialog();
}
});
But as I have a lot of preferences which will display dialogs the code for the dialog creation and display bloads the SettingsFragment and makes it nearly unreadable. Therefore I thought it would be a nice solution to put the responsibility of displaying the dialog and handling the preference values to the Preference and the XML layout.
Unfortunately I got stuck with the "full width issue" mentioned above.
Note: fixed the code of getDialog as I tested different versions (also in combination with the xml theme set)
Finally I did find a solution for this problem:
Fetch the AlertDialog of the Preference in showDialog method
#Override
protected void showDialog(Bundle state) {
super.showDialog(state);
CustomDialogPreference.makeDialogFullScreen((AlertDialog) getDialog());
}
make it span the complete width:
public static void makeDialogFullScreen(AlertDialog d) {
NLog.d(TAG, "makeDialogFullScreen enter ");
if (d != null) {
ViewGroup.LayoutParams params = d.getWindow().getAttributes();
if (params != null) {
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
d.getWindow().setAttributes((android.view.WindowManager.LayoutParams) params);
}
}
}
Try this in the onResume of your dialog.
// Store access variables for window and blank point
Window window = getDialog().getWindow();
Point size = new Point();
// Store dimensions of the screen in `size`
Display display = window.getWindowManager().getDefaultDisplay();
display.getSize(size);
// Set the width of the dialog proportional to 75% of the screen width and height
window.setLayout((int) (size.x * 0.75), (int) (size.y * 0.75));
window.setGravity(Gravity.CENTER);
// Call super onResume after sizing
Adjust accordingly for 100%. It works great for a dialogFragment. Haven't tried it for your case though.
Wait, you're not looking for the bog-standard 'Pref settings user options appear in a dialog' thing are you? That's almost definitely already done in AndroidStudio's add activity...> Settings Activity in boiler plate, check it out, or look for sample settings apps
Anyway, I do actually have a fullscreen dialog in my app, although it purposely doesn't fill the full screen, and I actually use an activity with some fragments now instead.
Personally I think this is what your problem is, I remember having this exact issue when I first needed a dialog like this. You should just use activities and have up navigation (if you want a full screen "popup" type thing you could use the Navigation pattern that makes the home/up button an 'X' instead of a '<');
Or anything else, you don't need to have a dialog explicitly, and if you do then extend activity or dialog and get what you want.
Here's my activity stuff in case it's any use
my theme:
<style name="AppTheme.FullScreenDialog"
parent="#style/Theme.AppCompat.Light.Dialog">
<item name="windowActionBar">true</item>
<item name="windowNoTitle">true</item>
</style>
my onCreate gist:
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
...
requestWindowFeature(Window.FEATURE_NO_TITLE);
...
super.onCreate(savedInstanceState);
setContentView(getConcreteContentView());
ButterKnife.bind(this);
setUpUIComponents();
...
}
my general layout gist:
<CoordinatorLayout>
<AppBarLayout>
<android.support.v7.widget.Toolbar/>
</android.support.design.widget.AppBarLayout>
<RelativeLayout
android:id="#+id/container_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:paddingTop="6dp"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<RelativeLayout
android:id="#+id/container_recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/tv_security_word"
android:paddingEnd="18dp"
android:paddingStart="18dp" />
<RelativeLayout
android:id="#+id/container_security"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_below="#+id/container_recycler"
android:minHeight="150dp"
android:paddingEnd="18dp"
android:paddingStart="18dp"
android:visibility="visible" />
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/security_container"
android:layout_centerHorizontal="true"
android:contentDescription="#string/app_name"
android:minHeight="50dp"
android:scaleType="centerInside" />
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>
Bon Chance!
I have simple Relative layout with one button.
And Im using this layout multiple times using include in Main Layout.
Its possible to write one method (using ButterKnife or not) for all this buttons using listener(this) and not creating multiple listeners like this ---->
(relativeLayout1.findViewById(R.id.currencyButton)).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(ForeignExchangeActivity.this, "Euro", Toast.LENGTH_SHORT).show();
}
});
(relativeLayout2.findViewById(R.id.currencyButton)).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(ForeignExchangeActivity.this, "GBP", Toast.LENGTH_SHORT).show();
}
});
Single item layaout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorBackgroundSeekbar">
<TextView
android:id="#+id/currencyTitle"
android:text="EUR - PLN"
android:padding="5dp"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="#FFFFFF"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:background="#color/colorButtonHiglight"/>
<TextView
android:id="#+id/currencyDate"
android:layout_below="#id/currencyTitle"
android:text="24-01-2015"
android:textStyle="bold"
android:layout_marginTop="12dp"
android:gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/currencyValue"
android:layout_below="#+id/currencyDate"
android:text="4.4567"
android:layout_marginTop="12dp"
android:textColor="#FFFFFF"
android:textStyle="bold"
android:textSize="25sp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:layout_centerHorizontal="true"
android:gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/colorCalculatorActivity"/>
<TextView
android:text="Inna data"
android:textAllCaps="false"
android:layout_marginTop="10dp"
android:id="#+id/currencyButton"
android:textSize="12sp"
android:padding="5dp"
android:gravity="center"
android:layout_below="#id/currencyValue"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:background="#drawable/button_rounder_corners"
android:layout_alignLeft="#+id/currencyValue"
android:layout_alignRight="#+id/currencyValue"
android:onClick="onClickDataButton"
/>
<View
android:layout_marginTop="10dp"
android:layout_below="#id/currencyButton"
android:layout_width="match_parent"
android:layout_height="1dp"/>
</RelativeLayout>
Example Inlcude
<LinearLayout
android:layout_width="match_parent"
android:weightSum="2"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="#dimen/activity_horizontal_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin">
<include
android:id="#+id/currency1"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
layout="#layout/single_item_foreign_exchange"/>
<View
android:layout_width="10dp"
android:layout_height="match_parent"/>
<include
android:id="#+id/currency2"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
layout="#layout/single_item_foreign_exchange"/>
</LinearLayout>
Binded inlcude layaouts
#Bind(R.id.currency1) RelativeLayout relativeLayout1;
#Bind(R.id.currency2) RelativeLayout relativeLayout2;
SOLVED
Added onClick method to my RelativeLayaout. Then created something like this
public void onClickDataButton(View view){
if (view == buttonEuro){
Toast.makeText(ForeignExchangeActivity.this, "Euro", Toast.LENGTH_SHORT).show();
} else if ( view == buttonGBP){
Toast.makeText(ForeignExchangeActivity.this, "GBP", Toast.LENGTH_SHORT).show();
}
}
And my button looks like
buttonEuro = (TextView) relativeLayout1.findViewById(R.id.currencyButton);
buttonGBP = (TextView) relativeLayout2.findViewById(R.id.currencyButton
);
so the same button id but finded in diffrent layaouts.
EDIT: Example for your case added: Buttons with same ID in different layouts.
1) You could iterate over an Array of Buttons.
2) Or: Create a custom Button-Class which holds anything custom you need (i.e. field for currency etc) and use that in your Layout.
Kind of Pseudocode (not tested):
class CurrencyButton extends android.widget.Button {
string currency;
public void init(Context ctx, String currency) {
this.currency = currency;
this.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(ctx, this.currency, Toast.LENGTH_SHORT).show();
}
});
}
public void doSomeOtherFancyCurrencyLogicHere() {
....
}
}
This can be used in your Layout files: (Pseudo)
<your.package.CurrencyButton
id="#+id/currency_button_eur"
LayoutParams etc />
<your.package.CurrencyButton
id="#+id/currency_button_gbp"
LayoutParams etc />
<!-- EDIT: as in your example with layouts in single_item_foreign_exchange -->
<your.package.CurrencyButton
id="#+id/currency_button"
LayoutParams etc />
If you use Butterknife
#InjectView(R.id.currency_button_eur)
your.package.CurrencyButton buttonEUR;
#InjectView(R.id.currency_button_gbp)
your.package.CurrencyButton buttonGBP;
// ... initialize them somewhere
buttonEUR.init(this, "EUR");
buttonGPB.init(this, "GBP");
// EDIT: as in your example with layouts
((your.package.CurrencyButton) relativeLayout1.findViewById(R.id.currencyButton)).init(this, "EUR");
((your.package.CurrencyButton) relativeLayout2.findViewById(R.id.currencyButton)).init(this, "GBP");
Actually you could go even further and extend this class for each currency, but this should do it in the first place.
Ok, I've seen you have SOLVED your question. But since I was already working on this answer, I'll add it here anyway :P
class CurrencyLayout extends FrameLayout {
String currency;
// Constructors that calls init after super(...);
public void init(Context ctx, AtributeSet attrs) {
View includedLayout = LayoutInflater.fromContext(ctx).inflate(R.layout.single_item_foreign_exchange, this, false);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.CurrencyLayout,
0, 0);
try {
final String currency = a.getString(R.styleable.CurrencyLayout_currencyName);
} finally {
a.recycle();
}
includedLayout.findViewById(R.id.currencyName).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(ctx, this.currency, Toast.LENGTH_SHORT).show();
}
});
}
this.addView(includedLayout);
}
inside res/values/attrs.xml add something like this:
<resources>
<declare-styleable name="CurrencyLayout">
<attr name="currencyName" format="string" />
</declare-styleable>
</resources>
And inside your Activity layout:
<LinearLayout
android:layout_width="match_parent"
android:weightSum="2"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="#dimen/activity_horizontal_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin">
<your_package.CurrencyLayout
android:id="#+id/currency1"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
custom:currencyName="GBP"/>
<View
android:layout_width="10dp"
android:layout_height="match_parent"/>
<your_package.CurrencyLayout
android:id="#+id/currency2"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
custom:currencyName="EUR"/>
</LinearLayout>
I hope this helps you anyway :D
More information on custom views and attributes
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.
I have a layout like this
main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mainLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ScrollView
android:id="#+id/scrollView1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:alignParentTop ="true"
android:scrollbars="none" >
<LinearLayout
android:id="#+id/linearLayout4"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<Button
android:id="#+id/btnLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="10dip"
android:layout_marginTop="10dip"
android:text="Login" />
<RelativeLayout
android:id="#+id/layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="10dip"
android:layout_marginTop="10dip"
android:visibility="gone" >
<Button
android:id="#+id/btnEditUser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/txtLoggedInfo"
android:layout_centerInParent="true"
android:layout_marginTop="5dip"
android:text="Edit User" />
</RelativeLayout>
</LinearLayout>
</ScrollView>
</RelativeLayout>
and my custom view is
public class MyView extends RelativeLayout {
private Context context = null;
private TextView txtLoggedInfo;
private View contentView = null;
public MyView(Context context) {
super(context);
this.context = context;
getLayout();
}
private void getLayout() {
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Service.LAYOUT_INFLATER_SERVICE);
contentView = layoutInflater.inflate(R.layout.main, null);
this.addView(contentView);
//......
if (bool ) {
((Button)findViewById(R.id.btnLogin)).setVisibility(View.GONE);
((RelativeLayout) findViewById(R.id.layout)).setVisibility(View.VISIBLE);
} else {
((Button)findViewById(R.id.btnLogin)).setVisibility(View.VISIBLE);
((RelativeLayout) findViewById(R.id.layout))
.setVisibility(View.GONE);
}
}
}
I want to Start a new activity when click on Login button and go back to MyView after login.I used
RelativeLayout.LayoutParams layputParams = new Relative.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
this.addContentView(new MyView(this), layputParams);
inside the activity for go back to the activity. When doing like this, the view visibility does not change.What is the problem here and how can i fix that problem?
Thanks
i would strongly suggest you to to do this
#Override
public void onWindowFocusChanged(boolean hasFocus) {
if (bool ) {
((Button)findViewById(R.id.btnLogin)).setVisibility(View.GONE);
((RelativeLayout) findViewById(R.id.layout)).setVisibility(View.VISIBLE);
} else {
((Button)findViewById(R.id.btnLogin)).setVisibility(View.VISIBLE);
((RelativeLayout) findViewById(R.id.layout))
.setVisibility(View.GONE);
}
super.onWindowFocusChanged(hasFocus);
}
that means that if windows focus has changed, all the content has been created. In your previous code, there is a possibility that condition did not work because all the content has not been loaded yet.