I have a 9 patch drawable which I want to use as a background on a view. I want the view to show a ripple effect that follows the outline of a 9 patch when the view is clicked. Here's my activity, layout, and drawable code.
MainActivity.kt:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val click = findViewById<ConstraintLayout>(R.id.container)
click.setOnClickListener { Toast.makeText(this, "Clicked", Toast.LENGTH_SHORT).show() }
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.antonc.testapp.MainActivity">
<android.support.constraint.ConstraintLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="8dp"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:paddingTop="16dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:background="#drawable/tooltip_background"
android:backgroundTint="#2681d8"
tools:layout_editor_absoluteX="8dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello test test !!!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintHorizontal_bias="0.0"
/>
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>
tooltip_background.xml:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#33000000">
<item android:drawable="#drawable/tooltip_left_top"/>
<item android:id="#android:id/mask" android:drawable="#drawable/tooltip_left_top"/>
</ripple>
tooltip_left_top.9.png:
But when I click on it, the ripple drawable is very distorted, as if it's stretched to the view size without observing the stretch rules of 9 patch. How should I configure the ripple to make it be the same as the background?:
Update: I have reworked the answer to refine the issue. The following has been edited to reflect the changes.
TL;DR Do not use android:backgroundTint for ripple backgrounds based on nine-patch drawables at least for API 28. Set the tint in code.
This issue has something to do with the background tint. I will explain how I came to this conclusion by referring to the following video.
I will refer to the bubbles as view1 through view4 from top to bottom. I changed from your nine-patch to better see the patches since your nine-patch was mostly black.
View1, when click, shows the appropriate ripple effect. It has a ripple background but no background tint.
View2 is what you are seeing with your background - it is just messed up. This view has a background tint set in XML.
The height of view3 has been forced to the height of view1 to see how the ripple looks. As you can see, the ripple looks right for the height. It is the non-ripple background image that is distorted.
View4 is the same as view2 except that it has the tint for RippleDrawable added programmatically. As you can see, this view looks and behaves as it should.
Bottom line? Don't set the background tint for a nine-patch in XML. Set it in code. Is this a bug? Maybe.
Here is the support code for the video above.
activity_main.xml
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFFFF"
android:fillViewport="true"
android:orientation="vertical"
android:padding="16dp"
tools:context=".MainActivity">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:context=".MainActivity">
<ImageView
android:id="#+id/imageView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="#drawable/bubble_background"
android:clickable="true" />
<ImageView
android:id="#+id/imageView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="#drawable/bubble_background"
android:backgroundTint="#color/background_tint"
android:clickable="true" />
<ImageView
android:id="#+id/imageView3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="#drawable/bubble_background"
android:backgroundTint="#color/background_tint"
android:clickable="true" />
<ImageView
android:id="#+id/imageView4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="#drawable/bubble_background"
android:clickable="true" />
</LinearLayout>
</ScrollView>
bubble_background.xml
<ripple
android:color="#33000000">
<item android:drawable="#drawable/ninepatch_bubble">
</item>
</ripple>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private LinearLayout mLayout;
private ImageView mImageView1;
private ImageView mImageView2;
private ImageView mImageView3;
private ImageView mImageView4;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLayout = findViewById(R.id.layout);
mImageView1 = findViewById(R.id.imageView1);
mImageView2 = findViewById(R.id.imageView2);
mImageView3 = findViewById(R.id.imageView3);
mImageView4 = findViewById(R.id.imageView4);
int bgTint = getResources().getColor(R.color.background_tint);
RippleDrawable rippleDrawable =(RippleDrawable) mImageView4.getBackground();
rippleDrawable.getDrawable(0).setTint(bgTint);
mImageView4.setBackground(rippleDrawable);
mLayout.post(new Runnable() {
#Override
public void run() {
mImageView3.getLayoutParams().height = mImageView1.getMeasuredHeight();
mLayout.requestLayout();
}
});
}
}
colors.xml
These were added to colors.xml:
<color name="background_tint">#2681d8</color>
<color name="ripple_tint">#33000000</color>
ninepatch_bubble.9.png
Try to use ripple effect like this:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/White">
<item android:drawable="#drawable/tooltip_left_top" />
<item android:id="#android:id/mask">
<color android:color="#color/your_tooltip_color_code" />
</item>
</ripple>
Update here if it works.
Related
Hey I am working in custom view in android. Inside my custom view, I am using view-pager and I want to view pager to be corner radius be 16dp. I did this successfully but the problem is there custom view corner showing some kind of translucent color. So how can i avoid this?. If I did in custom view to be rounded it's working fine, but I don't want to be whole view because inside custom view I have so many testView, images etc. I only want to do in view-pager. I am attaching image how it looks like. I marked in all corner in image. Can someone please guide me.
GalleryView.kt
class GalleryView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
private var binding: GalleryViewBinding = GalleryViewBinding.inflate(LayoutInflater.from(context), this, true)
init{
//.. Initialise code logic.
}
}
gallery.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/galleryContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/galleryPager"
android:layout_width="match_parent"
android:layout_height="224dp"
android:layout_marginBottom="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
// Textview, images etc
</androidx.constraintlayout.widget.ConstraintLayout>
I am not adding code for viewpager adapter, instead adding layout and how can I achieved rounded corner
viewpager_item_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/mainContainer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/gallery_pager_item_background">
<ImageView
android:id="#+id/main_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerInside"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
gallery_pager_item_background.xml
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:dither="true"
android:shape="rectangle">
<solid android:color="#color/black" />
<corners android:radius="16dp" />
</shape>
The corners that are showing are probably from a ViewGroup that frames the ViewPager. It is hard to know since you haven't posted all of your code.
The culprit could the the Decor View. Try the following in the main activity to see if the color of the edges change.
getWindow().getDecorView().setBackground(new ColorDrawable(getResources()
.getColor(android.R.color.holo_green_light)));
If that doesn't work, look at other ViewGroup parents to see where the color is coming in. You can use the Layout Inspector to look into the view hierarchy.
The problem could also be in how you are constructing the custom view.
I need to show a splash screen with 2 colors. 1 of the color hight requires 40% and another one requires 60%.
UI is not responsive for different screens when I provide height in dp.
XML:
<?xml version="1.0" encoding="UTF-8" ?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:height="290dp" android:gravity="fill_horizontal|top">
<color android:color="#00549F"/>
</item>
<item android:height="560dp" android:gravity="fill_horizontal|bottom">
<color android:color="#android:color/white"/>
</item>
<item android:bottom="80dp">
<bitmap
android:src="#drawable/Image_null"
android:gravity="center_horizontal|bottom"/>
</item>
</layer-list>
I Tried below code with layout.But it's not working.Showing errors at weightSum
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" android:background="#android:color/white" android:weightSum="2">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0.8"
android:background="#00549F"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1.2">
<ImageView
android:layout_width="wrap_content"
android:layout_height="80dp"
android:layout_gravity="bottom"
android:foregroundGravity="center"
android:src="#drawable/Image_null"
/>
</LinearLayout>
</LinearLayout>
Java Code:
public class SplashActivity : AppCompatActivity
{
static readonly string TAG = "X:" + typeof(SplashActivity).Name;
public override void OnCreate(Bundle savedInstanceState, PersistableBundle persistentState)
{
base.OnCreate(savedInstanceState, persistentState);
Log.Debug(TAG, "SplashActivity.OnCreate");
}
protected override void OnResume()
{
base.OnResume();
Log.Debug(TAG, "Startup work is finished - starting MainActivity.");
StartActivity(new Intent(this, typeof(MainActivity)));
}
}
Divide screen in two parts and set the background to each part .
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="4"
android:background="#00549F" />
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="6"
android:background="#FFFFFF" />
</LinearLayout>
The values for left, top, right and bottom are measured from their respective edge.
So left=0dp, top=0dp, bottom=0dp & right=50dp will give you a rectangle that is (match_parent - 50dp) wide and not 50dp wide. Therefore larger values for "right" will actually give you a smaller rectangle.
The same would apply to the other value, but these would behave as expected in most cases, its just "right" that might cause confusion.
Either you use px instead of dp or multiply all dimensions by 10.
Divide screen in two parts:-
android:layout_weight=5
android:layout_weight=5
Use LinearLayout and divide with two different child views and assign them weight. Use below code
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="2">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.5"
android:background="#00549F" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.5" />
</LinearLayout>
I am not able to use ripple effect on pressing on a tab please help I have tried a lot and struggling with it whole day.How can I use ripple effect on both pre-lollipop and lollipop devices any suggestion?
MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPager=(ViewPager)findViewById(R.id.pager);
mPager.setAdapter(new MyPagerAdapter(getSupportFragmentManager(),getApplicationContext()));
mTabs=(SlidingTabLayout)findViewById(R.id.tabs);
mTabs.setDistributeEvenly(true);
mTabs.setCustomTabView(R.layout.customtablayout,R.id.textTab);
mTabs.setBackgroundColor(getResources().getColor(R.color.colorAccent));
mTabs.setSelectedIndicatorColors(getResources().getColor(R.color.colorPrimary));
mTabs.setViewPager(mPager);
}
activitymain.xml
<sarveshchavan777.inrerface2.SlidingTabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
customtablayout.xml
<ImageView
android:id="#+id/imageTab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<TextView
android:id="#+id/textTab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="bottom|center" />
use this code for any item you want to give it ripple effect.
copy this code into a new XML file in the drawable folder. and set it as the background of any item you want ripple effect for.
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:color="#color/icons"
tools:targetApi="lollipop">
<item android:drawable="?attr/colorPrimaryDark" />
</ripple
This should work
mTabs.setTabRippleColor(getResources().getColorStateList(R.color.colorPrimaryDark));
I cannot find a way how to make linearLayout opaque. It's always transparent no matter what I do.
The layout looks like this:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent">
<LinearLayout
android:orientation="vertical"
android:id="#+id/error_panel"
android:layout_width="match_parent"
android:background="#color/gray_background_dark"
android:layout_height="wrap_content">
<TextView
android:id="#+id/error_message"
android:text="#string/dummy_number"
android:gravity="center_vertical|left"
android:textColor="#color/red"
android:layout_width="match_parent"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:layout_marginLeft="#dimen/activity_horizontal_margin"
android:layout_marginRight="#dimen/activity_horizontal_margin"
android:layout_height="wrap_content" />
</LinearLayout>
<!-- The content of this scroll view is seen underneath the errorPanel -->
<ScrollView
android:layout_height="match_parent"
android:layout_width="match_parent">
<!-- Content of ScrollView -->
</ScrollView>
</FrameLayout>
How can I make the LinearLayout opaque? Maybe instead of setting just color I could try to use a solid drawable..?
Background
I am using appcompat v7 theme <style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
Things I tried
Override the theme's panelBackground from transparent to <item name="android:panelBackground">#android:color/black</item>
Set background as background=#FF000000 on LinearLayout.
Set alpha as alpha=1 on LinearLayout.
Set background as drawable android:background="#drawable/background_error_panel" where the drawable is:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="#FF181818"/>
</shape>
Edit 3/25/2015
Maybe the animations are the problem..? i use scale anims and in code:
public void toggle() {
panel.setText("Some text Some text Some text Some text Some text ");
Animation slideIn = AnimationUtils.loadAnimation(MyApplication.context, R.anim.slide_in);
Animation slideOut = AnimationUtils.loadAnimation(MyApplication.context, R.anim.slide_out);
if (layout.getVisibility() == View.GONE) {
layout.setVisibility(View.VISIBLE);
layout.startAnimation(slideIn);
layout.setAlpha(1);
} else {
layout.startAnimation(slideOut);
layout.setVisibility(View.GONE);
}
}
It is your ScrollView being transparent. As per the docs,
Child views are drawn in a stack, with the most recently added child on top.
So you need to load the ScrollView first to have it in the background.
I've been playing with the L preview for a few days, and one thing that doesn't seem to work is the android:elevation attribute for a view. It works just fine when calling View.setElevation(), but it just seems to ignore the XML attribute. I'm using Android Studio 0.8.2 and have minSdkVersion and targetSdkVersion set to 'L', and compileSdkVersion set to 'android-L'. buildToolsVersion is "20.0.0". Here is a sample layout that doesn't work properly:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_margin="10dp"
android:elevation="5dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="top"/>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_margin="10dp"
android:elevation="0dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="bottom"/>
</android.support.v7.widget.CardView>
</LinearLayout>
Here is a screenshot of the result: imgur.com/mqeq9vK
According to the android:elevation I set, the bottom card should be flat on the "ground", but it isn't. In fact, it looks no different than the top card who's elevation is 5dp. Is this a known issue, and does it work for you?
EDIT: It seems this is only the case with CardView, or at least it isn't an issue with Buttons. In this layout I replaced CardView with Button, and even though the shadow is kind of screwed up (known bug), you can still see the difference in elevation.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:elevation="2dp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:elevation="1dp"/>
</LinearLayout>
EDIT 2: It's pretty much confirmed that this issue only affects CardView, android:elevation works fine for any other view. For a detailed explanation of why this happens look at the accepted answer. In the meantime, my workaround is to replace the CardView with a FrameLayout and set android:background to a drawable. Here is an example of a card background drawable that works:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<solid android:color="#fff" />
</shape>
I've also filed this as a bug, so please star this issue if it affects you. https://code.google.com/p/android-developer-preview/issues/detail?id=731
CardView sets its own elevation during initialization, which will override whatever you set from XML. You should file this as a bug at https://code.google.com/p/android-developer-preview/wiki/FilingIssues?tm=3
#Override
public void initialize(CardViewDelegate cardView, Context context, int backgroundColor,
float radius) {
cardView.setBackgroundDrawable(new RoundRectDrawable(backgroundColor, radius));
View view = (View) cardView;
view.setClipToOutline(true);
view.setElevation(context.getResources().getDimension(R.dimen.cardview_elevation));
}
Please use cardElevation property to set elevation on the CardView. This will effect shadow size pre-L as well.
Also, see the documentation for other attributes.
Please add this in your root
xmlns:card_view="http://schemas.android.com/apk/res-auto"
below is the code for a cardview
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardElevation="10dp"
android:id="#+id/view" >
.
.
.
.
.
Child
.
.
.
.
</android.support.v7.widget.CardView>
Until the bug fix is released you can programmatically set it.
I've done it in a RecyclerView like this:
In your RecyclerView.Adapter:
public class MyAdapter extends RecyclerView.Adapter<TripsAdapter.ViewHolder> {
/* ... */
public class ViewHolder extends RecyclerView.ViewHolder {
CardView card;
public ViewHolder(View itemView) {
card = (CardView) itemView.findViewById(R.id.card_view);
}
}
/* ... */
#Override public void onBindViewHolder(ViewHolder holder, int position) {
/// ...
// Update Card Elevation
final float scale = mContext.getResources().getDisplayMetrics().density;
holder.card.setElevation(1f * scale); //TODO set this in xml once CardView elevation bug is fixed
}
}