① 怎樣在android Menu item中使用自定義View
1.自定義屬性:attrs.xml
2.MenuItemView.java源碼:
package com.dandy.widget;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.StateListDrawable;
import android.graphics.drawable.shapes.RectShape;
import android.os.Build;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import com.lingyun.switchbutton.R;
/**
* 設置,菜單中的布局項
* 默認控制項是縱向居中顯示,所有paddingTop和paddingBottom在這沒有作用
* Created by dandy on 2016/4/14.
*/
public class MenuItemView extends View{
private static final String TAG = "MenuItemView";
/**默認是按下狀態的最小值**/
private static final long PRESSED_TIMEOUT = 10;
/**默認控制項距離邊界的大小**/
private static final int PADDING_DEFAULT = 18;
/**默認控制項的高**/
private static final int HEIGHT_DEFAULT = 50;
/**文字繪制時默認大小**/
private static final int TEXTSZIE_DEFAULT = 14;
/**尾部箭頭圖標大小**/
private static final int ARROW_SIZE = 13;
/***SwitchButton默認寬*/
private static final int SWITCHBUTTON_WIDTH = 50;
/***SwitchButton默認高*/
private static final int SWITCHBUTTON_HEIGHT = 28;
/**頭標**/
private Drawable headerDrawable;
/**頭標寬**/
private int headerDrawableWidth;
/**頭標高**/
private int headerDrawableHeight;
/**距離左邊緣的距離**/
private int paddingLeft;
/**距離右邊緣的距離**/
private int paddingRight;
/**繪制頭標時,畫布在Y軸的繪制偏移量**/
private float headerDrawableStartDrawY;
/**文字與圖片間的距離**/
private int drawablePadding = -1;
/**頭部文字提示**/
private String textHeader;
/**文字顏色**/
private int textHeaderColor = Color.parseColor("#5a5a5a");
/**文字大小**/
private int textSize = -1;
/**文字繪制時,畫布在Y軸的繪制偏移量**/
private float textStartDrawY;
/**繪制文字的畫筆**/
private Paint textPaint;
/** 尾部 > 圖片**/
private Drawable arrowDrawable;
/**尾部 > 大小**/
private int arrowSize = -1;
/** > 繪制的X軸偏移量**/
private float arrowStartDrawX;
/** > 繪制的Y軸偏移量**/
private float arrowStartDrawY;
/**footerDrawable != null 時,繪制的時候是否按照原圖片大小繪制**/
private boolean arrowWropToSelf = true;
/**尾部寬**/
private int arrowDrawableWidth;
/**尾部高**/
private int arrowDrawableHeight;
/**繪制arrow畫筆**/
private Paint arrowPaint;
/**arrowPaint 顏色**/
private int arrowColor = Color.parseColor("#5a5a5a");
private DisplayMetrics dm;
/*以下是繪制SwitchButton所用到的參數*/
private Style style = Style.CUSTOM_ITEM;
/**默認寬**/
private int switchButtonWidth = -1;
/**默認高**/
private int switchButtonHeight = -1;
private static final long DELAYDURATION = 10;
/**開啟顏色**/
private int onColor = Color.parseColor("#4ebb7f");
/**關閉顏色**/
private int offColor = Color.parseColor("#dadbda");
/**灰色帶顏色**/
private int areaColor = Color.parseColor("#dadbda");
/**手柄顏色**/
private int handlerColor = Color.parseColor("#ffffff");
/**邊框顏色**/
private int borderColor = offColor;
/**開關狀態**/
private boolean toggleOn = false;
/**邊框寬**/
private int borderWidth = 2;
/**縱軸中心**/
private float centerY;
/**按鈕水平方向開始、結束的位置**/
private float startX,endX;
/**手柄x軸方向最小、最大值**/
private float handlerMinX,handlerMaxX;
/**手柄大小**/
private int handlerSize;
/**手柄在x軸的坐標位置**/
private float handlerX;
/**關閉時內部灰色帶寬度**/
private float areaWidth;
/**是否使用動畫效果**/
private boolean animate = true;
/**是否默認處於打開狀態**/
private boolean defaultOn = true;
/**按鈕半徑**/
private float radius;
/**整個switchButton的區域**/
private RectF switchRectF = new RectF();
/**繪制switchButton的畫筆**/
private Paint switchPaint;
private OnToggleChangedListener mListener;
private Handler mHandler = new Handler();
private double currentDelay;
private float downX = 0;
/**switchButton在X軸繪制的偏移量**/
private float switchButtonDrawStartX;
/**switchButton在Y軸繪制的偏移量**/
private float switchButtonDrawStartY;
/**分割線,默認在底部繪制**/
private Drawable dividerr;
/**分割線繪制的寬**/
private int dividerWidth = 2;
/**是否需要繪制分割線**/
private boolean dividerVisibilty = true;
/**觸摸事件是否完成**/
private boolean touchDownEnd = false;
public MenuItemView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setup(attrs);
}
public MenuItemView(Context context, AttributeSet attrs) {
super(context, attrs);
setup(attrs);
}
/**
* 初始化控制項,獲取相關的控制項屬性
* @param attrs
*/
private void setup(AttributeSet attrs){
dm = Resources.getSystem().getDisplayMetrics();
TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.MenuItemView);
if(typedArray != null){
int count = typedArray.getIndexCount();
for(int i = 0;i < count;i++){
int attr = typedArray.getIndex(i);
switch (attr){
case R.styleable.MenuItemView_headerDrawable:
headerDrawable = typedArray.getDrawable(attr);
break;
case R.styleable.MenuItemView_drawPadding:
drawablePadding = typedArray.getDimensionPixelSize(attr,drawablePadding);
break;
case R.styleable.MenuItemView_textHeader:
textHeader = typedArray.getString(attr);
break;
case R.styleable.MenuItemView_textHeaderColor:
textHeaderColor = typedArray.getColor(attr, textHeaderColor);
break;
case R.styleable.MenuItemView_textSize:
textSize = typedArray.getDimensionPixelSize(attr, textSize);
break;
case R.styleable.MenuItemView_arrowDrawable:
arrowDrawable = typedArray.getDrawable(attr);
break;
case R.styleable.MenuItemView_arrowSize:
arrowSize = typedArray.getDimensionPixelSize(attr, arrowSize);
break;
case R.styleable.MenuItemView_arrowWropToSelf:
arrowWropToSelf = typedArray.getBoolean(attr, true);
break;
case R.styleable.MenuItemView_arrowColor:
arrowColor = typedArray.getColor(attr, arrowColor);
break;
case R.styleable.MenuItemView_onColor:
onColor = typedArray.getColor(attr, onColor);
break;
case R.styleable.MenuItemView_offColor:
borderColor = offColor = typedArray.getColor(attr,offColor);
break;
case R.styleable.MenuItemView_areaColor:
areaColor = typedArray.getColor(attr, areaColor);
break;
case R.styleable.MenuItemView_handlerColor:
handlerColor = typedArray.getColor(attr, handlerColor);
break;
case R.styleable.MenuItemView_bordeWidth:
borderWidth = typedArray.getColor(attr, borderWidth);
break;
case R.styleable.MenuItemView_animate:
animate = typedArray.getBoolean(attr, animate);
break;
case R.styleable.MenuItemView_defaultOn:
defaultOn = typedArray.getBoolean(attr, defaultOn);
break;
case R.styleable.MenuItemView_Style:
style = Style.getValue(typedArray.getInt(attr, Style.CUSTOM_ITEM.ordinal()));
break;
case R.styleable.MenuItemView_switchButtonWidth:
switchButtonWidth = typedArray.getDimensionPixelOffset(attr, switchButtonWidth);
break;
case R.styleable.MenuItemView_switchButtonHeight:
switchButtonHeight = typedArray.getDimensionPixelOffset(attr, switchButtonHeight);
break;
case R.styleable.MenuItemView_dividerr:
dividerr = typedArray.getDrawable(attr);
break;
case R.styleable.MenuItemView_dividerWidth:
dividerWidth = typedArray.getDimensionPixelOffset(attr,dividerWidth);
break;
case R.styleable.MenuItemView_dividerVisibilty:
dividerVisibilty = typedArray.getBoolean(attr,dividerVisibilty);
break;
}
}
typedArray.recycle();
}
② android removeView用法
直接給你上代碼吧,寫了我半個小時,經過了我的測試了的~
運行下就能看到結果了~關鍵的remove的時候有給你寫注釋~
布局的layout文件內容:
----------------------------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android=""
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:id="@+id/linearlayout">
<LinearLayout android:id="@+id/LinearLayout01"
android:layout_width="wrap_content" android:layout_height="wrap_content">
<Button android:layout_height="wrap_content" android:id="@+id/add"
android:text="Add" android:layout_width="100px"></Button>
<Button android:layout_height="wrap_content"
android:layout_width="100px" android:text="Remove" android:id="@+id/remove"></Button>
</LinearLayout>
<TextView android:id="@+id/TextView01" android:text="This is textView."
android:layout_width="fill_parent" android:gravity="center"
android:layout_height="50px"></TextView>
</LinearLayout>
----------------------------------------------------------------------------------
對應Activity的內容:
----------------------------------------------------------------------------------
package com.foxconn.dialog;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.LinearLayout;
public class DialogTest extends Activity implements OnClickListener {
private Button add_btn, remove_btn;
private LinearLayout linearLayout;
private int index = 0;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViews();
register();
}
private void register() {
add_btn.setOnClickListener(this);
remove_btn.setOnClickListener(this);
}
private void findViews() {
add_btn = (Button) findViewById(R.id.add);
remove_btn = (Button) findViewById(R.id.remove);
linearLayout = (LinearLayout) findViewById(R.id.linearlayout);
}
protected View createView() {
Button btn = new Button(this);
btn.setId(index++);
btn.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
btn.setText("aaaaaa" + index);
return btn;
}
private void removeView() {
//獲取linearlayout子view的個數
int count = linearLayout.getChildCount();
//研究整個LAYOUT布局,第0位的是含add和remove兩個button的layout
//第count-1個是那個文字被置中的textview
//因此,在remove的時候,只能操作的是0<location<count-1這個范圍的
//在執行每次remove時,我們從count-2的位置即textview上面的那個控制項開始刪除~
if (count - 2 > 0) {
//count-2>0用來判斷當前linearlayout子view數多於2個,即還有我們點add增加的button
linearLayout.removeViewAt(count - 2);
}
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.add:
linearLayout.addView(createView(), 1);
break;
case R.id.remove:
removeView();
break;
default:
break;
}
}
}
----------------------------------------------------------------------------------
③ Android 重學系列 View的繪制流程(六) 硬體渲染(上)
本文開始聊聊Android中的硬體渲染。如果跟著我的文章順序,從SF進程到App進程的繪制流程一直閱讀,我們到這里已經有了一定的基礎,可以試著進行橫向比對如Chrome瀏覽器渲染流程,看看軟體渲染,硬體渲染,SF合成都做了什麼程度的優化。
先讓我們回顧一下負責硬體渲染的主體對象ThreadedRenderer在整個繪制流程中做了哪幾個步驟。
在硬體渲染的過程中,有一個很核心的對象RenderNode,作為每一個View繪制的節點對象。
當每一次進行准備進行繪制的時候,都會雷打不動執行如下三個步驟:
如果遇到什麼問題歡迎來到 https://www.jianshu.com/p/c84bfa909810 下進行討論
實際上整個硬體渲染的設計還是比較龐大。因此本文先聊聊ThreadedRender整個體系中主要對象的構造以及相關的原理。
首先來認識下面幾個重要的對象有一個大體的印象。
在Java層中面向Framework中,只有這么多,下面是一一映射的簡圖。
能看到實際上RenderNode也會跟著View 樹的構建同時一起構建整個顯示層級。也是因此ThreadedRender也能以RenderNode為線索構建出一套和軟體渲染一樣的渲染流程。
僅僅這樣?如果只是這么簡單,知道我習慣的都知道,我喜歡把相關總結寫在最後。如果把總攬寫在正文開頭是因為設計比較繁多。因為我們如果以流水線的形式進行剖析容易造成迷失細節的困境。
讓我繼續介紹一下,在硬體渲染中native層的核心對象。
如下是一個思維導圖:
有這么一個大體印象後,就不容易迷失在源碼中。我們先來把這些對象的實例化以及上面列舉的ThreadedRenderer在ViewRootImpl中執行行為的順序和大家來聊聊其原理,先來看看ThreadedRenderer的實例化。
當發現mSurfaceHolder為空的時候會調用如下函數:
而這個方法則調用如下的方法對ThreadedRenderer進行創建:
文件:/ frameworks / base / core / java / android / view / ThreadedRenderer.java
能不能創建的了ThreadedRenderer則決定於全局配置。如果ro.kernel.qemu的配置為0,說明支持OpenGL 則可以直接返回true。如果qemu.gles為-1說明不支持OpenGL es返回false,只能使用軟體渲染。如果設置了qemu.gles並大於0,才能打開硬體渲染。
我們能看到ThreadedRenderer在初始化,做了三件事情:
關鍵是看1-3點中ThreadRenderer都做了什麼。
文件:/ frameworks / base / core / jni / android_view_ThreadedRenderer.cpp
能看到這里是直接實例化一個RootRenderNode對象,並把指針的地址直接返回。
能看到RootRenderNode繼承了RenderNode對象,並且保存一個JavaVM也就是我們所說的Java虛擬機對象,一個java進程全局只有一個。同時通過getForThread方法,獲取ThreadLocal中的Looper對象。這里實際上拿的就是UI線程的Looper。
在這個構造函數有一個mDisplayList十分重要,記住之後會頻繁出現。接著來看看RenderNode的頭文件:
文件:/ frameworks / base / libs / hwui / RenderNode.h
實際上我把幾個重要的對象留下來:
文件:/ frameworks / base / core / java / android / view / RenderNode.java
能看到很簡單,就是包裹一個native層的RenderNode返回一個Java層對應的對象開放Java層的操作API。
能看到這個過程生成了兩個對象:
這個對象實際上讓RenderProxy持有一個創建動畫上下文的工廠。RenderProxy可以通過ContextFactoryImpl為每一個RenderNode創建一個動畫執行對象的上下文AnimationContextBridge。
文件:/ frameworks / base / libs / hwui / renderthread / RenderProxy.cpp
在這里有幾個十分重要的對象被實例化,當然這幾個對象在聊TextureView有聊過( SurfaceView和TextureView 源碼淺析 ):
我們依次看看他們初始化都做了什麼。
文件:/ frameworks / base / libs / hwui / renderthread / RenderThread.cpp
能看到其實就是簡單的調用RenderThread的構造函數進行實例化,並且返回對象的指針。
RenderThread是一個線程對象。先來看看其頭文件繼承的對象:
文件:/ frameworks / base / libs / hwui / renderthread / RenderThread.h
其中RenderThread的中進行排隊處理的任務隊列實際上是來自ThreadBase的WorkQueue對象。
文件:/ frameworks / base / libs / hwui / thread / ThreadBase.h
ThreadBase則是繼承於Thread對象。當調用start方法時候其實就是調用Thread的run方法啟動線程。
另一個更加關鍵的對象,就是實例化一個Looper對象到WorkQueue中。而直接實例化Looper實際上就是新建一個Looper。但是這個Looper並沒有獲取當先線程的Looper,這個Looper做什麼的呢?下文就會揭曉。
WorkQueue把一個Looper的方法指針設置到其中,其作用可能是完成了某一件任務後喚醒Looper繼續工作。
而start方法會啟動Thread的run方法。而run方法最終會走到threadLoop方法中,至於是怎麼走進來的,之後有機會會解剖虛擬機的源碼線程篇章進行講解。
在threadloop中關鍵的步驟有如下四個:
在這個過程中創建了幾個核心對象:
另一個核心的方法就是,這個方法為WorkQueue的Looper注冊了監聽:
能看到在這個Looper中注冊了對DisplayEventReceiver的監聽,也就是Vsync信號的監聽,回調方法為displayEventReceiverCallback。
我們暫時先對RenderThread的方法探索到這里,我們稍後繼續看看回調後的邏輯。
文件:/ frameworks / base / libs / hwui / thread / ThreadBase.h
能看到這里的邏輯很簡單實際上就是調用Looper的pollOnce方法,阻塞Looper中的循環,直到Vsync的信號到來才會繼續往下執行。詳細的可以閱讀我寫的 Handler與相關系統調用的剖析 系列文章。
文件:/ frameworks / base / libs / hwui / thread / ThreadBase.h
實際上調用的是WorkQueue的process方法。
文件:/ frameworks / base / libs / hwui / thread / WorkQueue.h
能看到這個過程中很簡單,幾乎和Message的loop的邏輯一致。如果Looper的阻塞打開了,則首先找到預計執行時間比當前時刻都大的WorkItem。並且從mWorkQueue移除,最後添加到toProcess中,並且執行每一個WorkItem的work方法。而每一個WorkItem其實就是通過從某一個壓入方法添加到mWorkQueue中。
到這里,我們就明白了RenderThread中是如何消費渲染任務的。那麼這些渲染任務又是哪裡誕生呢?
上文聊到了在RenderThread中的Looper會監聽Vsync信號,當信號回調後將會執行下面的回調。
能看到這個方法的核心實際上就是調用drainDisplayEventQueue方法,對ui渲染任務隊列進行處理。
能到在這里mVsyncRequested設置為false,且mFrameCallbackTaskPending將會設置為true,並且調用queue的postAt的方法執行ui渲染方法。
還記得queue實際是是指WorkQueue,而WorkQueue的postAt方法實際實現如下:
/ frameworks / base / libs / hwui / thread / WorkQueue.h
情景帶入,當一個Vsync信號達到Looper的監聽者,此時就會通過WorkQueue的drainDisplayEventQueue 壓入一個任務到隊列中。
每一個默認的任務都是執行dispatchFrameCallback方法。這里的判斷mWorkQueue中是否存在比當前時間更遲的時刻,並返回這個WorkItem。如果這個對象在頭部needsWakeup為true,說明可以進行喚醒了。而mWakeFunc這個方法指針就是上面傳下來:
把阻塞的Looper喚醒。當喚醒後就繼續執行WorkQueue的process方法。也就是執行dispatchFrameCallbacks方法。
在這里執行了兩個事情:
先添加到集合中,在上面提到過的threadLoop中,會執行如下邏輯:
如果大小不為0,則的把中的IFrameCallback全部遷移到mFrameCallbacks中。
而這個方法什麼時候調用呢?稍後就會介紹。其實這部分的邏輯在TextureView的解析中提到過。
接下來將會初始化一個重要對象:
這個對象名字叫做畫布的上下文,具體是什麼上下文呢?我們現在就來看看其實例化方法。
文件:/ frameworks / base / libs / hwui / renderthread / CanvasContext.cpp
文件:/ device / generic / goldfish / init.ranchu.rc
在init.rc中默認是opengl,那麼我們就來看看下面的邏輯:
首先實例化一個OpenGLPipeline管道,接著OpenGLPipeline作為參數實例化CanvasContext。
文件:/ frameworks / base / libs / hwui / renderthread / OpenGLPipeline.cpp
能看到在OpenGLPipeline中,實際上就是存儲了RenderThread對象,以及RenderThread中的mEglManager。透過OpenGLPipeline來控制mEglManager進而進一步操作OpenGL。
做了如下操作:
文件:/ frameworks / base / libs / hwui / renderstate / RenderState.cpp
文件:/ frameworks / base / libs / hwui / renderthread / DrawFrameTask.cpp
實際上就是保存這三對象RenderThread;CanvasContext;RenderNode。
文件:/ frameworks / base / core / jni / android_view_ThreadedRenderer.cpp
能看到實際上就是調用RenderProxy的setName方法給當前硬體渲染對象設置名字。
文件:/ frameworks / base / libs / hwui / renderthread / RenderProxy.cpp
能看到在setName方法中,實際上就是調用RenderThread的WorkQueue,把一個任務隊列設置進去,並且調用runSync執行。
能看到這個方法實際上也是調用post執行排隊執行任務,不同的是,這里使用了線程的Future方式,阻塞了執行,等待CanvasContext的setName工作完畢。
④ android.support.v4.view.pagertabstrip什麼意思
PagerTabStrip這個控制項現在很少使用了,現在都是使用viewpager+tablayout,下面是這兩個配合的效果:
android學習手冊包含9個章節,108個例子,源碼文檔隨便看,例子都是可交互,可運行,源碼採用android studio目錄結構,高亮顯示代碼,文檔都採用文檔結構圖顯示,可以快速定位。360手機助手中下載
PagerTabStrip是ViewPager的一個關於當前頁面、上一個頁面和下一個頁面的一個非交互的指示器。它經常作為ViewPager控制項的一個子控制項被被添加在XML布局文件中。在你的布局文件中,將它作為子控制項添加在ViewPager中。而且要將它的 android:layout_gravity 屬性設置為TOP或BOTTOM來將它顯示在ViewPager的頂部或底部。每個頁面的標題是通過適配器的getPageTitle(int)函數提供給ViewPager的。
1、XML布局文件:
[html] view plain print?
<RelativeLayoutxmlns: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"
tools:context="com.example.testviewpage_2.MainActivity">
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="wrap_content"
android:layout_height="200dip"
android:layout_gravity="center">
<android.support.v4.view.PagerTitleStrip
android:id="@+id/pagertitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top"
/>
</android.support.v4.view.ViewPager>
</RelativeLayout>
<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"
tools:context="com.example.testviewpage_2.MainActivity" >
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="wrap_content"
android:layout_height="200dip"
android:layout_gravity="center">
<android.support.v4.view.PagerTitleStrip
android:id="@+id/pagertitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top"
/>
</android.support.v4.view.ViewPager>
</RelativeLayout>
清楚的看到我們將.PagerTitleStrip將其作為ViewPager的子控制項直接嵌入其中;這是第一步;當然android:layout_gravity=""的值要設置為top或bottom。將標題欄顯示在頂部或底部。
2、重寫適配器的getPageTitle()函數
便於大家有個整體認識,先貼全局代碼,然後再逐個講,這段代碼是在《ViewPager 詳解(二)---詳解四大函數》直接更改來的,如果不太明白,先看看這篇文章。
[java] view plain print?
packagecom.example.testviewpage_2;
/**
*@authorharvic
*@date2014.8.12
*/
importjava.util.ArrayList;
importjava.util.List;
importandroid.app.Activity;
importandroid.os.Bundle;
importandroid.support.v4.view.PagerAdapter;
importandroid.support.v4.view.PagerTitleStrip;
importandroid.support.v4.view.ViewPager;
importandroid.view.LayoutInflater;
importandroid.view.View;
importandroid.view.ViewGroup;
{
privateViewview1,view2,view3;
privateList<View>viewList;//view數組
privateViewPagerviewPager;//對應的viewPager
privateList<String>titleList;//標題列表數組
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager=(ViewPager)findViewById(R.id.viewpager);
LayoutInflaterinflater=getLayoutInflater();
view1=inflater.inflate(R.layout.layout1,null);
view2=inflater.inflate(R.layout.layout2,null);
view3=inflater.inflate(R.layout.layout3,null);
viewList=newArrayList<View>();//將要分頁顯示的View裝入數組中
viewList.add(view1);
viewList.add(view2);
viewList.add(view3);
titleList=newArrayList<String>();//每個頁面的Title數據
titleList.add("王鵬");
titleList.add("姜語");
titleList.add("結婚");
PagerAdapterpagerAdapter=newPagerAdapter(){
@Override
publicbooleanisViewFromObject(Viewarg0,Objectarg1){
//TODOAuto-generatedmethodstub
//根據傳來的key,找到view,判斷與傳來的參數Viewarg0是不是同一個視圖
returnarg0==viewList.get((int)Integer.parseInt(arg1.toString()));
}
@Override
publicintgetCount(){
//TODOAuto-generatedmethodstub
returnviewList.size();
}
@Override
publicvoiddestroyItem(ViewGroupcontainer,intposition,
Objectobject){
//TODOAuto-generatedmethodstub
container.removeView(viewList.get(position));
}
@Override
publicObjectinstantiateItem(ViewGroupcontainer,intposition){
//TODOAuto-generatedmethodstub
container.addView(viewList.get(position));
//把當前新增視圖的位置(position)作為Key傳過去
returnposition;
}
@Override
(intposition){
//TODOAuto-generatedmethodstub
returntitleList.get(position);
}
};
viewPager.setAdapter(pagerAdapter);
}
}
⑤ 如何通過View對象復制一個一模一樣的View
RZCellSizeManager,除了使用systemLayoutSizeFittingSize:外,還支持高度的緩存等vip功能。對於復雜的動態cell,性能提升比較明顯。該庫僅支持iOS7.x、8.x,慎入。 題主的問題2:cell中數量不確定的多張imageView該如何處理
⑥ android中,怎樣實現textView長按出現復制,出現復制、轉發按鈕
實現textiew長按事件,按鍵區事先定義,平時隱藏,長按時顯示即可
⑦ android如何深度克隆View對象
用java的反射,試試
⑧ Android textView 復制問題
方法一:在布局文件的TextView控制項屬性中增加一句:android:textIsSelectable="true"
方法二:直接上代碼
<LinearLayout 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" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center" >
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="60dp"
android:background="#80FF00"
android:gravity="center"
android:text="長按此處跳出復制選框"
android:textColor="#000000" />
</LinearLayout>
</LinearLayout>
package com.example.test;
import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.text.ClipboardManager;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private TextView tv;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.tv);
tv.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View arg0) {
test();
return false;
}
});
}
public Dialog test() {
Dialog dialog = new AlertDialog.Builder(this).setTitle("提示")
.setNegativeButton("取消", null)
.setItems(new String[] { "復制" }, new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
String string = tv.getText().toString();
(string, getBaseContext());
Toast.makeText(getBaseContext(), "文本已復制到粘貼板", 2000)
.show();
}
}).create();
dialog.setCanceledOnTouchOutside(false);
dialog.show();
return dialog;
}
public static void (String content, Context context) {
// 得到剪貼板管理器
ClipboardManager cmb = (ClipboardManager) context
.getSystemService(Context.CLIPBOARD_SERVICE);
cmb.setText(content.trim());
}
}