snackBar의 레이아웃을 사용자 지정하는 방법은 무엇입니까?


94

스낵바의 레이아웃을 사용자 정의보기로 변경하는 방법이 있습니까?

이제 검은 색이되고 배경색을 변경할 수 있습니다. 하지만 새로운 레이아웃을 부풀려서 스낵바 배경으로 만드는 올바른 방법을 모르겠습니다.

감사...

답변:


147

스낵바에서는 사용자 지정 레이아웃을 설정할 수 없습니다. 그러나 Primoz990이 제안했듯이 Snackbar 's View를 얻을 수 있습니다. getView 함수는 자식이 TextView 및 Button 인 수평 LinearLayout 개체 인 Snackbar.SnackbarLayout을 반환합니다. Snackbar에 자신의보기를 추가하려면 TextView를 숨기고 Snackbar.SnackbarLayout에보기를 추가하기 만하면됩니다.

// Create the Snackbar
Snackbar snackbar = Snackbar.make(containerLayout, "", Snackbar.LENGTH_LONG);
// Get the Snackbar's layout view
Snackbar.SnackbarLayout layout = (Snackbar.SnackbarLayout) snackbar.getView();
// Hide the text
TextView textView = (TextView) layout.findViewById(android.support.design.R.id.snackbar_text);
textView.setVisibility(View.INVISIBLE);

// Inflate our custom view
View snackView = mInflater.inflate(R.layout.my_snackbar, null);
// Configure the view
ImageView imageView = (ImageView) snackView.findViewById(R.id.image);
imageView.setImageBitmap(image);
TextView textViewTop = (TextView) snackView.findViewById(R.id.text);
textViewTop.setText(text);
textViewTop.setTextColor(Color.WHITE);

//If the view is not covering the whole snackbar layout, add this line
layout.setPadding(0,0,0,0);

// Add the view to the Snackbar's layout
layout.addView(snackView, 0);
// Show the Snackbar
snackbar.show();

4
나를 위해 hi..this 작품 ...하지만 내 플로팅 작업의 폭은 완전히 확장되지 않습니다
H 라발 (Raval)을

13
나는 이런 종류의 것에 대해주의를 기울일 것입니다. 이러한 시스템 클래스의 내부 구현 세부 정보가 언제 변경되는지 알 수 없습니다. 필요한 작업을 수행하지 않는 경우 사용자 정의 구성 요소를 구현하는 것이 더 안전합니다.
Dean Wild

crouton 라이브러리를 사용하는 것이 좋습니다
X09

@Ozuf 잘 크루통 라이브러리는 사용되지 않습니다
slinden77

3
v 25.1.0부터 이것이 가능해졌습니다. 아래 내 게시물을 확인하십시오. 좋은 답변 감사합니다!
Yakiv Mospan

64

Android 지원 라이브러리 25.1.0 버전 부터 가능합니다.

I. 값 / 레이아웃 폴더에 사용자 지정 레이아웃을 선언합니다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:orientation="horizontal"
          android:layout_width="match_parent"
          android:layout_height="wrap_content">

<Button
    android:id="@+id/snackbar_action"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="@dimen/design_snackbar_extra_spacing_horizontal"              
    android:layout_marginStart="@dimen/design_snackbar_extra_spacing_horizontal"
    android:layout_gravity="center_vertical|right|end"
    android:paddingTop="@dimen/design_snackbar_padding_vertical"
    android:paddingBottom="@dimen/design_snackbar_padding_vertical"
    android:paddingLeft="@dimen/design_snackbar_padding_horizontal"
    android:paddingRight="@dimen/design_snackbar_padding_horizontal"
    android:visibility="gone"
    android:textColor="?attr/colorAccent"
    style="?attr/borderlessButtonStyle"/>

<TextView
    android:gravity="center_vertical|right"
    android:id="@+id/snackbar_text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:paddingTop="@dimen/design_snackbar_padding_vertical"
    android:paddingBottom="@dimen/design_snackbar_padding_vertical"
    android:paddingLeft="@dimen/design_snackbar_padding_horizontal"
    android:paddingRight="@dimen/design_snackbar_padding_horizontal"
    android:textAppearance="@style/TextAppearance.Design.Snackbar.Message"
    android:maxLines="@integer/design_snackbar_text_max_lines"
    android:layout_gravity="center_vertical|left|start"
    android:ellipsize="end"/>

</LinearLayout>

힌트 :

  • @dimen/design_snackbar값을 사용 하여 머티리얼 디자인 지침과 일치합니다.
  • ?attr/colorAccentSnackbar에 응용 프로그램 테마 변경 사항을 적용하는 데 사용 합니다.

II. BaseTransientBottomBar 클래스를 확장합니다 .

public class final CustomSnackbar extends BaseTransientBottomBar<CustomSnackbar> {

/**
 * Constructor for the transient bottom bar.
 *
 * @param parent The parent for this transient bottom bar.
 * @param content The content view for this transient bottom bar.
 * @param contentViewCallback The content view callback for this transient bottom bar.
 */
private CustomSnackbar(ViewGroup parent, View content,    
            ContentViewCallback contentViewCallback) {
    super(parent, content, contentViewCallback);
}
}

III. BaseTransientBottomBar.ContentViewCallback 추가

public class final CustomSnackbar ...{

...

private static class ContentViewCallback implements        
                   BaseTransientBottomBar.ContentViewCallback {

  // view inflated from custom layout
  private View content;

  public ContentViewCallback(View content) {
      this.content = content;
  }

  @Override
  public void animateContentIn(int delay, int duration) {
      // add custom *in animations for your views
      // e.g. original snackbar uses alpha animation, from 0 to 1
      ViewCompat.setScaleY(content, 0f);
      ViewCompat.animate(content)
                .scaleY(1f).setDuration(duration)
                .setStartDelay(delay);
  }

  @Override
  public void animateContentOut(int delay, int duration) {
      // add custom *out animations for your views
      // e.g. original snackbar uses alpha animation, from 1 to 0
      ViewCompat.setScaleY(content, 1f);
      ViewCompat.animate(content)
                .scaleY(0f)
                .setDuration(duration)
                .setStartDelay(delay);
  }
}
}

IV. 커스텀 레이아웃으로 Snackbar를 생성하는 방법과 채우기 방법을 추가합니다.

public class final CustomSnackbar ...{

...

public static CustomSnackbar make(ViewGroup parent, @Duration int duration) {
 // inflate custom layout
 LayoutInflater inflater = LayoutInflater.from(parent.getContext());
 View content = inflater.inflate(R.layout.snackbar_view, parent, false);

 // create snackbar with custom view
 ContentViewCallback callback= new ContentViewCallback(content);
 CustomSnackbar customSnackbar = new CustomSnackbar(parent, content, callback);
// Remove black background padding on left and right
customSnackbar.getView().setPadding(0, 0, 0, 0);


 // set snackbar duration
 customSnackbar.setDuration(duration);
 return customSnackbar;
 }

 // set text in custom layout
 public CustomSnackbar setText(CharSequence text) {
 TextView textView = (TextView) getView().findViewById(R.id.snackbar_text);
 textView.setText(text);
 return this;
 }

 // set action in custom layout
 public CustomSnackbar setAction(CharSequence text, final OnClickListener  listener) {
 Button actionView = (Button) getView().findViewById(R.id.snackbar_action);
 actionView.setText(text);
 actionView.setVisibility(View.VISIBLE);
 actionView.setOnClickListener(new View.OnClickListener() {
     @Override
     public void onClick(View view) {
         listener.onClick(view);
         // Now dismiss the Snackbar
         dismiss();
     }
 });
 return this;
}
}

V. 인스턴스 생성 CustomSnackbarshow()메서드 호출 .

CustomSnackbar customSnackbar = CustomSnackbar.make(rooView,      CustomSnackbar.LENGTH_INDEFINITE);
customSnackbar.setText("No network connection!");
customSnackbar.setAction("Retry", new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // handle click here
    }
});
customSnackbar.show();

materialdoc.com 에서 Snackbar 및 사용자 정의에 대해 자세히 알아보십시오.

전체 CustomSnackbar.class코드 :

import android.support.annotation.NonNull;
import android.support.design.widget.BaseTransientBottomBar;
import android.support.v4.view.ViewCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;


public class CustomSnackbar extends BaseTransientBottomBar<CustomSnackbar> {

    /**
     * Constructor for the transient bottom bar.
     *
     * @param parent The parent for this transient bottom bar.
     * @param content The content view for this transient bottom bar.
     * @param callback The content view callback for this transient bottom bar.
     */
    private CustomSnackbar(ViewGroup parent, View content, ContentViewCallback callback) {
        super(parent, content, callback);
    }

    public static CustomSnackbar make(@NonNull ViewGroup parent, @Duration int duration) {
        final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        final View content = inflater.inflate(R.layout.snackbar_view, parent, false);
        final ContentViewCallback viewCallback = new ContentViewCallback(content);
        final CustomSnackbar customSnackbar = new CustomSnackbar(parent, content, viewCallback);

        customSnackbar.getView().setPadding(0, 0, 0, 0);
        customSnackbar.setDuration(duration);
        return customSnackbar;
    }

    public CustomSnackbar setText(CharSequence text) {
        TextView textView = (TextView) getView().findViewById(R.id.snackbar_text);
        textView.setText(text);
        return this;
    }

    public CustomSnackbar setAction(CharSequence text, final View.OnClickListener listener) {
        Button actionView = (Button) getView().findViewById(R.id.snackbar_action);
        actionView.setText(text);
        actionView.setVisibility(View.VISIBLE);
        actionView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                listener.onClick(view);
                // Now dismiss the Snackbar
                dismiss();
            }
        });
        return this;
    }

    private static class ContentViewCallback implements BaseTransientBottomBar.ContentViewCallback {

        private View content;

        public ContentViewCallback(View content) {
            this.content = content;
        }

        @Override
        public void animateContentIn(int delay, int duration) {
            ViewCompat.setScaleY(content, 0f);
            ViewCompat.animate(content).scaleY(1f).setDuration(duration).setStartDelay(delay);
        }

        @Override
        public void animateContentOut(int delay, int duration) {
            ViewCompat.setScaleY(content, 1f);
            ViewCompat.animate(content).scaleY(0f).setDuration(duration).setStartDelay(delay);
        }
    }
}

1
@AmirZiarati 예, 구성 요소가 바뀝니다 (기본적으로 작업 버튼은 오른쪽에 있음).
Yakiv Mospan 2017 년

2
검정색 배경이 보이도록 왼쪽과 오른쪽에 여백이 생겼습니다. 그것을 제거하는 방법?
Leo Droidcoder

2
@AmirZiarati를 아래쪽에서 표시하려면 Snackbar 클래스에서 개인 정적 메서드를 복사해야합니다. 질문에 대한 답변에서 방법을 강조했습니다.
Tunji_D

2
투명한 배경은 어떻게 설정합니까?
DaniloDeQueiroz

1
@YakivMospan 저를 위해 그것은 아래에서 보여줍니다, 당신은 내가 위에서 그것을 어떻게 보여줄 수 있는지 말해 주시겠습니까?
Levon Petrosyan 2018 년

24

XML 방식 :

에 사용되는 원래 레이아웃 xml 파일 Snackbar은 다음 파일입니다.

design_layout_snackbar_include.xml:

<?xml version="1.0" encoding="utf-8"?>        
<merge xmlns:android="http://schemas.android.com/apk/res/android">

    <TextView
            android:id="@+id/snackbar_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
              ...
            android:ellipsize="end"/>

    <Button
            android:id="@+id/snackbar_action"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:visibility="gone"
              ...
            android:textColor="?attr/colorAccent"
            style="?attr/borderlessButtonStyle"/>

</merge>

따라서이 레이아웃재정의하려면이 레이아웃 과 동일한 android:ids를 사용하여 자신의 레이아웃을 작성하고 refs.xml파일에 다음 행을 추가해야합니다.

<resources xmlns:tools="http://schemas.android.com/tools">
   ....   
    <item name="design_layout_snackbar_include" tools:override="true" type="layout">
        @layout/my_layout_snackbar
    </item>
   ....
</resources>

1
이전에는 잘 작동했지만 Design Support Library 25.1.0으로 업데이트 한 후 병합 레이아웃 예외가 발생하기 시작했습니다. 병합 태그를 뷰로 변경 한 코드 를 찾았 으며 이제 다시 작동합니다.
nilsi

2
이것은 너비를 늘리지 않습니다. 젠장이 안드로이드 !!!! 관점을 바꾸는 것이 왜 고통 스러운지. 젠장!
Amir Ziarati

자료 문서 BaseTransientBottomBarstackoverflow.com/a/41154330/9636
Heath Borders

18

대답은 : Snackbar를 사용자 지정하지 마십시오. 짧은 텍스트와 하나의 작업보다 더 많은 요소를 포함해서는 안됩니다. 참조 구글 재료 설계 지침을 .

업데이트 : 어쨌든 Snackbar를 사용자 정의하려면 여기에 내 앱에서 구현 한 것입니다.

//generate the snackbar
Snackbar sb = Snackbar.make(rootView, snack.text, duration);
//set te action button text color
sb.setActionTextColor(mCurrentActivity.getResources().getColor(R.color.snack_text_action));
//Get the view of the snackbar
View sbView = sb.getView();
//set background color
sbView.setBackgroundColor(mCurrentActivity.getResources().getColor(backgroudResId));
//Get the textview of the snackbar text
TextView textView = (TextView) sbView.findViewById(android.support.design.R.id.snackbar_text);
//set text color
textView.setTextColor(mCurrentActivity.getResources().getColor(R.color.snack_text));
//increase max lines of text in snackbar. default is 2.
textView.setMaxLines(10);

시도한 적이 없지만 Snackbar의 루트보기를 가져 오면 프로그래밍 방식으로 Snackbar에 새보기를 추가 할 수 있습니다.


16

작성된 코드 이미지

private Snackbar showSnackbar(CoordinatorLayout coordinatorLayout, int duration) { // Create the Snackbar
    Snackbar snackbar = Snackbar.make(coordinatorLayout, "", duration);
    // 15 is margin from all the sides for snackbar
    int marginFromSides = 15;

    float height = 100;

    //inflate view
    View snackView = getLayoutInflater().inflate(R.layout.snackbar_layout, null);

    // White background
    snackbar.getView().setBackgroundColor(Color.WHITE);
    // for rounded edges
    snackbar.getView().setBackground(getResources().getDrawable(R.drawable.round_edges));

    Snackbar.SnackbarLayout snackBarView = (Snackbar.SnackbarLayout) snackbar.getView();
    FrameLayout.LayoutParams parentParams = (FrameLayout.LayoutParams) snackBarView.getLayoutParams();
    parentParams.setMargins(marginFromSides, 0, marginFromSides, marginFromSides);
    parentParams.height = (int) height;
    parentParams.width = FrameLayout.LayoutParams.MATCH_PARENT;
    snackBarView.setLayoutParams(parentParams);

    snackBarView.addView(snackView, 0);
    return snackbar;
}

onCreate 활동에서 :

CoordinatorLayout coordinatorLayout = findViewById(R.id.coordinator_layout);

final Snackbar snackbar = showSnackbar(coordinatorLayout, Snackbar.LENGTH_LONG);
            snackbar.show();
            View view = snackbar.getView();
            TextView tv = (TextView) view.findViewById(R.id.snackbar_action);
            tv.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    snackbar.dismiss();
                }
            });

13

나는 그것을 시도하고 작동합니다!

View custom = LayoutInflater.from(this).inflate(R.layout.custom_view, null);
snackbar.getView().setPadding(0,0,0,0);
((ViewGroup) snackbar.getView()).removeAllViews();
((ViewGroup) snackbar.getView()).addView(custom);
TextView textView = custom.findViewById(R.id.text);
View button = custom.findViewById(R.id.button);
textView.setText("Your text here");
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
       // do something
    }
});

3

다음 코드를 시도하십시오.

Snackbar snackbar = Snackbar.make(container, "No Internet Connection", Snackbar.LENGTH_LONG);
View sbView = snackbar.getView();
sbView.setBackgroundColor(ContextCompat.getColor(this, R.color.colorPrimary));
snackbar.show();

노트 :

컨테이너 -레이아웃의 상위 뷰.


1

Yakiv Mospan의 답변에 추가하려면 BaseTransientBottomBar하단에서 사용자 정의 쇼를처럼 만들려면 클래스 Snackbar에서이 메서드를 복사 Snackbar하여 BaseTransientBottomBar생성자 에 적합한 부모를 찾습니다 .

private static ViewGroup findSuitableParent(View view) {
    ViewGroup fallback = null;
    do {
        if (view instanceof CoordinatorLayout) {
            // We've found a CoordinatorLayout, use it
            return (ViewGroup) view;
        } else if (view instanceof FrameLayout) {
            if (view.getId() == android.R.id.content) {
                // If we've hit the decor content view, then we didn't find a CoL in the
                // hierarchy, so use it.
                return (ViewGroup) view;
            } else {
                // It's not the content view but we'll use it as our fallback
                fallback = (ViewGroup) view;
            }
        }

        if (view != null) {
            // Else, we will loop and crawl up the view hierarchy and try to find a parent
            final ViewParent parent = view.getParent();
            view = parent instanceof View ? (View) parent : null;
        }
    } while (view != null);

    // If we reach here then we didn't find a CoL or a suitable content view so we'll fallback
    return fallback;
}

1

허용되는 답변에 대한 Kotlin 버전 : https://stackoverflow.com/a/33441214/2437655

 private fun showSnackbar() {
        val snackbar = Snackbar.make(
                binding.root,
                "",
                Snackbar.LENGTH_INDEFINITE
        )
        (snackbar.view as Snackbar.SnackbarLayout).apply {
            findViewById<View>(R.id.snackbar_text).visibility = View.INVISIBLE
            findViewById<View>(R.id.snackbar_action).visibility = View.INVISIBLE
            val snackbarBinding = DataBindingUtil.inflate<SnackbarBinding>(
                    LayoutInflater.from(this@SnackbarActivity),
                    R.layout.snackbar,
                    binding.root as ViewGroup,
                    false
            )
            setPadding(0, 0, 0, 0)
            addView(snackbarBinding.root, 0)
        }
        snackbar.setDuration(8000).show()
    }

1

다음은 kotlin의 유틸리티 클래스 코드입니다. https://gist.github.com/Ryszardenko/db429bc7d177e646ffe27e0672a0958c#file-customsnackbar-kt

class CustomSnackbar(private val view: View) {

    fun showSnackBar(title: String, cancelFun: () -> Unit = {}) {
        val snackView = View.inflate(view.context, R.layout.snackbar, null)
        val binding = SnackbarBinding.bind(snackView)
        val snackbar = Snackbar.make(view, "", Snackbar.LENGTH_LONG)
        (snackbar.view as ViewGroup).removeAllViews()
        (snackbar.view as ViewGroup).addView(binding.root)
        snackbar.view.setPadding(0, 0, 0, 0)
        snackbar.view.elevation = 0f
        snackbar.setBackgroundTint(
            ContextCompat.getColor(
                view.context,
                android.R.color.transparent
            )
        )
        binding.tvTitle.text = title
        binding.btnCancel.setOnClickListener {
            cancelFun()
            snackbar.dismiss()
        }
        snackbar.show()
    }
}

cancelFun ()은 람다이며 기본적으로 비어 있습니다. 예를 들어 "undo"함수와 같이 전달할 수 있습니다.


0

이 라이브러리를 사용해 볼 수 있습니다. 이것은 안드로이드 기본 스낵바의 래퍼입니다. https://github.com/ChathuraHettiarachchi/CSnackBar

Snackbar.with(this,null)
    .type(Type.SUCCESS)
    .message("Profile updated successfully!")
    .duration(Duration.SHORT)
    .show();

또는 자신의 견해를 사용할 수도 있습니다.

View view = getLayoutInflater().inflate(R.layout.custom_view, null);

Snackbar.with(this,null)
        .type(Type.UPDATE)
        .contentView(view, 76)
        .duration(Duration.SHORT)
        .show();

현재 커스텀 레이아웃의 유일한 문제는 dp의 뷰 높이를 입력으로 전달해야한다는 것입니다.


라이브러리를 사용하는 모든 장치에서 맞춤형 전체 너비 스낵바를 가질 수 있습니까?
yuralife

@yuralife 현재 이것은 안드로이드 스낵바의 래퍼이므로 할 수 없습니다. 전용 휴대 전화에이 전체 폭을 얻을 것이다, 태블릿에이 폭 기입하지 않습니다
Chathura Jayanath
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.