Android中的自定義控制項(一)

来源:http://www.cnblogs.com/huangjie123/archive/2016/11/22/6089140.html
-Advertisement-
Play Games

安卓允許你去繼承已經存在的控制項或者實現你自己的控制項以便優化界面和創造更加豐富的用戶體驗 ...


       自定義控制項是根據自己的需要自己來編寫控制項。安卓自帶的控制項有時候無法滿足你的需求,這種時候,我們只能去自己去實現適合項目的控制項。同時,安卓也允許你去繼承已經存在的控制項或者實現你自己的控制項以便優化界面和創造更加豐富的用戶體驗。在平常的項目中,我們 人為的把自定義控制項分為兩種:一種是組合方式實現。一種是通過繼承view或viewgroup及其子類實現。兩者都可以實現我們想要的效果,因此,我們可以根據自己的需求,選擇合適的方案。本文以案例的形式來顯示幾種較為常見的自定義控制項。

   案例一:   優酷菜單
     功能介紹: 手機界面的底部中央有一個半圓,初始狀態顯示三級菜單,由外到內分別是第三級菜單,第二級菜單,第三級菜單。每個菜單中有一些按鈕,可以用3個容器(RelativeLayout)來表示3個菜單,往裡面添加按鈕即可。當再次點擊中心位置的圖片式,隱藏外面兩層的的條目。再次點擊重心位置的圖片時,旋轉出二級菜單。點擊二級菜單中心位置時,旋轉出三級菜單,再次點擊則隱藏三級菜單。以上就是優酷菜單要實現的功能。

   實現步驟:
      1. 完成佈局文件。由於控制項較多所以優酷菜單的佈局較為複雜,但是可以在一個根佈局設置三個子線性佈局來包裹每一個小的控制項。通過調整margin值來是使得界面更加的美觀。註意3個菜單佈局的順序,先放men3,然後menu2,然後menu1,順序不能反,因為越往後放的菜單越在界面的上方,這樣面積最小的菜單1會在最上方,菜單1不會遮擋到下麵的菜單2和菜單3。
      2. 完成佈局文件後,創建一個類,在該類中實現業務邏輯。首先要創建兩個布爾類型的常量存儲菜單的狀態。通過swich語句判斷被點擊的控制項是二級菜單還是一級菜單。如果是一級菜單的中心被點擊,則判斷三級菜單是否打開。如果三級菜單打開著,則隱藏一級菜單和二級菜單,並修改狀態。如果三級菜單隱藏著則判斷二級菜單是否隱藏。如果二級菜單打開著,則隱藏二級菜單。如果二級菜單隱藏則打開二級菜單。如果是二級菜單的中心被點擊,則只需要判斷三級菜單是否隱藏。如果三級菜單打開著,則隱藏三級菜單。如果三級菜單隱藏則打開三級菜單。同時還要修改菜單的狀態。
      3. 接下來可以在一個工具類中實現動畫的效果。步驟2中的隱藏和顯示均都是通過動畫效果實現的。這裡的動畫效果用到的是補間動畫,為RotateAnimation對象傳入起始角度,結束的角度,參考對象和參考點坐標。一個小細節是將setFillAfter屬性設為true,表示從結束位置開始動畫,避免動畫結束後又回到起始位置。隱藏和顯示區別是旋轉的起始角度和結束角度,這裡顯示設定的起始角度是-180,結束角度為0。隱藏設定的起始角度為0,結束角度為-180。當然也可以設定為其他值,取決於自己想要的效果。
      4. 代碼優化。快速點擊按鈕時會發現菜單還沒隱藏完就開始顯示了,或者還沒顯示完又隱藏了。解決方案:監聽動畫的開啟次數來判斷是否需要執行畫,給動畫類添加一個監聽器。設置一個成員變數。當開始開始動畫是執行加一操作,結束動畫是執行減一操作。這樣只有當常量為零時,才沒有動畫。因此swich語句中加入判斷如果當前存在動畫,等待動畫執行完之後在進入下麵的邏輯。

       菜單選擇界面的佈局:

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

    <RelativeLayout
        android:id="@+id/rl_menu3"
        android:layout_width="280dp"
        android:layout_height="140dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level3">

        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="6dp"
            android:layout_marginLeft="12dp"
            android:background="@drawable/channel1" />

        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="46dp"
            android:layout_marginLeft="32dp"
            android:background="@drawable/channel2" />

        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="80dp"
            android:layout_marginLeft="60dp"
            android:background="@drawable/channel3" />

        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="6dp"
            android:background="@drawable/channel4" />

        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_marginBottom="80dp"
            android:layout_marginRight="60dp"
            android:background="@drawable/channel5" />

        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_marginBottom="46dp"
            android:layout_marginRight="32dp"
            android:background="@drawable/channel6" />

        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_marginBottom="6dp"
            android:layout_marginRight="12dp"
            android:background="@drawable/channel7" />

    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/rl_menu2"
        android:layout_width="180dp"
        android:layout_height="90dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level2">

        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="6dp"
            android:layout_marginLeft="12dp"
            android:background="@drawable/icon_search" />

        <ImageButton
            android:id="@+id/btn_menu2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="4dp"
            android:background="@drawable/icon_menu" />

        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_marginBottom="6dp"
            android:layout_marginRight="12dp"
            android:background="@drawable/icon_myyouku" />

    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/rl_menu1"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level1">

        <ImageButton
            android:id="@+id/btn_menu1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:background="@drawable/icon_home" />

    </RelativeLayout>
</RelativeLayout>

       主界面的佈局,在代碼中用打氣筒把菜單佈局打到主界面上。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    tools:context="com.example.selectbar.Selectbar">

    <com.example.selectbar.Rotate
        android:layout_centerInParent="true"
        android:id="@+id/rotate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>

      主程式是空實現。

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

public class Selectbar extends AppCompatActivity {

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

      主要邏輯的實現。

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.RelativeLayout;

import com.example.selectbar.com.example.selectbar.utils.utils;

/**
 * Created by huang on 2016/11/22.
 */
public class Rotate extends RelativeLayout implements View.OnClickListener {
    private static final String TAG = "Rotate";
    private RelativeLayout rl_menu1, rl_menu2, rl_menu3;
    private boolean menu2showing = true;
    private boolean menu3showing = true;

    public Rotate(Context context) {
        super(context,null);
    }

    public Rotate(Context context, AttributeSet attrs) {
        super(context, attrs);
        initdata(context);
    }


    private void initdata(Context context) {
        Log.i(TAG, "initdata: text");
        View view = View.inflate(context,R.layout.activity_rolate,null);
        view.findViewById(R.id.btn_menu1).setOnClickListener(this);
        view.findViewById(R.id.btn_menu2).setOnClickListener(this);
        rl_menu1 = (RelativeLayout) view.findViewById(R.id.rl_menu1);
        rl_menu2 = (RelativeLayout) view.findViewById(R.id.rl_menu2);
        rl_menu3 = (RelativeLayout) view.findViewById(R.id.rl_menu3);
        addView(view);
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_menu2:
                if (utils.hasAnimationexcuting()) {
                    return;
                }
                if (menu3showing) {
                    utils.hiden(rl_menu3);
                } else {
                    utils.show(rl_menu3);
                }
                menu3showing = !menu3showing;
                break;

            case R.id.btn_menu1:
                if (utils.hasAnimationexcuting()) {
                    return;
                }
                if (menu3showing) {
                    utils.hiden(rl_menu3);
                    menu3showing = false;
                    utils.hiden(rl_menu2, 300);

                } else if (menu2showing) {
                    utils.hiden(rl_menu2);
                } else {
                    utils.show(rl_menu2);
                }
                menu2showing = !menu2showing;
                break;
        }
    }
}

       還需要一個工具類實現動畫的效果。      

import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;

/**
 * Created by huang on 2016/11/22.
 */
public class utils {
    private static final String TAG = "utils";
    private static void setviewclickable(View view, boolean clickable) {
        view.setClickable(clickable);
        if (view instanceof ViewGroup) {
            ViewGroup viewgroup = (ViewGroup) view;
            for (int i = 0; i < viewgroup.getChildCount(); i++) {
                View child = ((ViewGroup) view).getChildAt(i);
                child.setClickable(clickable);
            }
        }
    }

    public static void hiden(View view) {
        float fromDegreeas = 0;
        float toDegrees = -180f;
        rotateview(view, fromDegreeas, toDegrees, 0l);
        setviewclickable(view, false);
    }

    public static void hiden(View view, long startoffset) {
        float fromDegreeas = 0;
        float toDegrees = -180f;
        rotateview(view, fromDegreeas, toDegrees, startoffset);
        setviewclickable(view, false);
    }

    public static void show(View view) {
        float fromDegrees = -180f;
        float toDegrees = 0;
        rotateview(view, fromDegrees, toDegrees, 0l);
        setviewclickable(view, true);
    }

    public static boolean hasAnimationexcuting() {
        return  startcount > 0;
    }

    public static void rotateview(View view, float fromDegrees, float toDegrees, long startoffset) {
        int pivotXType = RotateAnimation.RELATIVE_TO_SELF;
        int pivotYType = RotateAnimation.RELATIVE_TO_SELF;
        float pivotXValue = 0.5f;
        float pivatYValue = 1.0f;
        RotateAnimation ra = new RotateAnimation(fromDegrees, toDegrees, pivotXType, pivotXValue, pivotYType, pivatYValue);
        ra.setDuration(500);
        ra.setFillAfter(true);
        ra.setStartOffset(startoffset);
        ra.setAnimationListener(listener);
        view.startAnimation(ra);
    }

    public static int startcount;
    static Animation.AnimationListener listener = new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {
            startcount++;
//            Log.i(TAG, "onAnimationStart: " +startcount);
        }

        @Override
        public void onAnimationEnd(Animation animation) {
            startcount--;
//            Log.i(TAG, "onAnimationEnd: " + startcount);
        }

        @Override
        public void onAnimationRepeat(Animation animation) {

        }
    };
}

 

 

      案例二   popupwindow實現下拉列表:

      功能介紹:創建一個textview,當我們點擊textview時會彈出一個列表,列表中存放的是數字信息和一張刪除圖片。列表是用listview實現。點擊刪除圖片可以將本條記錄從列表中刪除。本案例的有兩種,一種是通過動畫的縮放實現彈出效果,另一種是採取popupwindow。本文采用的是第二種方案。

     實現步驟:

  1. 添加佈局文件。首先要在界面上放置一個textview,在textview的右邊放置一個下拉圖片。為了更方便地擺放控制項,可以採用相對佈局,這樣只要保證imageview和textview上對齊、下對齊、右對齊就可以實現要現實的效果。為了是界面更美觀,可以把圖片設為透明的,即背景為null。這裡將popupwindow彈出來的界面用listview表示。因此還要寫一個單獨的listview以及每一個條目的佈局,然後用打氣筒打到textview的下方、
  2. Pupupwindow的編寫。Popupwindow的編寫有兩個關鍵的步驟,一個是new一個pupupwimdow對象,將要顯示的佈局、佈局的高和寬、是否可聚等相關的參數傳入。這裡pupupwindow的顯示界面是用的打氣筒把listview載入進來。同時listview條目的佈局也用到inflate。因此用到兩次打氣筒。同時為每一個listview的條目設置條目點擊的監聽事件,這樣在條目被點擊時候可以將條目的內容顯示在textview中。。Popupwindow的編寫另一個關鍵性的步驟是showAsDropDown,即將要顯示在哪個控制項下方,偏移量多少出傳進來。需要註意的是控制項的實際寬高和看到的寬高有一定的誤差,只是因為控制項的背景用一定的寬度。還有一點就是,按返回鍵時PopupWindow沒法隱藏,給PopupWindow設置一個背景即可解決這個問題,如下:popupWindow.setBackgroundDrawable(new ColorDrawable())。每次顯示PopupWindow時都創建一個新的PopupWindow對象,其實可以復用一個PopupWindow對象的。即每次創建前先判斷popupwindow是否為空。
  3. Listiview條目的編寫較為定。這裡做了兩處的優化。一個是服用conterview,開始操作之前判斷conterview是否為空。若為空創建一個新的view,否則復用被回收的conterview。另一處的優化是,每一次finviewbyid會消耗大量的記憶體。因此可以單獨定義一個類,存放控制項,在cnterview為空時創建一次。每次調用時只需要調用定義類中的控制項。還有一點是,要是條目上的刪除圖標有用還要對刪除圖片設定一個點擊事件。一個小細節是,當listvie條目中存在button及其子類時,會搶占焦點。因此這裡刪除圖片的標簽用的是imageview。當然你也可以採取其他方式,比如,在條目的根佈局加上這個屬性:android:descendantFocusability="blocksDescendants"。

         主界面的佈局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="17dp"
    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="com.example.popuwindow.MainActivity">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <EditText
            android:id="@+id/et_number"
            android:layout_width="200dp"
            android:layout_height="wrap_content"
            android:hint="輸入賬號" />

        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignBottom="@id/et_number"
            android:layout_alignRight="@id/et_number"
            android:layout_alignTop="@id/et_number"
            android:background="@null"
            android:onClick="showNumberListToggle"
            android:src="@mipmap/down_arrow" />
    </RelativeLayout>
</RelativeLayout>

         listview條目的佈局

<?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="wrap_content"
    android:gravity="center_vertical"
    android:orientation="horizontal"
    android:padding="6dp">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/user" />

    <TextView
        android:id="@+id/tv_numer"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="6dp"
        android:layout_weight="1"
        android:text="10000"
        android:textSize="18sp" />

    <ImageView
        android:id="@+id/ib_del"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@null"
        android:src="@mipmap/delete" />
</LinearLayout>

       單獨寫一個listview。

<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:cacheColorHint="@null"
    android:background="@mipmap/listview_background"
    android:descendantFocusability="blocksDescendants">
</ListView>

 

       主程式中的邏輯。

import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.PopupWindow;

public class MainActivity extends AppCompatActivity {
    private EditText et_number;
    private PopupWindow popupwindow;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et_number = (EditText) findViewById(R.id.et_number);
    }

    public void showNumberListToggle(View view) {
        if (popupwindow == null) {                    //復用popupwindow
            View contentView = createContent();
            int width = et_number.getWidth() - 4;
            int height = 400;
            boolean focusable = true;
            popupwindow = new PopupWindow(contentView, width, height, focusable);
            popupwindow.setBackgroundDrawable(new ColorDrawable());
        }
        View anchor = et_number;
        int xoff = 2;
        int yoff = -5;
        popupwindow.showAsDropDown(anchor, xoff, yoff);
    }

    private View createContent() {
            ListView lv = (ListView) View.inflate(this, R.layout.activity_list, null);
            lv.setAdapter(new NumberListAdapter());
            lv.setVerticalScrollBarEnabled(false);
            lv.setOnItemClickListener(monitemclickListener);
        return lv;
    }

    AdapterView.OnItemClickListener monitemclickListener = new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            String number = (String) parent.getItemAtPosition(position);
            et_number.setText(number);
            popupwindow.dismiss();
        }
    };
}

       適配器的編寫

import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;

/**
 * Created by huang on 2016/11/22.
 */
public class NumberListAdapter extends BaseAdapter {
   private ArrayList<String> numbers = new ArrayList();
   
    {
        for (int i = 0; i < 30; i++) {
            numbers.add(10000 + i + "" );
        }
    }

    @Override
    public int getCount() {
        return numbers.size();
    }

    @Override
    public Object getItem(int position) {
        return numbers.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        View view;
        viewHolder holder;
        if(convertView == null){
            view = View.inflate(parent.getContext(),R.layout.item_number_list,null);
            holder = new viewHolder();
            holder.ib_del = (ImageView) view.findViewById(R.id.ib_del);
            holder.tv_number = (TextView) view.findViewById(R.id.tv_numer);
            view.setTag(holder);
        }else{
            view = convertView;
            holder = (viewHolder)view.getTag();
        }
        holder.ib_del.setImageResource(R.mipmap.delete);
        holder.tv_number.setText(numbers.get(position));
        holder.ib_del.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                numbers.remove(position);
                notifyDataSetChanged();
            }
        });
        return view;
    }

    static class viewHolder{
         TextView tv_number;
         ImageView ib_del;
    }
}

 

     

      案例三 viewpager實現輪播圖:  
      功能介紹:  廣告條的實現,又被稱為輪播圖。在手機界面的最上方放置一個ViewPager功能,實現界面的左右滑動。滑動又分為兩種,一種是間隔一定的時間自動滑動,同時還支持手勢的左右滑動。一個小細節是在輪播圖底部放置和圖片數量相等的小點,用於表示當前哪個圖片被選中。
      實現步驟:
        1. 佈局文件有兩部分組成,一個是viewpager,一個是底部的條和小圓點。Viewpager存在於v4包下,因此可相容到Android1.6。底部的條和小圓點放在一個線性佈局中,讓放在viewpager的底部,同時文字和圓點為中心位置。這裡特別說一下小圓點的實現。小圓點使用shape圖做出來的。由於無法再佈局文件中獲取圓點的個數,因此可以在佈局文件中放置一個LinearLayout,然後在java代碼中將view對象向該LinearLayout中添加。同時將白點和黑點的狀態選擇器設置為view的背景。
        2. 接下來是viewpager的編寫。編寫viewpager的關鍵是寫適配器。寫一個類繼承PagerAdapter,重寫其中的方法。Viewpager預設是載入三張圖片,屏幕中間一張,屏幕左邊和屏幕右邊各一張。我們希望輪播圖能夠迴圈的播放,因此可以給getcount返回一個足夠大的值,初始化輪播圖時,將輪播圖的初始位置設置在中間,這樣就可以實現迴圈播放。當我們把getcount返回值設為一個很大的值時,在instantiateItem中也要對position進行判斷。傳入的的position是一個極大的值,但是圖片的數量確實有限的,因此可以對position取餘,這樣就可以把position的位置和圖片的數量對應起來。
        3. 實現自動播放需要用到消息機制,間隔三秒調用顯示下一張圖片的方法。顯示下一張圖片是調用viewpager的setCurrentItem,傳入下一個圖片的item數。手指滑動時viewpager自身就有的功能,因此不需要再定義。
        4. 最後要實現的功能是,viewpager底部的文字和小圓點跟隨圖片變化。這時候可以設定一個viewpager的監聽事件,當圖片發生改變時改變textview的值。然後遍歷linearlayout的子view(子view中存發的是小圓點),當圓點的序列號和圖片的序列號一直是,則選中圓點。當然,這裡同樣要對position取餘,將position轉化到於圖片大小一致的範圍。

      主界面的實現:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.advertisement.MainActivity">

    <android.support.v4.view.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="150dp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@id/view_pager"
        android:background="@color/trans_balck"
        android:gravity="center"
        android:orientation="vertical"
        android:padding="5dp">

        <TextView
            android:id="@+id/tv_desc"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="圖片描述"
            android:textColor="@android:color/white" />

        <LinearLayout
            android:id="@+id/ll_dots"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"></LinearLayout>
    </LinearLayout>
</RelativeLayout>

       狀態選擇器

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true" android:drawable="@drawable/shape_dot_select"/>
    <item android:drawable="@drawable/shape_dot_normal"/>
</selector>

       shape圖的繪製

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
  android:shape="oval">
     <solid android:color="@color/trans_balck"/>
</shape>

<節省空間, 兩個寫下一起>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
  android:shape="oval">
     <solid android:color="@android:color/white"/>
</shape>

       主程式中的業務邏輯

import android.os.Bundle;
import android.os.Handler;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private int[] imageResids = {R.drawable.a, R.drawable.b, R.drawable.c, R.drawable.d, R.drawable.e};
    private String[] desc = {
            "鞏俐不低俗,我就不能低俗",
            "撲樹又回來啦!再唱經典老歌引萬人大合唱",
            "揭秘北京電影如何升級",
            "樂視網TV版大派送",
            "熱血屌絲的反殺"
    };

    private LinearLayout ll_dots;
    private TextView tv_desc;
    private ViewPager viewpager;
    
              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在Android開發中,我們經常會需要在Android界面上彈出一些對話框,比如詢問用戶或者讓用戶選擇。這些功能我們叫它Android Dialog對話框,AlertDialog實現方法為建造者模式。下麵我們模擬卸載應用程式時彈出的最為普通的警告對話框,如下圖: layout佈局界面代碼示例: Ja ...
  • 作為開發者我們需要經常站在用戶角度考慮問題,比如在應用商城下載軟體時,當用戶點擊下載按鈕,則會有下載進度提示頁面出現,現在我們通過線程休眠的方式模擬下載進度更新的演示,如圖(這裡為了截圖方便設置對話進度條位於屏幕上方): layout界面代碼(僅部署一個按鈕): Java代碼實現(通過線程實現模擬下 ...
  • 最近隨視頻教程學習Android,原本都是用Adt寫Android程式,中途教程換成了Android Studio,於是我自己下了android studio 2.2.2安裝好,並下載好sdk,也跟著更換開發環境。 但教程並未講解如何將舊有的Eclipse項目導入到Android Studio(以下 ...
  • 在編寫xml文件時,為了預覽效果,經常會使用預設填上一些內容,比如TextView時,隨便寫上一個text 但是如果這個在實際發佈的時候忘記了刪除這個text,就有可能出現問題了 其實在Android Studio上,可以使用一個更加優雅和高效的方式,那就是使用tools屬性 首先添加tools的n ...
  • 寫一個計算的方法,計算1 + 2 。 面向對象,詮釋萬物皆對象思想。 思路: YGInteger.h YGInteger.m 中寫一個description方法,和 擴展中,將數字轉換成字元串的方法 YGInteger+YGInit.h 這是Integer的Init分類 YGInteger+YGIn ...
  • MobileCoreService這個系統的庫,裡面有個私有的類LSApplicationWorkspace ,利用運行時可以獲得私有類裡面的方法,- (id)allInstalledApplications; 該方法能夠獲得設備上所有的應用信息,包括系統的和用戶的應用 獲得的應用的信息是一個類對象 ...
  • 以下是關於記憶體管理的學習筆記:引用計數與ARC。 iOS5以前自動引用計數(ARC)是在MacOS X 10.7與iOS 5中引入一項新技術,用於代替之前的手工引用計數MRC(Manual Reference Counting)管理Objective-C中的對象【官方也叫MRR(Manual Ret ...
  • 首先,在drawable文件夾寫一個xml文件solid_c9c9c9.xml 1 <?xml version="1.0" encoding="utf-8"?> 2 <shape xmlns:android="http://schemas.android.com/apk/res/android"> ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...