Làm cách nào để bạn tạo màn hình demo trong suốt cho ứng dụng Android?


105

Tôi đang cố tạo màn hình demo nửa trong suốt chỉ được khởi chạy khi người dùng cài đặt ứng dụng của tôi lần đầu tiên. Đây là một ví dụ từ ứng dụng Pulse News:

Galaxy Nexus

Ảnh chụp màn hình ví dụ từ Pulse News trên Galaxy Nexus

Nexus One

nhập mô tả hình ảnh ở đây

Thay vì tính năng 'nhấn để loại bỏ', tôi muốn người dùng có thể vuốt qua một vài trang demo trong suốt như vậy.

Trong lần thử đầu tiên, tôi đã sửa đổi một mẫu từ thư viện ViewPagerIndicator . Tôi đã sử dụng các tệp PNG nửa trong suốt trong ImageViews bên trong mỗi mảnh của máy nhắn tin chế độ xem. Sau đó, tôi khởi chạy hoạt động này dưới dạng 'hoạt động demo' trong phương pháp onCreate của 'hoạt động chính' của tôi.

Vấn đề: Không thể nhìn thấy 'hoạt động chính' trong nền - thay vào đó nó chỉ là màu đen. Tôi đã thử các giải pháp ở đây , nhưng điều đó không khắc phục được sự cố.

Có cách nào tốt hơn để tạo ra thứ gì đó như thế này không, hay tôi đang đi đúng hướng?

Tôi cũng có một câu hỏi liên quan khác phụ thuộc vào cách điều này được thực hiện. Tôi đang cố gắng phủ văn bản và mũi tên sao cho chúng trỏ vào các thành phần giao diện người dùng cụ thể trong nền. Bằng cách sử dụng PNG có văn bản và mũi tên, có khả năng nó sẽ không chia tỷ lệ chính xác trên các thiết bị khác nhau. Tức là, các mũi tên có thể không nhất thiết phải trỏ đến thành phần giao diện người dùng chính xác trong nền. Có cách nào để giải quyết vấn đề này không?

Cảm ơn!

Đây là mã của tôi cho lần thử đầu tiên:

DemoActivity.java

public class DemoActivity extends FragmentActivity {
    DemoFragmentAdapter mAdapter;
    ViewPager mPager;
    PageIndicator mIndicator;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.demo_activity);

        mAdapter = new DemoFragmentAdapter(getSupportFragmentManager());

        mPager = (ViewPager)findViewById(R.id.pager);
        mPager.setAdapter(mAdapter);
        //mPager.setAlpha(0);

        UnderlinePageIndicator indicator = (UnderlinePageIndicator)findViewById(R.id.indicator);
        indicator.setViewPager(mPager);
        indicator.setFades(false);
        mIndicator = indicator;
    }

}

DemoFragmentAdapter.java

class DemoFragmentAdapter extends FragmentPagerAdapter {
    protected static final int[] CONTENT = new int[] { R.drawable.demo1, R.drawable.demo2, R.drawable.demo3, R.drawable.demo4};

    private int mCount = CONTENT.length;

    public DemoFragmentAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        return DemoFragment.newInstance(CONTENT[position % CONTENT.length]);
    }

    @Override
    public int getCount() {
        return mCount;
    }

    public void setCount(int count) {
        if (count > 0 && count <= 10) {
            mCount = count;
            notifyDataSetChanged();
        }
    } }

DemoFragment.java

public final class DemoFragment extends Fragment {
    private static final String KEY_CONTENT = "TestFragment:Content";

    public static DemoFragment newInstance(int content) {
        DemoFragment fragment = new DemoFragment();
        fragment.mContent = content;
        return fragment;
    }

    private int mContent;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if ((savedInstanceState != null) && savedInstanceState.containsKey(KEY_CONTENT)) {
            mContent = savedInstanceState.getInt(KEY_CONTENT);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        ImageView image = new ImageView(getActivity());
        image.setBackgroundResource(mContent);

        LinearLayout layout = new LinearLayout(getActivity());
        layout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        layout.setGravity(Gravity.CENTER);
        layout.addView(image);

        return layout;
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt(KEY_CONTENT, mContent);
    }
}

Nếu không nhìn vào mã của bạn, thật khó để đề xuất bất cứ điều gì. Nếu bạn có thể đặt mã hoạt động của mình, nó có thể hữu ích.
Sayyam

11
đó là một câu hỏi hay.
con_9

Câu trả lời:


79

Đưa thông tin demo của bạn vào một hoạt động khác và cung cấp cho nó chủ đề sau.

<style name="Transparent" parent="@android:style/Theme.NoTitleBar">
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowNoTitle">true</item>      
    <item name="android:backgroundDimEnabled">false</item>
</style>

Nếu bạn đang sử dụng ActionBarSherlock, hãy thay đổi parentthành @style/Theme.Sherlock.

Điều này sẽ cung cấp cho bạn một hoạt động minh bạch, vì vậy bạn sẽ có thể nhìn thấy hoạt động bên dưới nó.

Bây giờ tôi đoán bạn cũng muốn có một nền mờ.

Trong bố cục xml (của hoạt động minh bạch của bạn), hãy thêm:

android:background="#aa000000" 

6 chữ số cuối cùng xác định màu: 000000 là màu đen.

2 đầu tiên xác định độ mờ: 00 trong suốt 100%, ff là 100% mờ. Vì vậy, hãy chọn một cái gì đó ở giữa.


1
Cảm ơn vì câu trả lời! Đây là khá nhiều những gì tôi đã làm, sau rất nhiều lần thử và sai . Tôi vẫn tò mò về cách màn hình demo Pulse có thể 'định vị lại' nội dung được phủ ở những vị trí phù hợp, ngay cả trên các kích thước màn hình khác nhau - hãy xem ảnh chụp màn hình được cập nhật. Bất kỳ ý tưởng?
Gautam,

2
Trong hoạt động đầu tiên của bạn, hãy tìm dạng xem bạn muốn trỏ tới ( findViewById). Sau đó, lấy vị trí của nó so với bố cục gốc bằng cách sử dụng phương pháp này . Gửi vị trí cho hoạt động lớp phủ trong ý định. Thực hiện căn chỉnh thích hợp.
Benito Bertoli,

2
Hoặc sử dụng View.getLocationOnScreen(int[] location)hoặc View.getLocationInWindow(int[] location). Tôi không chắc cái nào tốt hơn.
Benito Bertoli

@Gautam: "Có ý kiến ​​gì không?" - đối với Pulse, đây là vấn đề đặt một hình ảnh ở góc trên bên trái, một hình ảnh khác ở giữa và hình ảnh thứ ba ở góc dưới bên phải. Một tá dòng XML, dựa trên a RelativeLayout, là đủ.
CommonsWare

1
Điều này đã hiệu quả với tôi, nhưng tôi đã gặp vấn đề trong các hoạt động của mình khi thực hiện Hoạt động kéo dài. Vì vậy, để sử dụng AppCompatActivity, tôi đã định nghĩa kiểu như sau: <style name = "Transparent" parent = "Theme.AppCompat"> <item name = "android: windowContentOverlay"> @ null </item> <item name = "android : windowIsTranslucent "> true </item> <item name =" android: windowBackground "> @ android: color / transparent </item> <item name =" android: windowNoTitle "> true </item> <item name =" android : backgroundDimEnabled "> false </item> </style>
Jose Q

65

Bạn đã xem ShowcaseView chưa? https://github.com/Espiandev/ShowcaseView .

Sử dụng cái này:

View showcasedView = findViewById(R.id.view_to_showcase);
ViewTarget target = new ViewTarget(showcasedView);
ShowcaseView.insertShowcaseView(target, this, R.string.showcase_title, R.string.showcase_details);

1
Cảm ơn, đó chính xác là những gì tôi đang tìm kiếm.
Snicolas

Tuyệt vời! Bạn có biết điều gì tương tự cho iOS không?
KVISH

Chưa được chấp nhận ... Nhà phát triển có nghĩa là thiết kế của API cơ bản không đủ tốt (đúng một phần).
Laurent Meyer

Tôi đã thử điều này và tôi thấy rằng không có thẻ nào để thay đổi hình ảnh.
Anshul Tyagi

11

Pulse đang sử dụng một RelativeLayout với bốn ImageView và bốn TextView. Văn bản trong ảnh chụp màn hình đều là TextView với phông chữ tùy chỉnh của riêng chúng.

Trong Tệp kê khai của bạn, hãy thêm thông tin sau vào Hoạt động của bạn:

android: theme = "@ style / Theme.Transparent">

Trong RelativeLayout bên ngoài của bạn, hãy thêm:

android: background = "# aa000000"

Đối với tệp styles.xml của bạn:

<style name="Theme.Transparent" parent="android:Theme">
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowIsFloating">false</item>
    <item name="android:backgroundDimEnabled">false</item>
</style>    

Ví dụ về cách lập trình phông chữ tùy chỉnh bạn có thể tìm thấy tại:

https://github.com/commonsguy/cw-android/tree/master/Fonts/FontSampler/

Bố cục từ Trình xem cấu trúc phân cấp trông như thế này (hộp màu đỏ là vùng chứa RelativeLayout):

nhập mô tả hình ảnh ở đây


6
setContentView(R.layout.sample_main);
showOverLay();

private void showOverLay(){

    final Dialog dialog = new Dialog(context, android.R.style.Theme_Translucent_NoTitleBar);

    dialog.setContentView(R.layout.transparent);

    RelativeLayout layout = (RelativeLayout) dialog.findViewById(R.id.transparent);

    layout.setOnClickListener(new View.OnClickListener() {

        @Override

        public void onClick(View arg0) {

            dialog.dismiss();

        }

    });

    dialog.show();

}

chính xác những gì tôi đang tìm kiếm đơn giản và dễ hiểu, và dễ dàng gọi phương thức mà không cần kiểm soát hoặc xếp chồng các hoạt động. cảm ơn
Abhishek Garg

5

Đối với điều này, bạn cần tạo bố cục trợ giúp ở cuối bố cục chính, ví dụ: (cấu trúc)

<Parent layout>

<Layout 1>(Linear,Relative,....)
  Main layout
  your view...
</Layout 1>

<Layout help>
  set #70000000 as background of this layout 
  #70(transparent range can change) 000000(black)
  and height and width as fillparent
</Layout help>

</Parent layout>

2

Gói bố cục chính của bạn trong một RelativeLayout, sau đó thêm một bố cục thứ hai vào đó, chẳng hạn như:

<RelativeLayout
    .... >

    <LinearLayout
        .... >

        <!-- Contents of your main layout -->

    </LinearLayout>

    <LinearLayout
        ....
        android:background="#44000000" > <!-- This is alpha 68/255, black -->

        <!-- Contents of your overlay layout -->

    </LinearLayout>

</RelativeLayout>

Tôi tin rằng bố cục lớp phủ nằm bên dưới bố cục chính trong tệp XML (nếu bộ nhớ phục vụ). Sau đó, bạn có thể tạo bố cục của riêng mình ViewFlipper, bất cứ thứ gì bạn muốn trong bố cục thứ hai này.


1
Cám ơn phản hồi của bạn! Tôi đã thử điều này và nó có vẻ hoạt động. Tuy nhiên, có một vấn đề - nội dung trong bố cục lớp phủ không bao phủ trên Thanh hành động hoặc các tab Thanh hành động mà tôi có trong hoạt động của mình.
Gautam

Bạn đã thêm tệp RelativeLayoutvào demo_activity.xmltệp? Và là DemoActivitychính (đầu tiên) của bạn Activity?
Eric

Vâng 'DemoActivity' là nỗ lực của tôi để tạo ra một hoạt động minh bạch có thể làm được điều tương tự. 'MainActivity' là hoạt động mà tôi muốn ở bên dưới nền. Vì vậy, tôi đã bao bọc bố cục cho 'MainActivity', tức là 'main_activity.xml' bằng 'RelativeLayout' như bạn đã đề cập và cũng chèn 'LinearLayout' trong suốt. Vấn đề là, tất cả nội dung trong 'main_activity.xml' được hiển thị bên dưới 'ActionBar' và bất kỳ tab điều hướng nào của nó.
Gautam

1

Tạo một Hoạt động mới (giả sử Hướng dẫn).

Đi tới tệp xml bố cục của Hoạt động của bạn (activity_tutorial). Trong bố cục chính, thêm "android: background = # 000" và "android: alpha =" 0.5 "

<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=".Tutorial_Activity" 
    android:background="#000"
    android:alpha="0.5">
  ..................................................
  ....................................................
  .............................................
  ...............................................
  
  </RelativeLayout>

Bây giờ, hãy chuyển đến tệp kê khai ứng dụng và trong hoạt động hướng dẫn của bạn, hãy thêm thuộc tính android: theme = "@ android: style / Theme.Translucent.NoTitleBar">

<application>
 .........................................
..........................................
....................................
..........................................

<activity
            android:name="com.aird.airdictionary.Tutorial_Activity"
            android:label="@string/title_activity_tutorial"
            
          android:theme="@android:style/Theme.Translucent.NoTitleBar">
  
        </activity>
    </application>

</manifest>

Đó là nó, bây giờ chạy hoạt động này trên bất kỳ hoạt động nào khác và bạn có thể nhận được kết quả mong muốn. Tùy chỉnh, thêm văn bản, lượt xem hình ảnh và các nội dung khác để có được màn hình hướng dẫn mong muốn của bạn. Khá chắc chắn rằng bạn có thể làm cho một máy ngắm hoạt động với kỹ thuật này.


0

Bạn chỉ có thể kiểm tra mã trình khởi chạy Android khi họ làm điều đó. Tôi không biết có thực hiện.

Nếu là tôi, tôi sẽ làm (nếu chỉ là một lớp phủ đơn giản), vì vậy bạn không cần phải lo lắng về bố cục cho ứng dụng của mình, chỉ cần tạo bố cục lớp phủ và đính kèm nó lên bố cục ứng dụng của bạn bằng cách thêm nó trực tiếp vào các hoạt động của bạn WindowManager. Có thể đơn giản như thêm một ImageViewvào WindowManager, lắng nghe các chạm vào ImageViewhoặc có thời gian chờ để xóa ImageViewkhỏi của bạn Window.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.