2018-04-09 10:00:00 MiHomes 阅读数 688
  • Android底层技术:Linux驱动框架与开发

    于此,将框架(Framework)和设计模式(Design Pattern)应用于Linux驱动开发,说明了如何以面向对象、设计模式和框架概念来看待Linux驱动程序的架构。其直接的益处就是:让我们能基于一致的设计理念来结合Android HAL与Linux两层的驱动开发,规划出整体和谐Android-based软硬整合产品架构。

    22366 人正在学习 去看看 高煥堂

本文已同步更新至个人简书账号:https://www.jianshu.com/p/d1ec5825f42b


一.这个功能相信每个小伙伴都会遇到,话不多说,直接上效果图(花屏是录屏软件的原因)与步骤,以供小伙伴们参考。


嘿嘿嘿!.gif

1.依赖:

//图片选择器
compile 'com.jph.takephoto:takephoto_library:4.0.3'
//仿iOS的AlertViewController
compile 'com.bigkoo:alertview:1.0.3'
//最新版本Glide
compile 'com.github.bumptech.glide:glide:3.7.0'
//design中包含的RecycleView
compile 'com.android.support:design:25.3.1'
//ButterKnife
compile 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
//photoView 图片放大控件
compile 'com.github.chrisbanes:PhotoView:1.3.0'

2.xml文件布局:

      <android.support.v7.widget.RecyclerView
        android:id="@+id/recycleview_check"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        ></android.support.v7.widget.RecyclerView>

3.当前Activity中初始化代码:

    RecycleView recyCheck =(Recycleview)findViewById(R.id.recycleview_check);
    //设置展示框中单行展示的图片个数
    recyCheck.setLayoutManager(new GridLayoutManager(this, 5));
    //初始化自定义Adapter,onAddPicListener是添加图片的点击监听器,onPicClickListener是添加图片成功以后,点击放大的监听器。
    photoAdapter = new PhotoAdapter(this, onAddPicListener, onPicClickListener);
    //设置多选时最多选择的图片张数
    photoAdapter.setSelectMax(5);
    recyCheck.setAdapter(photoAdapter);

其中,PhotoAdapter代码如下:

public class PhotoAdapter extends
    RecyclerView.Adapter<PhotoAdapter.ViewHolder> {

private int selectMax = 3;
public final int TYPE_CAMERA = 1;
public final int TYPE_PICTURE = 2;

private Context mContext;
private LayoutInflater mInflater;
private List<TImage> list = new ArrayList<>();


//点击添加图片跳转
private onAddPicListener mOnAddPicListener;

public interface onAddPicListener {
    void onAddPicClick(int type, int position);
}

//点击图片放大
private onPicClickListener mOnPicClickListener;

public interface onPicClickListener {
    void onPicClick(View view, int position);
}

public PhotoAdapter(Context context, onAddPicListener mOnAddPicListener, onPicClickListener mOnPicClickListener) {
    mInflater = LayoutInflater.from(context);
    this.mContext = context;
    this.mOnAddPicListener = mOnAddPicListener;
    this.mOnPicClickListener = mOnPicClickListener;
}

public void setSelectMax(int selectMax) {
    this.selectMax = selectMax;
}

public void setList(List<TImage> list) {
    this.list = list;
}

public class ViewHolder extends RecyclerView.ViewHolder {

    ImageView mPhoto_image;
    ImageView mPhoto_del;

    public ViewHolder(View view) {
        super(view);
        mPhoto_image = (ImageView) view.findViewById(R.id.photo_image);
        mPhoto_del = (ImageView) view.findViewById(R.id.photo_del);
    }
}

@Override
public int getItemCount() {
    if (list.size() < selectMax) {
        return list.size() + 1;
    } else {
        return list.size();
    }
}

@Override
public int getItemViewType(int position) {
    if (isShowAddItem(position)) {
        return TYPE_CAMERA;
    } else {
        return TYPE_PICTURE;
    }
}

/**
 * 创建ViewHolder
 */
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
    View view = mInflater.inflate(R.layout.activity_photo_item,
            viewGroup, false);
    final ViewHolder viewHolder = new ViewHolder(view);

    return viewHolder;
}

private boolean isShowAddItem(int position) {
    int size = list.size() == 0 ? 0 : list.size();
    return position == size;
}

/**
 * 设置值
 */
@Override
public void onBindViewHolder(final ViewHolder viewHolder, final int position) {
    //少于3张,显示继续添加的图标
    Log.d("...", "onBindViewHolder: " + position);
    if (getItemViewType(position) == TYPE_CAMERA) {
        //设置添加按钮图片的样式
        viewHolder.mPhoto_image.setImageResource(R.mipmap.icon_addpic);
        viewHolder.mPhoto_image.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mOnAddPicListener.onAddPicClick(0, viewHolder.getAdapterPosition());
            }
        });
        viewHolder.mPhoto_del.setVisibility(View.INVISIBLE);
    } else {
        viewHolder.mPhoto_del.setVisibility(View.VISIBLE);
        viewHolder.mPhoto_image.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mOnPicClickListener.onPicClick(view, viewHolder.getAdapterPosition());
            }
        });
        viewHolder.mPhoto_del.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mOnAddPicListener.onAddPicClick(1, viewHolder.getAdapterPosition());
            }
        });

        Glide.with(mContext)
                .load(list.get(position).getCompressPath())
                .crossFade()
                .into(viewHolder.mPhoto_image);
    }
  }  
}

PhotoAdapter中所依赖的xml文件如下:

  <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerInParent="true">
<ImageView
    android:id="@+id/photo_image"
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:scaleType="centerCrop"
    android:src="@color/image_color" />

<ImageView
    android:id="@+id/photo_del"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="right|top"
    android:scaleType="center"
    android:src="@mipmap/icon_delete" />
</FrameLayout>

添加图片的点击监听器onAddPicListener 代码及所调用方法如下:

private List<TImage> selectMedia = new ArrayList<>();
private List<TImage> updateMedia = new ArrayList<>();
ArrayList<String> imageUrls = new ArrayList<>();
private List<String> internetUrls = new ArrayList<>();
private PhotoAdapter.onAddPicListener onAddPicListener = new PhotoAdapter.onAddPicListener() {
    @Override
    public void onAddPicClick(int type, int position) {
        switch (type) {
            case 0: //点击图片
                new AlertView("上传图片", null, "取消", null,
                        new String[]{"拍照", "从相册中选择"},
                        MainActivity.this, AlertView.Style.ActionSheet, new OnItemClickListener() {
                    @Override
                    public void onItemClick(Object o, int position) {
                        TakePhoto takePhoto = getTakePhoto();
                        //获取TakePhoto图片路径
                        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                             d(TAG, "SD卡可用");

                            File file = new File(Environment.getExternalStorageDirectory(), "/photo/" + System.currentTimeMillis() + ".jpg");
                            if (!file.getParentFile().exists()) file.getParentFile().mkdirs();
                            Uri imageUri = Uri.fromFile(file);
                            d(TAG, "文件创建成功并获取URL == " + imageUri);
                            //设置takephoto的照片使用压缩
                            configCompress(takePhoto);
                            //设置Takephoto 使用TakePhoto自带的相册   照片旋转角度纠正
                            configTakePhotoOption(takePhoto);
                            switch (position) {
                                case 0:  //拍照
                                    takePhoto.onPickFromCapture(imageUri);
                                    break;
                                case 1:  //相册选择
                                    //如果已展示图片的个数为0,就设置多选时最多选中3张
                                    if (selectMedia.size() == 0) { 
                                        takePhoto.onPickMultiple(3);
                                    //如果已展示图片的个数为1,就设置多选时最多选中2张
                                    } else if (selectMedia.size() == 1) {
                                        takePhoto.onPickMultiple(2);
                                   //如果已展示图片的个数为2,就设置多选时最多选中1张
                                    } else if (selectMedia.size() == 2) {
                                        takePhoto.onPickMultiple(1);
                                    }
                                    break;
                            }
                        } else {
                            Log.d(TAG, "SD卡bu可用");
                        }

                    }
                }).show();
                break;
            case 1:  //点击删除按钮
                
                    selectMedia.remove(position);
                    photoAdapter.notifyItemRemoved(position);
                    internetUrls.remove(position);

                break;
        }
    }
};
//设置Takephoto 使用TakePhoto自带的相册   照片旋转角度纠正
private void configTakePhotoOption(TakePhoto takePhoto) {
    TakePhotoOptions.Builder builder = new TakePhotoOptions.Builder();
    builder.setWithOwnGallery(true);
    builder.setCorrectImage(true);
    takePhoto.setTakePhotoOptions(builder.create());
}

//设置takephoto的照片使用压缩
private void configCompress(TakePhoto takePhoto) {
    CompressConfig config;
    config = new CompressConfig.Builder()
            .setMaxSize(102400)
            .setMaxPixel(800)
            .enableReserveRaw(true)
            .create();
    takePhoto.onEnableCompress(config, false);
}
/**
 * 获取TakePhoto实例
 * 没有继承TakePhotoActivity 所写
 */
public TakePhoto getTakePhoto() {
    if (takePhoto == null) {
        takePhoto = (TakePhoto) TakePhotoInvocationHandler.of(this).bind(new TakePhotoImpl(this, this));
    }
    return takePhoto;
}

getTakePhoto中会报错,此时,我们让当前Activity实现InvokeListener与TakePhoto.TakeResultListener接口,重写invoke与方法,重写以下方法代码如下:


image.png
@Override
public void takeCancel() {
    Log.d(TAG, "takeCancel");
}

@Override
public void takeFail(TResult result, String msg) {
    ArrayList<TImage> images = result.getImages();
    showImg(result.getImages());
    Log.d(TAG, "takeFail" + images.get(0).toString());
}

@Override
public void takeSuccess(TResult result) {
    showImg(result.getImages());
}

//没有继承TakePhotoActivity 所写
@Override
protected void onSaveInstanceState(Bundle outState) {
    getTakePhoto().onSaveInstanceState(outState);
    super.onSaveInstanceState(outState);
}

//没有继承TakePhotoActivity 所写
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    PermissionManager.TPermissionType type = PermissionManager.onRequestPermissionsResult(requestCode, permissions, grantResults);
    PermissionManager.handlePermissionsResult(this, type, invokeParam, this);
}

//没有继承TakePhotoActivity 所写
@Override
public PermissionManager.TPermissionType invoke(InvokeParam invokeParam) {
    PermissionManager.TPermissionType type = PermissionManager.checkPermission(TContextWrap.of(this), invokeParam.getMethod());
    if (PermissionManager.TPermissionType.WAIT.equals(type)) {
        this.invokeParam = invokeParam;
    }
    return type;
}


//图片成功后返回执行的方法
private void showImg(ArrayList<TImage> images) {
    Log.d(TAG, images.toString());
    //目的是防止上传重复的图片
    updateMedia.clear();

    for (int i = 0; i < images.size(); i++) {
        if (images.get(i).getCompressPath() != null) {
            selectMedia.add(images.get(i));
            updateMedia.add(images.get(i));
        }
    }
    if (selectMedia != null) {
        photoAdapter.setList(selectMedia);
        photoAdapter.notifyDataSetChanged();
    }
    //需上传图片,请使用用updateMedia数组。
}

回过头来看,既然照相肯定有回调,我们应当在当前Activity中重写回调方法,并交给takePhoto来操作

   //没有继承TakePhotoActivity 所写
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    //将拍照返回的结果交给takePhoto处理
    getTakePhoto().onActivityResult(requestCode, resultCode, data);
    super.onActivityResult(requestCode, resultCode, data);
}

图片点击放大监听器onPicClickListener代码如下:

 //图片点击事件
private PhotoAdapter.onPicClickListener onPicClickListener = new PhotoAdapter.onPicClickListener() {
    @Override
    public void onPicClick(View view, int position) {
        imageUrls.clear();
        for (int i = 0; i < selectMedia.size(); i++) {
            String compressPath = selectMedia.get(i).getCompressPath();
            imageUrls.add(compressPath);
        }
        imageBrower(position, imageUrls);
    }
};
 private void imageBrower(int position, ArrayList<String> imageUrls) {
    Intent intent = new Intent(this, ImagePagerActivity.class);
    intent.putExtra(ImagePagerActivity.EXTRA_IMAGE_URLS, imageUrls);
    intent.putExtra(ImagePagerActivity.EXTRA_IMAGE_INDEX, position);
    startActivity(intent);
}

我们可以看到,图片点击以后跳转到了另一个Activity,这个Activity就是我们专门用来放大图片的Activity了,使用的方法很简单,传入需要展示的图片数组和你点击的图片索引,就会自动选中对应的图片进行展示并具备左右滑动切换图片的效果,代码如下(可当作工具类使用,应用于项目各个需要展示图片数组的位置,调用imageBrower方法即可):

public class ImagePagerActivity extends FragmentActivity {
private static final String STATE_POSITION = "STATE_POSITION";
public static final String EXTRA_IMAGE_INDEX = "image_index";
public static final String EXTRA_IMAGE_URLS = "image_urls";

@BindView(R.id.indicator)
TextView indicator;
@BindView(R.id.pager)
HackyViewPager pager;

private int pagerPosition;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.image_detail_pager);
    ButterKnife.bind(this);
    MyUtils.setSystemColor(this,R.color.bg_shouye);

    pagerPosition = getIntent().getIntExtra(EXTRA_IMAGE_INDEX, 0);
    ArrayList<String> urls = getIntent().getStringArrayListExtra(EXTRA_IMAGE_URLS);
    ImagePagerAdapter mAdapter = new ImagePagerAdapter(getSupportFragmentManager(), urls);
    pager.setAdapter(mAdapter);
    CharSequence text = getString(R.string.viewpager_indicator, 1, pager.getAdapter().getCount());
    indicator.setText(text);
    // 更新下标
    pager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrollStateChanged(int arg0) {
        }

        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
        }

        @Override
        public void onPageSelected(int arg0) {
            CharSequence text = getString(R.string.viewpager_indicator, arg0 + 1, pager.getAdapter().getCount());
            indicator.setText(text);
        }
    });
    if (savedInstanceState != null) {
        pagerPosition = savedInstanceState.getInt(STATE_POSITION);
    }
    pager.setCurrentItem(pagerPosition);

}

@Override
protected void onSaveInstanceState(Bundle outState) {
    outState.putInt(STATE_POSITION, pager.getCurrentItem());
}

private class ImagePagerAdapter extends FragmentStatePagerAdapter {
    public ArrayList<String> fileList;

    public ImagePagerAdapter(FragmentManager fm, ArrayList<String> fileList) {
        super(fm);
        this.fileList = fileList;
    }

    @Override
    public int getCount() {
        return fileList == null ? 0 : fileList.size();
    }

    @Override
    public Fragment getItem(int position) {
        String url = fileList.get(position);
        return ImageDetailFragment.newInstance(url);
    }
  }
}

ImagePagerActivity 对应的xml文件如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/bg_shouye"
>

<com.mihomes.checkphotodemo.HackyViewPager
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/black" />

<TextView
    android:id="@+id/indicator"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom"
    android:background="@android:color/transparent"
    android:gravity="center"
    android:text="@string/viewpager_indicator"
    android:textColor="@android:color/white"
    android:textSize="18sp" />
</LinearLayout>

HackyViewPager是一个重写了ViewPager的自定义类,解决了PhotoView和ViewPager的滑动冲突,代码如下:

public class HackyViewPager extends ViewPager {
  private static final String TAG = "HackyViewPager";
  public HackyViewPager(Context context) {
    super(context);
}

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

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    try {
        return super.onInterceptTouchEvent(ev);
    } catch (IllegalArgumentException e) { // 不理会
        Log.e(TAG, "hacky viewpager error1");
        return false;
    } catch (ArrayIndexOutOfBoundsException e) {
        // 不理会
        Log.e(TAG, "hacky viewpager error2");
        return false;
    }
  }
}

同时,ImagePagerActivity中所引用的ImageDetailFragment代码如下:

public class ImageDetailFragment extends Fragment {
private static final String TAG = "ImageDetailFragment";
private String mImageUrl;
private PhotoView mImageView;
private ProgressBar progressBar;
private PhotoViewAttacher mAttacher;
private Dialog dialog;
private Button save;
private Button saveCancel;
public static ImageDetailFragment newInstance(String imageUrl) {
    final ImageDetailFragment f = new ImageDetailFragment();
    final Bundle args = new Bundle();
    args.putString("url", imageUrl);
    f.setArguments(args);
    return f;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mImageUrl = getArguments() != null ? getArguments().getString("url") : null;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.image_detail_fragment, container, false);
    mImageView = (PhotoView) v.findViewById(R.id.maxphoto_image);
    mAttacher = new PhotoViewAttacher(mImageView);
    mAttacher.setOnPhotoTapListener(new PhotoViewAttacher.OnPhotoTapListener() {
        @Override
        public void onPhotoTap(View arg0, float arg1, float arg2) {
            getActivity().finish();
        }

        @Override
        public void onOutsidePhotoTap() {

        }
    });

    progressBar = (ProgressBar) v.findViewById(R.id.maxphoto_loading);
    Glide.with(getContext()).load(mImageUrl).into(mImageView);
    mAttacher.update();
    return v;
}

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

  }
}

ImageDetailFragment所引用的xml文件代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/bg_shouye">

<uk.co.senab.photoview.PhotoView
    android:id="@+id/maxphoto_image"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />

<ProgressBar
    android:id="@+id/maxphoto_loading"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:visibility="gone" />
</LinearLayout>

最后,莫要忘了在清单文件(AndroidManifest.xml)中声明我们所引用的ImagePagerActivity:

<activity android:name=".ImagePagerActivity"></activity>

该Demo中所用的色值属性如下:

<color name="image_color">#f6f6f6</color>
<color name="bg_shouye">#333333</color>

文字属性如下:

  <string name="viewpager_indicator">指示器</string>

二.值得一提的是,takePhoto多选框修改样式的方法如下

自定义相册

如果TakePhoto自带相册的UI不符合你应用的主题的话,你可以对它进行自定义。方法如下:

自定义Toolbar

在“res/layout”目录中创建一个名为“toolbar.xml”的布局文件,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    app:theme="@style/CustomToolbarTheme"
    android:background="#ffa352">
</android.support.v7.widget.Toolbar>

在“toolbar.xml”文件中你可以指定TakePhoto自带相册的主题以及Toolbar的背景色。

自定义状态栏

在“res/values”目录中创建一个名为“colors.xml”的资源文件,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="multiple_image_select_primaryDark">#212121</color>
</resources>

通过上述方式便可以自定义状态栏的颜色。

自定义提示文字

在“res/values”目录的“string.xml”文件冲添加如下代码:

<resources>    
    <string name="album_view">选择图片</string>
    <string name="image_view">单击选择</string>
    <string name="add">确定</string>
    <string name="selected">已选</string>
    <string name="limit_exceeded">最多能选 %d 张</string>
</resources>

重写上述代码,便可以自定义TakePhoto自带相册的提示文字。

自定义标题栏颜色

在styles.xml里面重写以下style即可:

<style name="MultipleImageSelectTheme"
 parent="Theme.AppCompat.Light.NoActionBar"> 
 <item name="colorPrimary">@color/multiple_image_select_primary</item>//标题栏颜色
 <item name="colorPrimaryDark">@color/multiple_image_select_primaryDark</item> //状态栏颜色          
 <item name="colorAccent">@color/multiple_image_select_accent</item> 
 <item name="actionModeStyle">@style/CustomActionModeStyle</item>
 <item name="windowActionModeOverlay">true</item>
 <item name="actionMenuTextColor">@android:color/white</item>   //标题栏文字颜色
</style>
<style name="CustomActionModeStyle" parent="Base.Widget.AppCompat.ActionMode">
    <item name="background">@color/rdb_bg</item>  //选中标题栏背景颜色
</style>

三.本项目GitHub地址:https://github.com/MiHomes/checkPhotoDemo

四.随手分享,喜欢的朋友可以关注简书号MiHomes,后续会有更多更好的博客推送给您。

另:欢迎指出不足,会进行更正

末尾:移动互联&人力资源交流群,可加微信zy666128入群交流。


image



2016-08-02 22:56:21 jaikydota163 阅读数 11150
  • Android底层技术:Linux驱动框架与开发

    于此,将框架(Framework)和设计模式(Design Pattern)应用于Linux驱动开发,说明了如何以面向对象、设计模式和框架概念来看待Linux驱动程序的架构。其直接的益处就是:让我们能基于一致的设计理念来结合Android HAL与Linux两层的驱动开发,规划出整体和谐Android-based软硬整合产品架构。

    22366 人正在学习 去看看 高煥堂

实现效果



功能说明

大家都知道在Android5.0以前,Android自带的checkbox不可以通过width和height设置宽高,只能通过切多张图和设置android:scaleX="0.5",android:scaleY="0.5"来实现大小的缩放,这就是一个非常苦恼的问题。
恰好公司需要,需要Checkbox有不可点击状态,在这里就编写了这个简单的图片ImageCheckBox,适用于各种复选框的需要,主要实现了图片的选中状态(checked),非选择状态(unchecked),和禁用状态(disable),适用于新手及新学习Android的码友们,老玩家当然也可以看看,这个还是挺简单挺实用的,在后面会简略介绍实现方法及源代码,同时博客的最后还提供源代码和图片等资源github下载地址。

其他系列文章推荐:
--------------------------------------------------------------------------------------------------------------------
Android实用视图动画及工具系列之一:简单的载入视图和载入动画:
Android实用视图动画及工具系列之二:Toast对话框和加载载入对话框:
Android实用视图动画及工具系列之三:表情加载动画和失败加载动画,人物加载动画:
--------------------------------------------------------------------------------------------------------------------

实现步骤

步骤一:添加需要的状态图片

在编写下面的代码前,我们需要三种图片,选中状态的图片checked,非选中unChecked,和禁用disable,如下面的几张图(其他图片资源在源代码内,需要的自行下载):
Checked:

unchecked:

disable:


将所有图片导入到Android项目目录的drawable文件夹下:



步骤二:自定义CheckBox类,ImageCheckBox

新建类ImageCheckBox,代码如下,此类主要继承自ImageView,实现了图片的三种状态
CHECK_STATE_DISABLED 状态,禁用
CHECK_STATE_UNCHECKED 状态,非选中
CHECK_STATE_CHECKED 状态,选中
package com.jaiky.test.statucheckbox;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;

/**
 * Author by Jaiky, Email jaikydota@163.com, Date on 5/21/2015.
 * PS: Not easy to write code, please indicate.
 */
public class ImageCheckBox extends ImageView {
    //状态,不能使用
    public static final int CHECK_STATE_DISABLED = 0;
    //为不选中状态
    public static final int CHECK_STATE_UNCHECKED = 1;
    //选中状态
    public static final int CHECK_STATE_CHECKED = 2;

    private int check_bkg_id;
    private int uncheck_bkg_id;
    private int disable_check_bkg_id;

    //当前状态
    private int checkState;

    public ImageCheckBox(Context context) {
        this(context, null);
    }

    public ImageCheckBox(Context context, AttributeSet attrs) {
        this(context, attrs, 0);

    }

    public ImageCheckBox(Context context, AttributeSet attrs,
                         int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }

    private void init(AttributeSet attrs) {
        TypedArray t = getContext().obtainStyledAttributes(attrs,
                R.styleable.ImageCheckBox);
        checkState = t.getInteger(R.styleable.ImageCheckBox_checked_state,
                CHECK_STATE_UNCHECKED);
        check_bkg_id = t.getResourceId(
                R.styleable.ImageCheckBox_checked, 0);
        uncheck_bkg_id = t.getResourceId(
                R.styleable.ImageCheckBox_unchecked, 0);
        disable_check_bkg_id = t.getResourceId(
                R.styleable.ImageCheckBox_checked_disabled, 0);

        setBkgByCheckState();

        //如果可以点击
        if (isClickable()) {
            setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    changeState();
                }
            });
        }

        t.recycle();
    }

    public boolean isCheck(){
        if (checkState == CHECK_STATE_DISABLED) {
            return false;
        }

        if (checkState == CHECK_STATE_CHECKED) {
            return true;
        }
        else {
            return false;
        }
    }

    /**
     * 设置选中状态
     * @param check
     */
    public void setCheck(boolean check){
        if (checkState == CHECK_STATE_DISABLED) {
            return;
        }
        if (check) {
            checkState = CHECK_STATE_CHECKED;
        }
        else {
            checkState = CHECK_STATE_UNCHECKED;
        }
        setBkgByCheckState();
        notifyListner();
    }

    /**
     * 改变Check状态
     */
    public void changeState() {
        if (checkState == CHECK_STATE_DISABLED) {
            return;
        }

        if (checkState == CHECK_STATE_UNCHECKED) {
            checkState = CHECK_STATE_CHECKED;
        } else if (checkState == CHECK_STATE_CHECKED) {
            checkState = CHECK_STATE_UNCHECKED;
        }

        setBkgByCheckState();
        notifyListner();
    }

    public void setCheckDisabled() {
        this.checkState = CHECK_STATE_DISABLED;
        setBkgByCheckState();
    }

    private void setBkgByCheckState() {
        if (checkState == CHECK_STATE_UNCHECKED) {
            setImageResource(uncheck_bkg_id);
        }
        else if (checkState == CHECK_STATE_DISABLED) {
            setImageResource(disable_check_bkg_id);
        }
        else {
            setImageResource(check_bkg_id);
        }

    }

    public interface OnCheckStateChangedListener {
        public void onCheckStateChanged(boolean isChecked);
    }

    private OnCheckStateChangedListener listener;

    public void setOnCheckStateChangedListener(OnCheckStateChangedListener listener) {
        this.listener = listener;
    }

    private void notifyListner() {
        if (this.listener != null) {
            if (checkState == CHECK_STATE_UNCHECKED) {
                this.listener.onCheckStateChanged(false);
            } else if (checkState == CHECK_STATE_CHECKED) {
                this.listener.onCheckStateChanged(true);
            }
        }
    }
}


步骤三:Demo测试修改布局和主类

修改activity_main.xml内容如下(注意自定义控件包名):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#bb000000"
    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.jaiky.test.statucheckbox.MainActivity">

    <com.jaiky.test.statucheckbox.ImageCheckBox
        android:id="@+id/cbSelect1"
        android:layout_width="25dp"
        android:layout_height="25dp"
        android:layout_gravity="center_vertical"
        android:clickable="true"
        custom:checked="@drawable/radiobutton_checked"
        custom:checked_state="1"
        custom:unchecked="@drawable/radiobutton_unchecked" />

    <com.jaiky.test.statucheckbox.ImageCheckBox
        android:id="@+id/cbSelect2"
        android:layout_toRightOf="@id/cbSelect1"
        android:layout_marginLeft="30dp"
        android:layout_width="35dp"
        android:layout_height="35dp"
        android:layout_gravity="center_vertical"
        android:clickable="true"
        custom:checked="@drawable/radiobutton_checked"
        custom:checked_state="1"
        custom:unchecked="@drawable/radiobutton_unchecked" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_below="@+id/cbSelect2"
        android:layout_marginTop="30dp">
        <com.jaiky.test.statucheckbox.ImageCheckBox
            android:id="@+id/cbSelect3"
            android:layout_width="35dp"
            android:layout_height="35dp"
            android:layout_gravity="center_vertical"
            android:clickable="true"
            custom:checked_disabled="@drawable/video_disabled"
            custom:checked="@drawable/video_play"
            custom:checked_state="1"
            custom:unchecked="@drawable/video_pause" />

        <Button
            android:id="@+id/btn1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="30dp"
            android:text="视频按钮不可用"
            />
    </LinearLayout>

</RelativeLayout>

修改MainActiivty类内容如下(注意包名):
package com.jaiky.test.statucheckbox;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    ImageCheckBox cbSelect1, cbSelect2, cbSelect3;
    Button btn1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        cbSelect1 = (ImageCheckBox) findViewById(R.id.cbSelect1);
        cbSelect2 = (ImageCheckBox) findViewById(R.id.cbSelect2);
        cbSelect3 = (ImageCheckBox) findViewById(R.id.cbSelect3);
        btn1 = (Button) findViewById(R.id.btn1);
        btn1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                cbSelect3.setCheckDisabled();
            }
        });
    }
}


--------------------------------------------------------------------------------------------------------------------
获取源代码及资源文件:
--------------------------------------------------------------------------------------------------------------------

声明

欢迎转载,但请保留文章原始出处
作者:Jaiky_杰哥 
出处:http://blog.csdn.net/jaikydota163/article/details/52098865


2010-09-22 15:20:48 systemdai 阅读数 349
  • Android底层技术:Linux驱动框架与开发

    于此,将框架(Framework)和设计模式(Design Pattern)应用于Linux驱动开发,说明了如何以面向对象、设计模式和框架概念来看待Linux驱动程序的架构。其直接的益处就是:让我们能基于一致的设计理念来结合Android HAL与Linux两层的驱动开发,规划出整体和谐Android-based软硬整合产品架构。

    22366 人正在学习 去看看 高煥堂
1.调用setOnCheckedChangeListener()方法,并把 CompoundButton.OnCheckedChangeListener实例作为参数传入
2.在CompoundButton.OnCheckedChangeListener的onCheckedChanged()方法里,取得被选中复选框的实例

/** Called when the activity is first created. */
private CheckBox c1,c2 ;
private Button button;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
c1 = (CheckBox) findViewById(R.id.CheckBox01);
c2 = (CheckBox) findViewById(R.id.CheckBox02);
button = (Button) findViewById(R.id.Button01);

//注册事件监听
c1.setOnCheckedChangeListener(new CheckBoxListener());
c2.setOnCheckedChangeListener(new CheckBoxListener());
button.setOnClickListener(new ButtonClickListener());

}

//定义事件
class CheckBoxListener implements OnCheckedChangeListener{
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
if(isChecked){
//Toast
Toast.makeText(CheckBoxActivity.this, buttonView.getText()+"被选择",Toast.LENGTH_SHORT ).show();
}else{
Toast.makeText(CheckBoxActivity.this, buttonView.getText()+"取消选择",Toast.LENGTH_SHORT ).show();
}
}
}

class ButtonClickListener implements OnClickListener{
String buffer = "";
public void onClick(View v) {
if(c1.isChecked())
buffer = buffer+c1.getText();
if(c2.isChecked())
buffer = buffer +c2.getText();
Toast.makeText(CheckBoxActivity.this, buffer+"被选择", Toast.LENGTH_SHORT).show();
}
}


[b]main.xml[/b]

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>

<CheckBox android:text="金钱" android:id="@+id/CheckBox01" android:layout_width="wrap_content" android:layout_height="wrap_content"></CheckBox>
<CheckBox android:text="地位" android:id="@+id/CheckBox02" android:layout_width="wrap_content" android:layout_height="wrap_content"></CheckBox>
<Button android:id="@+id/Button01" android:text="确定" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
</LinearLayout>


[b]运行效果[/b]
[img]http://dl.iteye.com/upload/attachment/315087/39396fdd-91d6-3146-9da0-d2c43df181e4.png[/img]
2013-06-25 17:24:58 xueshuangshuang123 阅读数 16076
  • Android底层技术:Linux驱动框架与开发

    于此,将框架(Framework)和设计模式(Design Pattern)应用于Linux驱动开发,说明了如何以面向对象、设计模式和框架概念来看待Linux驱动程序的架构。其直接的益处就是:让我们能基于一致的设计理念来结合Android HAL与Linux两层的驱动开发,规划出整体和谐Android-based软硬整合产品架构。

    22366 人正在学习 去看看 高煥堂

简单讲解一下原理:每个多选框都是独立的,可以通过迭代所有多选框,然后根据其状态是否被选中再获取其值。
 CheckBox.setChecked(true);//设置成选中状态。
 CheckBox.getText();//获取多选框的值
 调用setOnCheckedChangeListener()方法,处理多选框被选择事件,把CompoundButton.OnCheckedChangeListener实例作为参数传入

1、布局文件:

<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=".MainActivity" >

    <CheckBox
        android:id="@+id/checkBox1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="40dp"
        android:layout_marginTop="28dp"
        android:text="@string/check_java" />

    <CheckBox
        android:id="@+id/checkBox2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/checkBox1"
        android:layout_below="@+id/checkBox1"
        android:layout_marginTop="39dp"
        android:text="@string/check_.net" />

    <CheckBox
        android:id="@+id/checkBox3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/checkBox2"
        android:layout_below="@+id/checkBox2"
        android:layout_marginTop="47dp"
        android:text="@string/check_php" />

    <CheckBox
        android:id="@+id/checkBox4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/checkBox3"
        android:layout_below="@+id/checkBox3"
        android:layout_marginTop="40dp"
        android:text="@string/check_3G" />
    
     <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignRight="@+id/checkBox2"
        android:layout_below="@+id/checkBox4"
        android:layout_marginTop="58dp"
        android:onClick="getValues"
        android:text="@string/text_get" />

</RelativeLayout>


 

2、布局文件中引用的string.xml的值

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">lession16-checkbox</string>
    <string name="action_settings">Settings</string>
    <string name="hello_world">Hello world!</string>
    
    <string name="check_java">java专业</string>
	<string name="check_.net">.net专业</string>
	<string name="check_php">php专业</string>
	<string name="check_3G">3G专业</string>
	
	<string name="text_get">获取值</string>
</resources>


 

3、MainActivity中的代码:

package com.example.lession16_checkbox;

import java.util.ArrayList;
import java.util.List;

import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.view.Menu;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.Toast;

public class MainActivity extends Activity {
	
	//声明组件
	private CheckBox cb1,cb2,cb3,cb4;
	
	//声明一个集合
	private List<CheckBox> checkBoxs=new ArrayList<CheckBox>();

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		//获取组件
		cb1 = (CheckBox) findViewById(R.id.checkBox1);
		cb2 = (CheckBox) findViewById(R.id.checkBox2);
		cb3 = (CheckBox) findViewById(R.id.checkBox3);
		cb4 = (CheckBox) findViewById(R.id.checkBox4);
		
		//默认选项
		cb2.setChecked(true);
		cb4.setChecked(true);
		
		//注册事件
		cb1.setOnCheckedChangeListener(listener);
		cb2.setOnCheckedChangeListener(listener);
		cb3.setOnCheckedChangeListener(listener);
		cb4.setOnCheckedChangeListener(listener);
		//把四个组件添加到集合中去
		checkBoxs.add(cb1);
		checkBoxs.add(cb2);
		checkBoxs.add(cb3);
		checkBoxs.add(cb4);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}
	
	public void getValues(View v) {

		String content = "";

		for (CheckBox cbx : checkBoxs) {
			if (cbx.isChecked()) {
				content += cbx.getText() + "\n";
			}
		}

		if ("".equals(content)) {
			content = "您还没有选择尼";
		}
		new AlertDialog.Builder(this).setMessage(content).setTitle("选中的内容如下")
				.setPositiveButton("关闭", null).show();

	}

	CompoundButton.OnCheckedChangeListener listener = new CompoundButton.OnCheckedChangeListener() {

		@Override
		public void onCheckedChanged(CompoundButton buttonView,
				boolean isChecked) {
			// TODO Auto-generated method stub
			CheckBox box = (CheckBox) buttonView;

			Toast.makeText(getApplicationContext(),
					"获取的值:" + isChecked + "xxxxx" + box.getText(),
					Toast.LENGTH_LONG).show();

		}
	};

}


 

效果图:


2019-04-08 22:27:30 hju22 阅读数 343
  • Android底层技术:Linux驱动框架与开发

    于此,将框架(Framework)和设计模式(Design Pattern)应用于Linux驱动开发,说明了如何以面向对象、设计模式和框架概念来看待Linux驱动程序的架构。其直接的益处就是:让我们能基于一致的设计理念来结合Android HAL与Linux两层的驱动开发,规划出整体和谐Android-based软硬整合产品架构。

    22366 人正在学习 去看看 高煥堂

1、项目需求

  1. 本项目是一个安卓项目,启动页面有多个复选框和一个TextView
  2. 复选框分别显示为北京、上海、广州;TextView的文字为:已经勾选的城市;
  3. 点击每个复选框时,toast提示复选框的内容和选中状态(true和false)
  4. 点击文字时,toast提示选中的城市有哪些

2、项目分析

  1. checkbox的勾选监听
    (1)循环取出checkbox,对每个checkbox设置勾选监听器
  2. TextView的点击监听
    (1)TextView需要设置点击监听器,监听器的作用是发一个toast
    (2)遍历复选框列表,判断复选框的选中状态,如果选中,就将文本添加到结果字符串中
    (3)显示toast
    (4)清除toast内容,还原到初始状态

3、布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    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"
    android:orientation="vertical"
    tools:context="com.example.gui.checkbox1.MainActivity">
    <LinearLayout
        android:id="@+id/checklist"
        android:orientation="horizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <CheckBox
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="北京"/>
        <CheckBox
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="上海"/>
        <CheckBox
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="广州"/>

    </LinearLayout>
    <TextView
        android:id="@+id/textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="已经勾选的城市"/>

</LinearLayout>

4、Activity

package com.example.gui.checkbox1;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    //声明checkbox所在的布局
    LinearLayout checklist;
    //checkbox个数
    int count;
    //保存选中的checkbox
    StringBuffer stringBuffer=new StringBuffer();

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

        /*1、监听每个checkbox*/
        checklist=(LinearLayout)findViewById(R.id.checklist);
        count=checklist.getChildCount();
        for(int i=0;i<count;i++){
            CheckBox box=(CheckBox)checklist.getChildAt(i);
            box.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener(){
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    Toast.makeText(getApplicationContext(),buttonView.getText().toString()+isChecked,Toast.LENGTH_SHORT).show();
                }
            });
        }
        /*2、监听textview*/

        TextView textView=(TextView)findViewById(R.id.textview);
        textView.setOnClickListener(new TextView.OnClickListener(){
            @Override
            public void onClick(View v) {
                stringBuffer.append("已经勾选的城市有:");
                for(int i=0;i<count;i++){
                    CheckBox box=(CheckBox)checklist.getChildAt(i);
                    if(box.isChecked()){
                        stringBuffer.append(box.getText().toString());
                    }
                }
                Toast.makeText(getApplicationContext(),stringBuffer,Toast.LENGTH_SHORT).show();
                //清除内容,还原到初始状态
                stringBuffer=new StringBuffer();
            }
        });
    }
}

5、运行结果

apk下载链接:https://pan.baidu.com/s/1Ze5qDFiS97k4OOqF7v_nsQ
提取码:l93q

运行结果:
1、启动页:
在这里插入图片描述
2、选中北京
在这里插入图片描述
3、取消选中北京
在这里插入图片描述
4、只选中上海、广州,点击提交按钮,toast提示如下:
在这里插入图片描述

没有更多推荐了,返回首页