自定義圖片輪播控制元件
自動輪播,手指滑動,點選回撥
效果圖:
ImageCycler
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.system.Os;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Scroller;
import android.widget.Toast;
/**
* 一個圖片輪播控制元件
* @author 1
*/
public class ImageCycler extends View {
/**
* 點選事件閥值
*/
private static final float CLICK_DISTANCE = 5;
/**
* 上層圖片索引,其值為 {@link #leftImgIndex} ,{@link #centerImgIndex} ,{@link #rightImgIndex}其中之一
*/
private int frontImgIndex = -1;
/**
* 下層圖片索引,其值為 {@link #leftImgIndex} ,{@link #centerImgIndex} ,{@link #rightImgIndex}其中之一
*/
private int backImgIndex = -1;
/**
* 輪播圖的左圖片
*/
private int leftImgIndex = 0;
/**
* 輪播圖的中間圖片
*/
private int centerImgIndex = 0;
/**
* 輪播圖的右圖片
*/
private int rightImgIndex = 0;
/**
* 用來存放輪播圖的圖片的集合
*/
//private List<Bitmap> imgs = new ArrayList<Bitmap>();
private Map<String,Bitmap> imgMap = new HashMap<String, Bitmap>();
/**
* 用來存放item圖片相關實體
*/
private List<ImageItem> imageItems = new ArrayList<ImageCycler.ImageItem>();
/**
* 圖片item點選回撥
*/
private ImageItemClickCallback itemClickCallback;
private Scroller scroller = new Scroller(getContext());
public ImageCycler(Context context) {
super(context);
init();
}
private void init() {
startScroll();
}
public ImageCycler(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
/**
* 初始化輪播圖的索引設定
*/
private void initImagesIndex() {
if(imgMap.size() < 1){
return;
}
if(frontImgIndex == -1){//第一次進行初始化設定
centerImgIndex = 0;
}
frontImgIndex = centerImgIndex;
leftImgIndex = centerImgIndex - 1;
if(leftImgIndex < 0){
leftImgIndex = imgMap.size() - 1;
}
rightImgIndex = centerImgIndex + 1;
if( rightImgIndex >= imgMap.size() ){
rightImgIndex = 0;
}
}
/**
* 設定圖片item點選回撥
* @return
*/
public void setItemClickCallback(ImageItemClickCallback itemClickCallback) {
this.itemClickCallback = itemClickCallback;
}
/**
* 獲取用來存放item圖片相關實體
*/
public List<ImageItem> getImageItems() {
return imageItems;
}
/**
* 設定用來存放item圖片相關實體
*/
public void setImageItems(List<? extends ImageItem> items) {
if(items == null){
return;
}
this.imageItems = (List<ImageItem>) items;
loadImage(this.imageItems);
}
ExecutorService threadPool ;
private void loadImage(List<ImageItem> items) {
if(threadPool == null){
int threadCount = Runtime.getRuntime().availableProcessors()*2;
threadPool = Executors.newSingleThreadExecutor();
}
for(int i = 0 ; i < items.size() ; i ++){
String urlPath = items.get(i).getImageUrl();
threadPool.execute(new ImageLoadRunnable(urlPath ));
}
}
float touchDownX;
float touchMoveX;
/**
* 自動輪播的滑動的X座標值,每次停止自動輪播時通過scroller.getCurrX()獲得其值,每次MotionEvent.ACTION_UP事件後清零
*/
int autoScrollX = 0;
boolean isInitImgIndexByOutOfLeftBounds = false;
boolean isInitImgIndexByOutOfRightBounds = false;
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
getParent().requestDisallowInterceptTouchEvent(true);
touchDownX = event.getX();
return true;
case MotionEvent.ACTION_MOVE:
if(imgMap.size() <= 1){
break;
}
touchMoveX = event.getX();
float distanceMove = touchMoveX - touchDownX;
if(Math.abs(distanceMove) <= CLICK_DISTANCE){//點選
break;
}
stopScroll();
if(distanceMove < 0){//左滑動
//向左滑動
drawX = getWidth() + distanceMove;
Log.v("test", "ACTION_MOVE 向左 autoScrollX = "+autoScrollX);
if(autoScrollX > 0){
drawX = drawX - (getWidth() - autoScrollX);
if(drawX < 0){
backImgIndex = centerImgIndex;
frontImgIndex = rightImgIndex ;
if(frontImgIndex >= imageItems.size()){
frontImgIndex = 0;
}
isInitImgIndexByOutOfLeftBounds = true;
//leftImgIndex = backImgIndex;
drawX = getWidth() + drawX;
}else if(isInitImgIndexByOutOfLeftBounds){
backImgIndex = leftImgIndex;
frontImgIndex = centerImgIndex;
isInitImgIndexByOutOfLeftBounds = false;
}
}else {
backImgIndex = centerImgIndex;
frontImgIndex = rightImgIndex;
}
Log.v("test", "ACTION_MOVE 向左 backImgIndex = "+backImgIndex+" frontImgIndex = "+frontImgIndex+" drawX = "+drawX);
Log.v("test", "ACTION_MOVE 向左 leftImgIndex = "+leftImgIndex+" centerImgIndex = "+centerImgIndex+" rightImgIndex = "+rightImgIndex);
}else {//右滑動
//向右滑動
drawX = distanceMove;//drawX + distanceMove;
if(autoScrollX > 0){
drawX = drawX + autoScrollX;
if(drawX > getWidth()){
frontImgIndex = leftImgIndex;
backImgIndex = leftImgIndex - 1;
if(backImgIndex < 0){
backImgIndex = imageItems.size()-1;
}
isInitImgIndexByOutOfRightBounds = true;
//rightImgIndex = centerImgIndex;
drawX = drawX - getWidth();
}else if(isInitImgIndexByOutOfRightBounds){
backImgIndex = leftImgIndex;
frontImgIndex = centerImgIndex;
isInitImgIndexByOutOfRightBounds = false;
}
}else {
backImgIndex = leftImgIndex;
frontImgIndex = centerImgIndex;
}
Log.v("test", "ACTION_MOVE 向右 backImgIndex = "+backImgIndex+" frontImgIndex = "+frontImgIndex+" drawX = "+drawX);
Log.v("test", "ACTION_MOVE 向右 leftImgIndex = "+leftImgIndex+" centerImgIndex = "+centerImgIndex+" rightImgIndex = "+rightImgIndex);
}
invalidate();
break;
case MotionEvent.ACTION_UP:
getParent().requestDisallowInterceptTouchEvent(false);
autoScrollX = 0;
if(imgMap.size() <= 1){
break;
}
float distanceUp = Math.abs(event.getX()-touchDownX);
//Log.d("test", "=== 距離 ="+distanceUp);
if(distanceUp <= CLICK_DISTANCE){
//點選行為
int clickPosition = 0;
if(itemClickCallback != null){
if(event.getX() < drawX){
//點選左圖片
clickPosition = backImgIndex;
}else {
//點選右圖片
clickPosition = frontImgIndex;
}
itemClickCallback.onItemClick(clickPosition, imageItems.get(clickPosition));
}
Log.d("test", "點選 event.getX()="+event.getX()+",drawX="+drawX+",backImgIndex="+backImgIndex+",frontImgIndex="+frontImgIndex+" ,clickPosition="+clickPosition);
break;
}
if(drawX <= getWidth()/2){
}else {
frontImgIndex = backImgIndex;
}
centerImgIndex = frontImgIndex;
leftImgIndex = centerImgIndex -1;
if(leftImgIndex < 0){
leftImgIndex = imgMap.size() - 1;
}
rightImgIndex = centerImgIndex + 1;
if(rightImgIndex >= imgMap.size()){
rightImgIndex = 0;
}
Log.d("test", "=== ACTION_UP preImgIndex="+leftImgIndex+" centerImgIndex="+centerImgIndex+" nextImgIndex="+rightImgIndex);
//drawX = 0;
scroller.startScroll((int)drawX, 0, -(int)drawX, 0);
invalidate();
Log.d("test", "=== ACTION_UP === event.getX()="+event.getX());
break;
default:
break;
}
return super.dispatchTouchEvent(event);
}
/**
* 下層圖片(左半邊圖片)和上層圖片(右半邊圖片)的分界點x座標;
* 其值為0時左圖片將不會繪製,空間全部繪製為右圖片
*/
float drawX = 0;
/**
* 還沒有下載完成時顯示的圖片
*/
private Bitmap loadingBitmap;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float radio = drawX/getWidth();
Paint paint = new Paint();
Bitmap b;
if(imgMap.size() < 1){
if(loadingBitmap == null){
loadingBitmap = getLoadingBitmap();
}
canvas.drawBitmap(loadingBitmap, new Matrix(), paint);
return;
}else if (imgMap.size() == 1) {
frontImgIndex = 0;
backImgIndex = -1;
drawX = 0;
//Log.d("test", "imgs.size() == 1");
}
//Log.d("test", "onDraw backImgIndex = "+backImgIndex+" frontImgIndex = "+frontImgIndex);
/*******************繪製下層圖片(左半邊圖片)******************/
if(backImgIndex != -1){
String urlKey = imageItems.get(backImgIndex).getImageUrl();
b = imgMap.get(urlKey);
if(b == null){
if(loadingBitmap == null){
loadingBitmap = getLoadingBitmap();
}
b = loadingBitmap;
}
if(b.getWidth() != getWidth() || b.getHeight() != getHeight()){
//boolean remove = imgMap.remove(key)
b = scaleBitmap(b,getWidth(),getHeight());
imgMap.put(urlKey, b);
}
if(drawX > getWidth()){
drawX = getWidth();
}
Rect src = new Rect(0, 0, (int) drawX, b.getHeight());
Rect dst = new Rect(0, 0, (int) drawX, getHeight());
canvas.drawBitmap(b, src, dst, paint);
}
/*******************繪製上層圖片(右半邊圖片)******************/
if(frontImgIndex != -1){
String urlKey = imageItems.get(frontImgIndex).getImageUrl();
b = imgMap.get(urlKey);
if(b == null){
if(loadingBitmap == null){
loadingBitmap = getLoadingBitmap();
}
b = loadingBitmap;
}
if(b.getWidth() != getWidth() || b.getHeight() != getHeight()){
//boolean remove = imgs.remove(b);
b = scaleBitmap(b,getWidth(),getHeight());
imgMap.put(urlKey, b);//imgs.add(frontImgIndex, b);
}
if(drawX < 0){
drawX = 0;
}
Rect s = new Rect((int) drawX, 0, b.getWidth(), b.getHeight());
Rect d = new Rect((int) drawX, 0, getWidth(), getHeight());
canvas.drawBitmap(b, s, d, paint);//canvas.drawBitmap(b, null , dst, paint );
}
/*******************繪製位置標示******************/
int radius = getWidth()/75;
int dotPadding = radius*2;
int startX = (getWidth() - ((imageItems.size())*radius*2+(imageItems.size()-2)*dotPadding))/2;
int dotY = getHeight() - 2 * radius;
for(int i = 0;i<imageItems.size();i++){
if(i == frontImgIndex){
paint.setColor(Color.RED);
}else {
paint.setColor(Color.YELLOW);
}
canvas.drawCircle(startX+i*(radius*2+dotPadding), dotY, radius, paint);
}
}
private Bitmap getLoadingBitmap() {
Bitmap b = Bitmap.createBitmap(getWidth(), getHeight(), Config.ALPHA_8);
Canvas canvas = new Canvas(b);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setTextSize(35);
paint.setColor(Color.RED);
paint.setTextAlign(Align.CENTER);
canvas.drawText("圖片下載中請稍等……", getWidth()/2, getHeight()/2, paint );
return b;
}
/**
* 根據指定的寬高縮放圖片
* @param b所要轉換的bitmap
* @param newWidth 指定圖片的新的寬
* @param newHeight 指定圖片的新的高
* @return 轉換成了指定寬高的bitmap
*/
private Bitmap scaleBitmap(Bitmap b, int newWidth, int newHeight) {
float scaleX = (float)newWidth/b.getWidth();
float scaleY = (float)newHeight/b.getHeight();
Log.v("test", "--- scaleX = "+scaleX+" scaleY = "+scaleY);
Matrix m = new Matrix();
m.postScale(scaleX, scaleY, b.getWidth()/2, b.getHeight()/2);
return Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), m , false);
}
public void startScroll(){
scroller.startScroll(getWidth(), 0, -getWidth(), 0, 7000);
backImgIndex = frontImgIndex;
frontImgIndex = rightImgIndex;
centerImgIndex = frontImgIndex;
leftImgIndex = centerImgIndex -1;
if(leftImgIndex < 0){
leftImgIndex = imageItems.size() - 1;
}
rightImgIndex = centerImgIndex + 1;
if(rightImgIndex >= imageItems.size()){
rightImgIndex = 0;
}
invalidate();
}
public void stopScroll(){
autoScrollX = scroller.getCurrX();
scroller.forceFinished(true);//.abortAnimation();//scroller.startScroll(getWidth(), 0, 0, 0, 1500);
Log.d("scroll", "---abortAnimation---" + scroller.getCurrX());
}
@Override
public void computeScroll() {
super.computeScroll();
if(scroller.computeScrollOffset()){
int scrollX = scroller.getCurrX();
drawX = scrollX;
//Log.d("scroll", "---computeScroll---"+scrollX );
postInvalidate();
if(scrollX == 0){
scroller.abortAnimation();
post(new Runnable() {
@Override
public void run() {
startScroll();
}
});
}
}
}
/****************************************內部類和介面************************************************/
/**
* 用來獲取圖片的url路徑
* @author 1
*/
public interface ImageItem{
/**
* 獲取圖片url
* @return
*/
public String getImageUrl();
}
/**
* 圖片item點選回撥
* @author 1
*/
public interface ImageItemClickCallback{
/**
* 圖片item點選回撥
* @param position 點選的item索引
* @param item 點選的item例項
*/
public void onItemClick(int position,ImageItem item);
}
private Bitmap defaultBitmap;
/**
* 用來下載網路圖片
*/
class ImageLoadRunnable implements Runnable{
private String path;
public ImageLoadRunnable(String urlPath) {
super();
this.path = urlPath;
}
@Override
public void run() {
try {
if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1){//android6.0以下版本
//Log.v("test", "android6.0以下版本");
loadBitmapByHttpClient();
}else {//android6.0及以上版本
//Log.v("test", "android6.0及以上版本");
loadBitmapByURLConnection();
}
initImagesIndex();
postInvalidate();
} catch (Exception e) {
if(defaultBitmap == null){
defaultBitmap = getDefaultBitmap();//BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
}
imgMap.put(path, defaultBitmap);
Log.e("test", " 圖片下載失敗 ---"+path);
e.printStackTrace();
}
}
/**
* 通過 HttpClient來載入圖片,用在android6.0以下系統版本
*/
private void loadBitmapByHttpClient() throws IOException,
ClientProtocolException {
InputStream is;
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(path);
HttpResponse respose = client.execute(get);
if(respose.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
HttpEntity entity = respose.getEntity();
is = entity.getContent();//.getInputStream();
Bitmap b = BitmapFactory.decodeStream(is);
if(b.getWidth() != getWidth() || b.getHeight() != getHeight()){
b = scaleBitmap(b,getWidth(),getHeight());
}
//imgs.add(b);
imgMap.put(path, b);
Log.d("test", " imgs.size() = "+imgMap.size());
Log.d("test", " 圖片下載完成 ");
}else {
if(defaultBitmap == null){
defaultBitmap = getDefaultBitmap();//BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
}
imgMap.put(path, defaultBitmap);
Log.e("test", " 圖片下載失敗 ==="+path);
}
}
/**
* 通過 HttpURLConnection來載入圖片,用在android6.0及以上系統版本
*/
private void loadBitmapByURLConnection() throws MalformedURLException,
IOException, ProtocolException {
URL url = new URL(path);
InputStream is;
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5 * 1000);
conn.setRequestMethod("GET");
if(conn.getResponseCode() == HttpURLConnection.HTTP_OK){
is = conn.getInputStream();
Bitmap b = BitmapFactory.decodeStream(is);
if(b.getWidth() != getWidth() || b.getHeight() != getHeight()){
b = scaleBitmap(b,getWidth(),getHeight());
}
//imgs.add(b);
imgMap.put(path, b);
Log.d("test", " imgs.size() = "+imgMap.size());
Log.d("test", " 圖片下載完成 ");
}else {
if(defaultBitmap == null){
defaultBitmap = getDefaultBitmap();//BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
}
imgMap.put(path, defaultBitmap);
Log.e("test", " 圖片下載失敗 ==="+path);
}
}
/**
* 獲得預設顯示圖片
* @return
*/
private Bitmap getDefaultBitmap() {
Bitmap b = Bitmap.createBitmap(getWidth(), getHeight(), Config.ALPHA_8);
Canvas canvas = new Canvas(b);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setTextSize(30);
paint.setColor(Color.RED);
paint.setTextAlign(Align.CENTER);
canvas.drawLine(0, 0, getWidth(), getHeight(), paint);
canvas.drawLine(0, getHeight(), getWidth(), 0, paint);
canvas.drawLine(0, 0, 0, getHeight(), paint);
canvas.drawLine(0, 0, getWidth(), 0, paint);
canvas.drawLine(0, getHeight(), getWidth(), getHeight(), paint);
canvas.drawLine(getWidth(), 0, getWidth(), getHeight(), paint);
canvas.drawText("暫無圖片", getWidth()/2, getHeight()/2, paint );
return b;
}
}
}
activity_image_cycler.xml
<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: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.cardviewexample.ImageCyclerActivity"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<com.example.cardviewexample.view.ImageCycler
android:id="@+id/ic"
android:layout_width="match_parent"
android:layout_height="140dp"
/><!-- android:background="#ee00ff" -->
</LinearLayout>
ImageCyclerActivity
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
import com.example.cardviewexample.view.ImageCycler;
import com.example.cardviewexample.view.ImageCycler.ImageItem;
import com.example.cardviewexample.view.ImageCycler.ImageItemClickCallback;
public class ImageCyclerActivity extends Activity {
private ImageCycler ic;
List<MyImageUrlItem> items = new ArrayList<MyImageUrlItem>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_cycler);
ic = (ImageCycler) findViewById(R.id.ic);
items.add(new MyImageUrlItem("http://images.99pet.com/InfoImages/wm600_450/ef48d0d8e8f64172a28b9451fc5a941d.jpg","小貓小狗"));
items.add(new MyImageUrlItem("http://h.hiphotos.bdimg.com/album/h%3D370%3Bq%3D90/sign=0f7b0e1aa7efce1bf52bcecd9f6a82e3/a08" +
"b87d6277f9e2f989c50e41f30e924b999f3b5.jpg","小鴨戴花"));
items.add(new MyImageUrlItem("","空空空"));
items.add(new MyImageUrlItem("http://p2.gexing.com/shaitu/20130222/2012/512760af66779.jpg","熊貓桌布"));
items.add(new MyImageUrlItem("http://pic1.nipic.com/2009-02-20/2009220135032130_2.jpg","風景"));
items.add(new MyImageUrlItem("http://pic.duowan.com/tx2/1205/201189276629/201189504837.jpg","憶江南"));//
ic.setImageItems(items);
ic.setItemClickCallback(new ImageItemClickCallback() {
@Override
public void onItemClick(int position, ImageItem item) {
MyImageUrlItem urlItem = (MyImageUrlItem) item;
Log.d("item", "Item.getDesc() = "+urlItem.getDesc());
Toast.makeText(getApplicationContext(), urlItem.getDesc(), 0).show();
}
});
}
class MyImageUrlItem implements ImageItem{
private String myUrl;
private String name;
public MyImageUrlItem(String url){
myUrl = url;
}
public MyImageUrlItem(String myUrl, String name) {
super();
this.myUrl = myUrl;
this.name = name;
}
public String getMyUrl() {
return myUrl;
}
public void setMyUrl(String myUrl) {
this.myUrl = myUrl;
}
@Override
public String getImageUrl() {
return myUrl;
}
public String getDesc(){
return name;
}
}
}
相關文章
- uniapp自定義卡片輪播圖APP
- 小程式輪播圖自定義指示器
- 自定義view————Banner輪播View
- 圖片輪播--純cssCSS
- app直播原始碼,Banner廣告圖片輪播控制元件APP原始碼控制元件
- carousel 輪播自定義進度條
- 文字輪播與圖片輪播?CSS 不在話下CSS
- GKCycleScrollView - 一個輕量級的自定義輪播圖元件View元件
- Android 和 iOS 圖片輪播AndroidiOS
- 造輪子之圖片輪播元件(swiper)元件
- Android常用控制元件-BannerView(無限輪播圖控制元件)Android控制元件View
- php短視訊原始碼,jQuery實現自定義輪播圖外掛PHP原始碼jQuery
- Android自定義控制元件之區域性圖片放大鏡–BiggerViewAndroid控制元件View
- Android自定義控制元件之區域性圖片放大鏡--BiggerViewAndroid控制元件View
- 實現簡單的輪播圖(單張圖片、多張圖片)
- 用原生js實現圖片輪播器JS
- jQuery輪播圖之上下輪播jQuery
- Vue富文字帶圖片修改圖片大小自定義選擇項自定義字型Vue自定義字型
- 輪播圖
- 6.自定義圖片剪下
- 一分鐘學會如何自定義小程式輪播圖(蜜雪冰城Demo)
- [外掛擴充套件]圖片輪播外掛套件
- 安卓之viewPager簡單用法圖片輪播安卓Viewpager
- JQuery實現圖片輪播無縫滾動jQuery
- 微信小程式------輪播圖------縱向輪播圖微信小程式
- vue輪播圖Vue
- Flutter輪播圖Flutter
- WebView自定義長按圖片功能WebView
- 手機直播原始碼,android 輪播圖自定製元件原始碼Android元件
- 自定義上傳圖片拼圖遊戲遊戲
- jQuery實現3D圖片輪播詳解jQuery3D
- 用原生JS實現 圖片輪播切換 功能JS
- 記一個JavaScript圖片輪播思路與程式碼JavaScript
- iOS自定義控制元件:自定義TableView、CollectionView空資料佔點陣圖iOS控制元件View
- Highcharts 實現自定義匯出圖片
- Typora中自定義命令上傳圖片
- Flutter 自定義列表以及本地圖片引用Flutter地圖
- 原生JS實現輪播圖--第一章圖片展示JS
- java學習---前端---使用JavaScript和jQuery實現圖片輪播圖前端JavaScriptjQuery